Skip to content

Commit 8870dd2

Browse files
add erase to Tutorial6_31EditPolygonPoints1
1 parent 88dce4f commit 8870dd2

File tree

2 files changed

+115
-17
lines changed

2 files changed

+115
-17
lines changed

Tutorial1-1Basics/src/main/java/com/smarttoolfactory/tutorial1_1basics/chapter6_graphics/Tutorial6_31EditPolygonPoints1.kt

Lines changed: 114 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package com.smarttoolfactory.tutorial1_1basics.chapter6_graphics
22

3+
import android.graphics.Bitmap
4+
import android.graphics.PorterDuff
35
import androidx.compose.foundation.Canvas
46
import androidx.compose.foundation.Image
57
import androidx.compose.foundation.background
6-
import androidx.compose.foundation.border
78
import androidx.compose.foundation.layout.Arrangement
8-
import androidx.compose.foundation.layout.Box
9+
import androidx.compose.foundation.layout.BoxWithConstraints
910
import androidx.compose.foundation.layout.Column
1011
import androidx.compose.foundation.layout.Row
12+
import androidx.compose.foundation.layout.aspectRatio
1113
import androidx.compose.foundation.layout.fillMaxSize
1214
import androidx.compose.foundation.layout.fillMaxWidth
1315
import androidx.compose.foundation.layout.padding
@@ -24,21 +26,31 @@ import androidx.compose.runtime.remember
2426
import androidx.compose.runtime.setValue
2527
import androidx.compose.runtime.snapshots.SnapshotStateList
2628
import androidx.compose.ui.Modifier
29+
import androidx.compose.ui.draw.clipToBounds
30+
import androidx.compose.ui.draw.drawWithContent
2731
import androidx.compose.ui.geometry.Offset
32+
import androidx.compose.ui.geometry.Size
33+
import androidx.compose.ui.graphics.BlendMode
34+
import androidx.compose.ui.graphics.Canvas
2835
import androidx.compose.ui.graphics.Color
36+
import androidx.compose.ui.graphics.ImageBitmap
37+
import androidx.compose.ui.graphics.Paint
38+
import androidx.compose.ui.graphics.PaintingStyle
2939
import androidx.compose.ui.graphics.Path
3040
import androidx.compose.ui.graphics.PathEffect
41+
import androidx.compose.ui.graphics.asImageBitmap
3142
import androidx.compose.ui.graphics.drawscope.Stroke
43+
import androidx.compose.ui.graphics.nativeCanvas
3244
import androidx.compose.ui.layout.ContentScale
33-
import androidx.compose.ui.res.painterResource
45+
import androidx.compose.ui.res.imageResource
3446
import androidx.compose.ui.tooling.preview.Preview
47+
import androidx.compose.ui.unit.IntSize
3548
import androidx.compose.ui.unit.dp
3649
import com.smarttoolfactory.tutorial1_1basics.R
3750
import com.smarttoolfactory.tutorial1_1basics.chapter5_gesture.gesture.MotionEvent
3851
import com.smarttoolfactory.tutorial1_1basics.chapter5_gesture.gesture.pointerMotionEvents
3952
import com.smarttoolfactory.tutorial1_1basics.ui.Blue400
4053
import com.smarttoolfactory.tutorial1_1basics.ui.backgroundColor
41-
import com.smarttoolfactory.tutorial1_1basics.ui.components.getRandomColor
4254
import kotlin.math.sqrt
4355

