使用简单代码在Android Jetpack Compose中开发绘图应用

使用 Jetpack Compose 触控功能在 Canvas 上画出图形。
如果大家有意学习 Android,不妨先从妙趣横生的绘图应用起步。在今天的文章中,我们将共同了解如何使用最新 Android Jetpack Compose 开发一款绘图应用。
目前 Jetpack Compose 仍处于 Alpha 测试阶段,因此大家必须下载 Android Studio 4.2(Canary 版)并完成以下设置才能使用。
绘图应用的开发流程非常简单,只需要三步:
-
Canvas 绘图画布
-
触控检测(按压与触控移动)
-
根据触控检测绘制路径
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Canvas(modifier = Modifier.fillMaxSize()) {
// Drawing happens here
}
}
}
在这里,我们只需要通过 fillMaxSize() 设置 Modifier,确保其占用应用程序中的整个空间。
override fun onTouchEvent(event: MotionEvent?): Boolean {
when (event?.action) {
MotionEvent.ACTION_DOWN -> { }
MotionEvent.ACTION_MOVE -> { }
MotionEvent.ACTION_UP -> { }
else -> return false
}
invalidate()
return true
}
Canvas(modifier = Modifier
.fillMaxSize()
.pointerInteropFilter {
when (it.action) {
MotionEvent.ACTION_DOWN -> { }
MotionEvent.ACTION_MOVE -> { }
MotionEvent.ACTION_UP -> { }
else -> false
}
true
}
)
从以上代码来看,二者其实非常相似,唯一的区别在于后者不再需要 invalidate。Jetpack Compose 会通过更改部分状态值通知所需图形。
下面,我们具体聊聊传统 Android 与 Jetpack Compose 之间的工作方式差异。
如下图所示,检测触控与绘制的位置有所不同。
private val action: MutableState<Any?> = mutableStateOf(null)
private val path = Path()
when (it.action) {
MotionEvent.ACTION_DOWN -> {
action.value = it
path.moveTo(it.x, it.y)
}
MotionEvent.ACTION_MOVE -> {
action.value = it
path.lineTo(it.x, it.y)
}
else -> false
}
{
action.value?.let {
drawPath(
path = path,
color = Color.Green,
alpha = 1f,
style = Stroke(10f))
}
}
private val action: MutableState<Any?> = mutableStateOf(null)
private val path = Path()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Canvas(modifier = Modifier
.fillMaxSize()
.pointerInteropFilter {
when (it.action) {
MotionEvent.ACTION_DOWN -> {
action.value = it
path.moveTo(it.x, it.y)
}
MotionEvent.ACTION_MOVE -> {
action.value = it
path.lineTo(it.x, it.y)
}
else -> false
}
true
}
) {
action.value?.let {
drawPath(
path = path,
color = Color.Green,
alpha = 1f,
style = Stroke(10f))
}
}
}
}
如果您是一位经验丰富的开发者,也许会好奇我们能否直接在绘图函数内设置 path 坐标,由此代替通过 action 发送该坐标。相应代码如下所示:
没问题,这在技术上完全可行。
但根据我的经验,一旦触发后续 action,则某些 action 更新有可能无法正确被发送至绘图函数(特别是在 ACTION_DOWN 之后由 ACTION_MOVE 触发 action 的情况下,此时由 ACTION_DOWN 发出的 action 将会丢失)。
不知道这是功能层面的限制,还是受到 alpha 版本的影响,具体情况仍然有待观察。
因此,为了实现正确的操作效果并获取完整路径信息,请在触控检测函数中设置 path 以避免丢失问题。
https://elye-project.medium.com/code-simple-android-jetpack-compose-drawing-app-886d1146ad20