Skip to content

Commit 05f01a9

Browse files
add Animate state, modifier and demo
1 parent 308342d commit 05f01a9

File tree

5 files changed

+468
-0
lines changed

5 files changed

+468
-0
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.smarttoolfactory.composeimage.demo.zoom
2+
3+
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.border
5+
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.fillMaxSize
7+
import androidx.compose.foundation.layout.size
8+
import androidx.compose.material.Text
9+
import androidx.compose.runtime.Composable
10+
import androidx.compose.ui.Modifier
11+
import androidx.compose.ui.graphics.Color
12+
import androidx.compose.ui.unit.dp
13+
import com.smarttoolfactory.image.zoom.AnimatedZoomLayout2
14+
15+
@Composable
16+
fun AnimatedZoomDemo() {
17+
18+
Column(modifier = Modifier.fillMaxSize()) {
19+
AnimatedZoomLayout2(
20+
modifier = Modifier
21+
.fillMaxSize()
22+
.border(2.dp, Color.Green)
23+
) {
24+
Text(
25+
modifier = Modifier
26+
.size(200.dp)
27+
.background(Color.Yellow),
28+
text = "Hello World........\n" +
29+
"asdamsdalşsdkasşl\n" +
30+
"asdasdaskdk\n" +
31+
" asads dasdasdasd asdasdasd",
32+
)
33+
}
34+
35+
// AnimatedZoomLayout2(
36+
// modifier = Modifier
37+
// .fillMaxWidth()
38+
//
39+
// .border(2.dp, Color.Green)
40+
// ) {
41+
// Text(
42+
// modifier = Modifier
43+
// .size(100.dp)
44+
// .background(Color.Yellow),
45+
// text = "Hello World",
46+
// )
47+
// }
48+
}
49+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package com.smarttoolfactory.image.zoom
2+
3+
import androidx.compose.foundation.border
4+
import androidx.compose.foundation.layout.Box
5+
import androidx.compose.runtime.Composable
6+
import androidx.compose.ui.Alignment
7+
import androidx.compose.ui.Modifier
8+
import androidx.compose.ui.graphics.Color
9+
import androidx.compose.ui.platform.LocalDensity
10+
import androidx.compose.ui.unit.DpSize
11+
import androidx.compose.ui.unit.dp
12+
import com.smarttoolfactory.image.DimensionSubcomposeLayout
13+
14+
@Composable
15+
fun AnimatedZoomLayout(
16+
modifier: Modifier = Modifier,
17+
content: @Composable () -> Unit
18+
) {
19+
20+
val density = LocalDensity.current
21+
22+
DimensionSubcomposeLayout(
23+
placeMainContent = false,
24+
mainContent = { content() }
25+
) {
26+
Box(
27+
modifier
28+
.border(5.dp, Color.Red)
29+
.animatedZoom(
30+
animatedZoomState = rememberAnimatedZoomState(
31+
minZoom = .5f,
32+
maxZoom = 30f
33+
),
34+
),
35+
contentAlignment = Alignment.Center
36+
) {
37+
content()
38+
}
39+
}
40+
}
41+
42+
@Composable
43+
fun AnimatedZoomLayout2(
44+
modifier: Modifier = Modifier,
45+
content: @Composable () -> Unit
46+
) {
47+
48+
Box(
49+
modifier
50+
.border(4.dp, Color.Red)
51+
.animatedZoom(
52+
animatedZoomState = rememberAnimatedZoomState(
53+
minZoom = .5f,
54+
maxZoom = 30f,
55+
contentSize = DpSize(200.dp, 200.dp)
56+
)
57+
),
58+
contentAlignment = Alignment.Center
59+
) {
60+
content()
61+
}
62+
63+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package com.smarttoolfactory.image.zoom
2+
3+
import androidx.compose.foundation.gestures.detectTapGestures
4+
import androidx.compose.runtime.rememberCoroutineScope
5+
import androidx.compose.ui.Modifier
6+
import androidx.compose.ui.composed
7+
import androidx.compose.ui.draw.clipToBounds
8+
import androidx.compose.ui.graphics.graphicsLayer
9+
import androidx.compose.ui.input.pointer.pointerInput
10+
import com.smarttoolfactory.gesture.detectTransformGestures
11+
import com.smarttoolfactory.image.util.update
12+
import kotlinx.coroutines.launch
13+
14+
/**
15+
* Modifier that zooms in or out of Composable set to. This zoom modifier has option
16+
* to move back to bounds with an animation or option to have fling gesture when user removes
17+
* from screen while velocity is higher than threshold to have smooth touch effect.
18+
*
19+
* @param key is used for [Modifier.pointerInput] to restart closure when any keys assigned
20+
* change
21+
* @param consume flag to prevent other gestures such as scroll, drag or transform to get
22+
* @param clip when set to true clips to parent bounds. Anything outside parent bounds is not
23+
* drawn
24+
* empty space on sides or edges of parent.
25+
* [EnhancedZoomData] of this modifier
26+
*/
27+
fun Modifier.animatedZoom(
28+
key: Any? = Unit,
29+
consume: Boolean = true,
30+
clip: Boolean = true,
31+
animatedZoomState: AnimatedZoomState,
32+
) = composed(
33+
34+
factory = {
35+
36+
val coroutineScope = rememberCoroutineScope()
37+
38+
val boundPan = animatedZoomState.limitPan && !animatedZoomState.rotatable
39+
val clipToBounds = (clip || boundPan)
40+
41+
val transformModifier = Modifier.pointerInput(key) {
42+
// Pass size of this Composable this Modifier is attached for constraining operations
43+
// inside this bounds
44+
animatedZoomState.size = this.size
45+
detectTransformGestures(
46+
consume = consume,
47+
onGestureEnd = {
48+
coroutineScope.launch {
49+
animatedZoomState.onGestureEnd {
50+
}
51+
}
52+
},
53+
onGesture = { centroid, pan, zoom, rotate, mainPointer, pointerList ->
54+
55+
coroutineScope.launch {
56+
animatedZoomState.onGesture(
57+
centroid = centroid,
58+
pan = pan,
59+
zoom = zoom,
60+
rotation = rotate,
61+
mainPointer = mainPointer,
62+
changes = pointerList
63+
)
64+
}
65+
}
66+
)
67+
}
68+
69+
val tapModifier = Modifier.pointerInput(key) {
70+
// Pass size of this Composable this Modifier is attached for constraining operations
71+
// inside this bounds
72+
animatedZoomState.size = this.size
73+
detectTapGestures(
74+
onDoubleTap = {
75+
coroutineScope.launch {
76+
animatedZoomState.onDoubleTap {}
77+
}
78+
}
79+
)
80+
}
81+
82+
val graphicsModifier = Modifier.graphicsLayer {
83+
this.update(animatedZoomState)
84+
}
85+
86+
this.then(
87+
(if (clipToBounds) Modifier.clipToBounds() else Modifier)
88+
.then(tapModifier)
89+
.then(transformModifier)
90+
.then(graphicsModifier)
91+
)
92+
},
93+
inspectorInfo = {
94+
name = "animatedZoomState"
95+
96+
}
97+
)

0 commit comments

Comments
 (0)