4456
@Preview
@@ -82,6 +94,12 @@ private fun PolygonDrawingApp() {
8294
*/
8395
var currentPolygon by remember { mutableStateOf(Polygon(), policy = neverEqualPolicy()) }
8496

97+
val imageBitmap = ImageBitmap.imageResource(R.drawable.landscape4)
98+
99+
var crop by remember {
100+
mutableStateOf(false)
101+
}
102+
85103
LaunchedEffect(mode, motionEvent) {
86104
if (mode == Mode.Touch && motionEvent == MotionEvent.Idle) {
87105

@@ -116,6 +134,7 @@ private fun PolygonDrawingApp() {
116134
mode = if (mode == Mode.Draw) {
117135
Mode.Touch
118136
} else Mode.Draw
137+
crop = false
119138
}
120139
) {
121140
Text("Mode: $mode")
@@ -125,16 +144,27 @@ private fun PolygonDrawingApp() {
125144
onClick = {
126145
currentPolygon = Polygon()
127146
mode = Mode.Draw
147+
crop = false
128148
}
129149
) {
130150
Text("Reset")
131151
}
152+
153+
Button(
154+
onClick = {
155+
crop = true
156+
}
157+
) {
158+
Text("Crop")
159+
}
132160
}
133161

162+
val sizeModifier = Modifier
163+
.padding(16.dp)
164+
.fillMaxWidth()
165+
.aspectRatio(4 / 3f)
134166

135167
val drawModifier = Modifier
136-
.border(2.dp, getRandomColor())
137-
.fillMaxSize()
138168
.pointerMotionEvents(
139169
onDown = { pointerInputChange ->
140170

@@ -274,18 +304,87 @@ private fun PolygonDrawingApp() {
274304
delayAfterDownInMillis = 20
275305
)
276306

277-
Box {
307+
BoxWithConstraints(sizeModifier) {
308+
val imageWidth = constraints.maxWidth
309+
val imageHeight = constraints.maxHeight
310+
311+
val erasedBitmap: ImageBitmap = remember {
312+
Bitmap.createBitmap(imageWidth, imageHeight, Bitmap.Config.ARGB_8888)
313+
.asImageBitmap()
314+
}
315+
316+
val canvas: Canvas = remember {
317+
Canvas(erasedBitmap)
318+
}
319+
320+
val paint = remember {
321+
Paint()
322+
}
323+
324+
val erasePaint = remember {
325+
Paint().apply {
326+
blendMode = BlendMode.SrcIn
327+
this.style = PaintingStyle.Fill
328+
}
329+
}
330+
331+
canvas.apply {
332+
333+
val canvasWidth = nativeCanvas.width.toFloat()
334+
val canvasHeight = nativeCanvas.height.toFloat()
335+
336+
with(canvas.nativeCanvas) {
337+
drawColor(android.graphics.Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
338+
339+
// Destination
340+
drawPath(path = currentPolygon.path, paint)
341+
342+
// Source
343+
drawImageRect(
344+
image = imageBitmap,
345+
dstSize = IntSize(canvasWidth.toInt(), canvasHeight.toInt()),
346+
paint = erasePaint
347+
)
348+
}
349+
}
350+
278351
Image(
279-
modifier = Modifier.fillMaxSize(),
280-
painter = painterResource(R.drawable.landscape6),
352+
modifier = Modifier.matchParentSize()
353+
.clipToBounds()
354+
.drawWithContent {
355+
val width = this.size.width
356+
val height = this.size.height
357+
358+
val checkerWidth = 10.dp.toPx()
359+
val checkerHeight = 10.dp.toPx()
360+
361+
val horizontalSteps = (width / checkerWidth).toInt()
362+
val verticalSteps = (height / checkerHeight).toInt()
363+
364+
for (y in 0..verticalSteps) {
365+
for (x in 0..horizontalSteps) {
366+
val isGrayTile = ((x + y) % 2 == 1)
367+
drawRect(
368+
color = if (isGrayTile) Color.LightGray else Color.White,
369+
topLeft = Offset(x * checkerWidth, y * checkerHeight),
370+
size = Size(checkerWidth, checkerHeight)
371+
)
372+
}
373+
}
374+
375+
drawContent()
376+
}
377+
.matchParentSize(),
378+
bitmap = if (crop) erasedBitmap else imageBitmap,
281379
contentDescription = null,
282380
contentScale = ContentScale.Crop
283381
)
284382

285-
Canvas(modifier = drawModifier) {
383+
384+
Canvas(modifier = drawModifier.matchParentSize()) {
286385
when (motionEvent) {
287386
MotionEvent.Move -> {
288-
if (mode != Mode.Touch) {
387+
if (mode == Mode.Draw) {
289388
drawLine(
290389
color = Color.Black,
291390
start = firstTouchPoint.position,
@@ -328,7 +427,6 @@ private fun PolygonDrawingApp() {
328427
)
329428
}
330429

331-
332430
val path = currentPolygon.path
333431

334432
drawPath(
@@ -343,7 +441,7 @@ private fun PolygonDrawingApp() {
343441
@Immutable
344442
data class Polygon(
345443
val path: Path = Path(),
346-
val lines: SnapshotStateList<Line> = mutableStateListOf()
444+
val lines: SnapshotStateList<Line> = mutableStateListOf(),
347445
) {
348446
val firstPoint: Point? = lines.firstOrNull()?.start
349447
val lastPoint: Point? = lines.lastOrNull()?.end
@@ -352,7 +450,7 @@ data class Polygon(
352450
@Immutable
353451
data class Line(
354452
val start: Point,
355-
val end: Point
453+
val end: Point,
356454
) {
357455

358456
fun isPointExist(offset: Offset): Boolean {
@@ -365,11 +463,11 @@ data class Line(
365463

366464
class Point(
367465
var position: Offset,
368-
var isTouched: Boolean = false
466+
var isTouched: Boolean = false,
369467
)
370468

371469
private enum class Mode {
372-
Draw, Touch
470+
Draw, Touch, ERASE
373471
}
374472

375473
private fun calculateDistanceFromCenter(center: Offset, position: Offset): Float {

Tutorial1-1Basics/src/main/java/com/smarttoolfactory/tutorial1_1basics/tutorial_list/TutorialList.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2321,7 +2321,7 @@ fun createGestureTutorialList(): List<TutorialSectionModel> {
23212321
)
23222322

23232323
val tutorial5_13_2 = TutorialSectionModel(
2324-
title = "5-13-2 Rotate Drag Box",
2324+
title = "5-13-2 Rotate Drag Zoom Image",
23252325
description = "Rotate, zoom, and/or translate a Box from its current transformation.",
23262326
action = {
23272327
Tutorial5_13Screen2()

0 commit comments

Comments
 (0)