Skip to content

Commit bf81455

Browse files
update BeforeAfterLayout
update overloads, add docs and fix before/after content order bug
1 parent 7b02e5e commit bf81455

File tree

1 file changed

+147
-32
lines changed

1 file changed

+147
-32
lines changed

image/src/main/java/com/smarttoolfactory/image/beforeafter/BeforeAfterLayout.kt

Lines changed: 147 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@ import androidx.compose.foundation.layout.Box
77
import androidx.compose.foundation.layout.BoxScope
88
import androidx.compose.foundation.layout.fillMaxSize
99
import androidx.compose.foundation.layout.size
10+
import androidx.compose.foundation.shape.CircleShape
1011
import androidx.compose.foundation.shape.GenericShape
12+
import androidx.compose.material.Icon
1113
import androidx.compose.runtime.*
1214
import androidx.compose.ui.Modifier
1315
import androidx.compose.ui.draw.clipToBounds
1416
import androidx.compose.ui.geometry.Offset
1517
import androidx.compose.ui.geometry.Size
1618
import androidx.compose.ui.graphics.Color
19+
import androidx.compose.ui.graphics.Shape
1720
import androidx.compose.ui.graphics.graphicsLayer
1821
import androidx.compose.ui.input.pointer.pointerInput
1922
import androidx.compose.ui.platform.LocalDensity
@@ -30,21 +33,48 @@ import com.smarttoolfactory.image.util.update
3033
import com.smarttoolfactory.image.zoom.rememberZoomState
3134
import kotlinx.coroutines.launch
3235

