Skip to content

Commit f5e57a1

Browse files
add EnhancedZoomDemo
1 parent 58b096c commit f5e57a1

File tree

1 file changed

+244
-0
lines changed

1 file changed

+244
-0
lines changed
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
package com.smarttoolfactory.composeimage.demo
2+
3+
import android.graphics.Bitmap
4+
import androidx.compose.foundation.*
5+
import androidx.compose.foundation.layout.*
6+
import androidx.compose.material.Text
7+
import androidx.compose.runtime.*
8+
import androidx.compose.ui.Modifier
9+
import androidx.compose.ui.draw.clipToBounds
10+
import androidx.compose.ui.geometry.Offset
11+
import androidx.compose.ui.geometry.Rect
12+
import androidx.compose.ui.geometry.Size
13+
import androidx.compose.ui.graphics.*
14+
import androidx.compose.ui.graphics.drawscope.DrawScope
15+
import androidx.compose.ui.graphics.drawscope.Stroke
16+
import androidx.compose.ui.layout.ContentScale
17+
import androidx.compose.ui.platform.LocalContext
18+
import androidx.compose.ui.res.imageResource
19+
import androidx.compose.ui.unit.IntOffset
20+
import androidx.compose.ui.unit.IntSize
21+
import androidx.compose.ui.unit.dp
22+
import com.smarttoolfactory.composeimage.R
23+
import com.smarttoolfactory.image.zoom.EnhancedZoomData
24+
import com.smarttoolfactory.image.zoom.enhancedZoom
25+
import com.smarttoolfactory.image.zoom.rememberEnhancedZoomState
26+
27+
@Composable
28+
fun EnhancedZoomDemo() {
29+
30+
Column(
31+
modifier = Modifier
32+
.fillMaxSize()
33+
.verticalScroll(rememberScrollState())
34+
.background(Color.Gray)
35+
.padding(top = 40.dp)
36+
) {
37+
38+
val imageBitmapLarge = ImageBitmap.imageResource(
39+
LocalContext.current.resources,
40+
R.drawable.landscape6
41+
)
42+
43+
BoxWithConstraints(
44+
modifier = Modifier
45+
.fillMaxWidth()
46+
.aspectRatio(4 / 3f)
47+
) {
48+
val width = constraints.maxWidth
49+
val height = constraints.maxHeight
50+
51+
52+
var rectCrop by remember {
53+
mutableStateOf(
54+
Rect(
55+
offset = Offset.Zero,
56+
size = Size(
57+
imageBitmapLarge.width.toFloat(),
58+
imageBitmapLarge.height.toFloat()
59+
)
60+
)
61+
)
62+
}
63+
64+
var rectDraw by remember {
65+
mutableStateOf(
66+
Rect(
67+
offset = Offset.Zero,
68+
size = Size(width.toFloat(), height.toFloat())
69+
)
70+
)
71+
}
72+
73+
74+
val zoomState = rememberEnhancedZoomState(
75+
minZoom = .5f,
76+
imageSize = IntSize(imageBitmapLarge.width, imageBitmapLarge.height),
77+
containerSize = IntSize(width, height)
78+
)
79+
80+
val modifier = Modifier
81+
.clipToBounds()
82+
.enhancedZoom(
83+
enhancedZoomState = zoomState,
84+
onDown = { zoomData: EnhancedZoomData ->
85+
rectDraw = zoomData.drawRect
86+
rectCrop = zoomData.cropRect
87+
},
88+
onMove = { zoomData: EnhancedZoomData ->
89+
rectDraw = zoomData.drawRect
90+
rectCrop = zoomData.cropRect
91+
},
92+
onUp = { zoomData: EnhancedZoomData ->
93+
rectDraw = zoomData.drawRect
94+
rectCrop = zoomData.cropRect
95+
}
96+
)
97+
.size(maxWidth, maxHeight)
98+
99+
100+
Image(
101+
modifier = modifier,
102+
bitmap = imageBitmapLarge,
103+
contentDescription = null,
104+
contentScale = ContentScale.FillBounds
105+
)
106+
107+
DrawingOverlay(
108+
modifier = Modifier.size(maxWidth, maxHeight),
109+
rect = rectDraw,
110+
touchRegionWidth = 100f
111+
)
112+
113+
if (rectCrop.size != Size.Zero) {
114+
Image(
115+
modifier = Modifier
116+
.offset {
117+
IntOffset(0, 900)
118+
}
119+
.size(maxWidth, maxHeight),
120+
bitmap = Bitmap.createBitmap(
121+
imageBitmapLarge.asAndroidBitmap(),
122+
rectCrop.left.toInt(),
123+
rectCrop.top.toInt(),
124+
rectCrop.width.toInt().coerceAtMost(imageBitmapLarge.width),
125+
rectCrop.height.toInt().coerceAtMost(imageBitmapLarge.height),
126+
).asImageBitmap(),
127+
contentDescription = null,
128+
contentScale = ContentScale.FillBounds
129+
)
130+
}
131+
132+
Text(
133+
"isAnimating: ${zoomState.isAnimationRunning}, " +
134+
"isPanAnimating: ${zoomState.isPanning}, " +
135+
"isZooming: ${zoomState.isZooming}\n" +
136+
"rectDraw: $rectDraw",
137+
color = Color.Green
138+
)
139+
}
140+
}
141+
}
142+
143+
@Composable
144+
internal fun DrawingOverlay(
145+
modifier: Modifier,
146+
rect: Rect,
147+
touchRegionWidth: Float
148+
) {
149+
150+
val path = remember(rect) {
151+
Path().apply {
152+
153+
if (rect != Rect.Zero) {
154+
// Top left lines
155+
moveTo(rect.topLeft.x, rect.topLeft.y + touchRegionWidth)
156+
lineTo(rect.topLeft.x, rect.topLeft.y)
157+
lineTo(rect.topLeft.x + touchRegionWidth, rect.topLeft.y)
158+
159+
// Top right lines
160+
moveTo(rect.topRight.x - touchRegionWidth, rect.topRight.y)
161+
lineTo(rect.topRight.x, rect.topRight.y)
162+
lineTo(rect.topRight.x, rect.topRight.y + touchRegionWidth)
163+
164+
// Bottom right lines
165+
moveTo(rect.bottomRight.x, rect.bottomRight.y - touchRegionWidth)
166+
lineTo(rect.bottomRight.x, rect.bottomRight.y)
167+
lineTo(rect.bottomRight.x - touchRegionWidth, rect.bottomRight.y)
168+
169+
// Bottom left lines
170+
moveTo(rect.bottomLeft.x + touchRegionWidth, rect.bottomLeft.y)
171+
lineTo(rect.bottomLeft.x, rect.bottomLeft.y)
172+
lineTo(rect.bottomLeft.x, rect.bottomLeft.y - touchRegionWidth)
173+
}
174+
}
175+
}
176+
177+
Canvas(modifier = modifier) {
178+
179+
val color = Color.White
180+
val strokeWidth = 2.dp.toPx()
181+
182+
with(drawContext.canvas.nativeCanvas) {
183+
val checkPoint = saveLayer(null, null)
184+
185+
// Destination
186+
drawRect(Color(0x77000000))
187+
188+
// Source
189+
drawRect(
190+
topLeft = rect.topLeft,
191+
size = rect.size,
192+
color = Color.Transparent,
193+
blendMode = BlendMode.Clear
194+
)
195+
restoreToCount(checkPoint)
196+
}
197+
198+
drawGrid(rect)
199+
drawPath(
200+
path,
201+
color,
202+
style = Stroke(strokeWidth * 2)
203+
)
204+
}
205+
}
206+
207+
208+
fun DrawScope.drawGrid(rect: Rect, color: Color = Color.White) {
209+
210+
val width = rect.width
211+
val height = rect.height
212+
val gridWidth = width / 3
213+
val gridHeight = height / 3
214+
215+
216+
drawRect(
217+
color = color,
218+
topLeft = rect.topLeft,
219+
size = rect.size,
220+
style = Stroke(width = 2.dp.toPx())
221+
)
222+
223+
// Horizontal lines
224+
for (i in 1..2) {
225+
drawLine(
226+
color = color,
227+
start = Offset(rect.left, rect.top + i * gridHeight),
228+
end = Offset(rect.right, rect.top + i * gridHeight),
229+
strokeWidth = .7.dp.toPx()
230+
)
231+
}
232+
233+
// Vertical lines
234+
for (i in 1..2) {
235+
drawLine(
236+
color,
237+
start = Offset(rect.left + i * gridWidth, rect.top),
238+
end = Offset(rect.left + i * gridWidth, rect.bottom),
239+
strokeWidth = .7.dp.toPx()
240+
)
241+
}
242+
}
243+
244+

0 commit comments

Comments
 (0)