36+
/**
37+
* A composable that lays out and draws a given [beforeContent] and [afterContent]
38+
* based on [contentOrder]. This overload uses [DefaultOverlay] to draw vertical slider and thumb.
39+
*
40+
* @param enableProgressWithTouch flag to enable drag and change progress with touch
41+
* @param enableZoom when enabled images are zoomable and pannable
42+
* @param contentOrder order of composables to be drawn
43+
* @param verticalThumbMove when true thumb can move vertically based on user touch
44+
* @param lineColor color if divider line
45+
* @param thumbBackgroundColor background color of thumb [Icon]
46+
* @param thumbTintColor tint color of thumb [Icon]
47+
* @param thumbShape shape of thumb [Icon]
48+
* @param thumbElevation elevation of thumb [Icon]
49+
* @param thumbResource drawable resource that should be used with thumb
50+
* @param thumbSize size of the thumb in dp
51+
* @param thumbPositionPercent vertical position of thumb if [verticalThumbMove] is false.
52+
* It's between [0f-100f] to set thumb's vertical position in layout
53+
* @param beforeContent content to be drawn as before Composable
54+
* @param afterContent content to be drawn as after Composable
55+
* @param beforeLabel label for [beforeContent]. It's [BeforeLabel] by default
56+
* @param afterLabel label for [afterContent]. It's [AfterLabel] by default
57+
*
58+
*/
3359
@Composable
3460
fun BeforeAfterLayout(
3561
modifier: Modifier = Modifier,
3662
enableProgressWithTouch: Boolean = true,
3763
enableZoom: Boolean = true,
3864
contentOrder: ContentOrder = ContentOrder.BeforeAfter,
39-
verticalThumbMove: Boolean = false,
4065
lineColor: Color = Color.White,
66+
verticalThumbMove: Boolean = false,
67+
thumbBackgroundColor: Color = Color.White,
68+
thumbTintColor: Color = Color.Gray,
69+
thumbShape: Shape = CircleShape,
70+
thumbElevation: Dp = 2.dp,
4171
@DrawableRes thumbResource: Int = R.drawable.baseline_swap_horiz_24,
4272
thumbSize: Dp = 36.dp,
4373
@FloatRange(from = 0.0, to = 100.0) thumbPositionPercent: Float = 85f,
4474
beforeContent: @Composable () -> Unit,
4575
afterContent: @Composable () -> Unit,
46-
beforeLabel: @Composable BoxScope.() -> Unit = { BeforeLabel(contentOrder) },
47-
afterLabel: @Composable BoxScope.() -> Unit = { AfterLabel(contentOrder) },
76+
beforeLabel: @Composable BoxScope.() -> Unit = { BeforeLabel(contentOrder = contentOrder) },
77+
afterLabel: @Composable BoxScope.() -> Unit = { AfterLabel(contentOrder = contentOrder) },
4878
) {
4979
var progress by remember { mutableStateOf(50f) }
5080

@@ -66,8 +96,12 @@ fun BeforeAfterLayout(
6696
width = dpSize.width,
6797
height = dpSize.height,
6898
position = offset,
69-
verticalThumbMove = verticalThumbMove,
7099
lineColor = lineColor,
100+
verticalThumbMove = verticalThumbMove,
101+
thumbBackgroundColor = thumbBackgroundColor,
102+
thumbTintColor = thumbTintColor,
103+
thumbShape = thumbShape,
104+
thumbElevation = thumbElevation,
71105
thumbResource = thumbResource,
72106
thumbSize = thumbSize,
73107
thumbPositionPercent = thumbPositionPercent
@@ -76,23 +110,53 @@ fun BeforeAfterLayout(
76110
)
77111
}
78112

113+
/**
114+
* A composable that lays out and draws a given [beforeContent] and [afterContent]
115+
* based on [contentOrder]. This overload uses [DefaultOverlay] to draw vertical slider and thumb
116+
* and has [progress] and [onProgressChange] which makes it eligible to animate by changing
117+
* [progress] value.
118+
*
119+
* @param enableProgressWithTouch flag to enable drag and change progress with touch
120+
* @param enableZoom when enabled images are zoomable and pannable
121+
* @param contentOrder order of composables to be drawn
122+
* @param progress current position or progress of before/after
123+
* @param onProgressChange current position or progress of before/after
124+
* @param verticalThumbMove when true thumb can move vertically based on user touch
125+
* @param lineColor color if divider line
126+
* @param thumbBackgroundColor background color of thumb [Icon]
127+
* @param thumbTintColor tint color of thumb [Icon]
128+
* @param thumbShape shape of thumb [Icon]
129+
* @param thumbElevation elevation of thumb [Icon]
130+
* @param thumbResource drawable resource that should be used with thumb
131+
* @param thumbSize size of the thumb in dp
132+
* @param thumbPositionPercent vertical position of thumb if [verticalThumbMove] is false.
133+
* It's between [0f-100f] to set thumb's vertical position in layout
134+
* @param beforeContent content to be drawn as before Composable
135+
* @param afterContent content to be drawn as after Composable
136+
* @param beforeLabel label for [beforeContent]. It's [BeforeLabel] by default
137+
* @param afterLabel label for [afterContent]. It's [AfterLabel] by default
138+
*/
79139
@Composable
80140
fun BeforeAfterLayout(
81141
modifier: Modifier = Modifier,
82142
enableProgressWithTouch: Boolean = true,
83143
enableZoom: Boolean = true,
84144
contentOrder: ContentOrder = ContentOrder.BeforeAfter,
85-
verticalThumbMove: Boolean = false,
145+
@FloatRange(from = 0.0, to = 100.0) progress: Float = 50f,
146+
onProgressChange: ((Float) -> Unit)? = null,
86147
lineColor: Color = Color.White,
148+
verticalThumbMove: Boolean = false,
149+
thumbBackgroundColor: Color = Color.White,
150+
thumbTintColor: Color = Color.Gray,
151+
thumbShape: Shape = CircleShape,
152+
thumbElevation: Dp = 2.dp,
87153
@DrawableRes thumbResource: Int = R.drawable.baseline_swap_horiz_24,
88154
thumbSize: Dp = 36.dp,
89155
@FloatRange(from = 0.0, to = 100.0) thumbPositionPercent: Float = 85f,
90-
@FloatRange(from = 0.0, to = 100.0) progress: Float = 50f,
91-
onProgressChange: ((Float) -> Unit)? = null,
92156
beforeContent: @Composable () -> Unit,
93157
afterContent: @Composable () -> Unit,
94-
beforeLabel: @Composable BoxScope.() -> Unit = { BeforeLabel(contentOrder) },
95-
afterLabel: @Composable BoxScope.() -> Unit = { AfterLabel(contentOrder) },
158+
beforeLabel: @Composable BoxScope.() -> Unit = { BeforeLabel(contentOrder = contentOrder) },
159+
afterLabel: @Composable BoxScope.() -> Unit = { AfterLabel(contentOrder = contentOrder) },
96160
) {
97161

98162
Layout(
@@ -111,8 +175,12 @@ fun BeforeAfterLayout(
111175
width = dpSize.width,
112176
height = dpSize.height,
113177
position = offset,
114-
verticalThumbMove = verticalThumbMove,
115178
lineColor = lineColor,
179+
verticalThumbMove = verticalThumbMove,
180+
thumbBackgroundColor = thumbBackgroundColor,
181+
thumbTintColor = thumbTintColor,
182+
thumbShape = thumbShape,
183+
thumbElevation = thumbElevation,
116184
thumbResource = thumbResource,
117185
thumbSize = thumbSize,
118186
thumbPositionPercent = thumbPositionPercent
@@ -121,6 +189,22 @@ fun BeforeAfterLayout(
121189
)
122190
}
123191

192+
/**
193+
* A composable that lays out and draws a given [beforeContent] and [afterContent]
194+
* based on [contentOrder].
195+
*
196+
* @param enableProgressWithTouch flag to enable drag and change progress with touch
197+
* @param enableZoom when enabled images are zoomable and pannable
198+
* @param contentOrder order of composables to be drawn
199+
200+
* It's between [0f-100f] to set thumb's vertical position in layout
201+
* @param beforeContent content to be drawn as before Composable
202+
* @param afterContent content to be drawn as after Composable
203+
* @param beforeLabel label for [beforeContent]. It's [BeforeLabel] by default
204+
* @param afterLabel label for [afterContent]. It's [AfterLabel] by default
205+
* @param overlay Composable for drawing overlay over this Composable. It returns dimensions
206+
* of ancestor and touch position
207+
*/
124208
@Composable
125209
fun BeforeAfterLayout(
126210
modifier: Modifier = Modifier,
@@ -129,8 +213,8 @@ fun BeforeAfterLayout(
129213
contentOrder: ContentOrder = ContentOrder.BeforeAfter,
130214
beforeContent: @Composable () -> Unit,
131215
afterContent: @Composable () -> Unit,
132-
beforeLabel: @Composable BoxScope.() -> Unit = { BeforeLabel(contentOrder) },
133-
afterLabel: @Composable BoxScope.() -> Unit = { AfterLabel(contentOrder) },
216+
beforeLabel: @Composable BoxScope.() -> Unit = { BeforeLabel(contentOrder = contentOrder) },
217+
afterLabel: @Composable BoxScope.() -> Unit = { AfterLabel(contentOrder = contentOrder) },
134218
overlay: @Composable ((DpSize, Offset) -> Unit)?
135219
) {
136220
var progress by remember { mutableStateOf(50f) }
@@ -152,6 +236,23 @@ fun BeforeAfterLayout(
152236
)
153237
}
154238

239+
/**
240+
* A composable that lays out and draws a given [beforeContent] and [afterContent]
241+
* based on [contentOrder].
242+
*
243+
* @param enableProgressWithTouch flag to enable drag and change progress with touch
244+
* @param enableZoom when enabled images are zoomable and pannable
245+
* @param contentOrder order of composables to be drawn
246+
* @param progress current position or progress of before/after
247+
* @param onProgressChange current position or progress of before/after
248+
* It's between [0f-100f] to set thumb's vertical position in layout
249+
* @param beforeContent content to be drawn as before Composable
250+
* @param afterContent content to be drawn as after Composable
251+
* @param beforeLabel label for [beforeContent]. It's [BeforeLabel] by default
252+
* @param afterLabel label for [afterContent]. It's [AfterLabel] by default
253+
* @param overlay Composable for drawing overlay over this Composable. It returns dimensions
254+
* of ancestor and touch position
255+
*/
155256
@Composable
156257
fun BeforeAfterLayout(
157258
modifier: Modifier = Modifier,
@@ -162,8 +263,8 @@ fun BeforeAfterLayout(
162263
contentOrder: ContentOrder = ContentOrder.BeforeAfter,
163264
beforeContent: @Composable () -> Unit,
164265
afterContent: @Composable () -> Unit,
165-
beforeLabel: @Composable BoxScope.() -> Unit = { BeforeLabel(contentOrder) },
166-
afterLabel: @Composable BoxScope.() -> Unit = { AfterLabel(contentOrder) },
266+
beforeLabel: @Composable (BoxScope.() -> Unit)? = { BeforeLabel(contentOrder = contentOrder) },
267+
afterLabel: @Composable (BoxScope.() -> Unit)? = { AfterLabel(contentOrder = contentOrder) },
167268
overlay: @Composable ((DpSize, Offset) -> Unit)?
168269
) {
169270

@@ -192,8 +293,8 @@ private fun Layout(
192293
contentOrder: ContentOrder = ContentOrder.BeforeAfter,
193294
beforeContent: @Composable () -> Unit,
194295
afterContent: @Composable () -> Unit,
195-
beforeLabel: @Composable BoxScope.() -> Unit = { BeforeLabel(contentOrder) },
196-
afterLabel: @Composable BoxScope.() -> Unit = { AfterLabel(contentOrder) },
296+
beforeLabel: @Composable (BoxScope.() -> Unit)?,
297+
afterLabel: @Composable (BoxScope.() -> Unit)?,
197298
overlay: @Composable ((DpSize, Offset) -> Unit)?
198299
) {
199300
DimensionSubcomposeLayout(
@@ -346,7 +447,7 @@ private fun Layout(
346447
this.shape = shapeAfter
347448
}
348449

349-
BeforeAfterLayoutImpl(
450+
LayoutImpl(
350451
modifier = parentModifier,
351452
beforeModifier = beforeModifier,
352453
afterModifier = afterModifier,
@@ -356,6 +457,7 @@ private fun Layout(
356457
beforeLabel = beforeLabel,
357458
afterLabel = afterLabel,
358459
overlay = overlay,
460+
contentOrder = contentOrder,
359461
boxWidthInDp = boxWidthInDp,
360462
boxHeightInDp = boxHeightInDp,
361463
rawOffset = rawOffset
@@ -365,40 +467,53 @@ private fun Layout(
365467
}
366468

367469
@Composable
368-
private fun BeforeAfterLayoutImpl(
470+
private fun LayoutImpl(
369471
modifier: Modifier,
370472
beforeModifier: Modifier,
371473
afterModifier: Modifier,
372474
graphicsModifier: Modifier,
373475
beforeContent: @Composable () -> Unit,
374476
afterContent: @Composable () -> Unit,
375-
beforeLabel: @Composable BoxScope.() -> Unit,
376-
afterLabel: @Composable BoxScope.() -> Unit,
477+
beforeLabel: @Composable (BoxScope.() -> Unit)? = null,
478+
afterLabel: @Composable (BoxScope.() -> Unit)? = null,
377479
overlay: @Composable ((DpSize, Offset) -> Unit)? = null,
480+
contentOrder: ContentOrder,
378481
boxWidthInDp: Dp,
379482
boxHeightInDp: Dp,
380483
rawOffset: Offset,
381484
) {
382485
Box(modifier = modifier) {
383486

384487
// BEFORE
385-
Box(modifier = beforeModifier) {
386-
Box(
387-
modifier = Modifier.then(graphicsModifier)
388-
) {
389-
beforeContent()
488+
val before = @Composable {
489+
Box(if (contentOrder == ContentOrder.BeforeAfter) beforeModifier else afterModifier) {
490+
Box(
491+
modifier = Modifier.then(graphicsModifier)
492+
) {
493+
beforeContent()
494+
}
495+
beforeLabel?.invoke(this)
390496
}
391-
beforeLabel()
392497
}
393498

394499
// AFTER
395-
Box(afterModifier) {
396-
Box(
397-
modifier = Modifier.then(graphicsModifier)
398-
) {
399-
afterContent()
500+
val after = @Composable {
501+
Box(if (contentOrder == ContentOrder.BeforeAfter) afterModifier else beforeModifier) {
502+
Box(
503+
modifier = Modifier.then(graphicsModifier)
504+
) {
505+
afterContent()
506+
}
507+
afterLabel?.invoke(this)
400508
}
401-
afterLabel()
509+
}
510+
511+
if (contentOrder == ContentOrder.BeforeAfter) {
512+
before()
513+
after()
514+
} else {
515+
after()
516+
before()
402517
}
403518
}
404519

0 commit comments

Comments
 (0)