首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

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

使用 Jetpack Compose 触控功能在 Canvas 上画出图形。

如果大家有意学习 Android,不妨先从妙趣横生的绘图应用起步。在今天的文章中,我们将共同了解如何使用最新 Android Jetpack Compose 开发一款绘图应用。

设置 Jetpack Compose 的先决条件

目前 Jetpack Compose 仍处于 Alpha 测试阶段,因此大家必须下载 Android Studio 4.2(Canary 版)并完成以下设置才能使用。

在 Jetpack Compose 中绘图

绘图应用的开发流程非常简单,只需要三步:

  1. Canvas 绘图画布
  2. 触控检测(按压与触控移动)
  3. 根据触控检测绘制路径

设置 Canvas

与传统 Android 开发有所不同,这一次我们不再使用布局。因此,我们不需要构建自定义视图并将其绘制到 Canvas 之上。

override fun onCreate(savedInstanceState: Bundle?) {    super.onCreate(savedInstanceState)    setContent {         Canvas(modifier = Modifier.fillMaxSize()) {            // Drawing happens here        }    }}

在这里,我们只需要通过 fillMaxSize() 设置 Modifier,确保其占用应用程序中的整个空间。

触控检测

要检测触控,我们通常需要在 Android 中的自定义视图内覆盖 onTouchEvent 函数。

override fun onTouchEvent(event: MotionEvent?): Boolean {    when (event?.action) {        MotionEvent.ACTION_DOWN -> { }        MotionEvent.ACTION_MOVE -> { }        MotionEvent.ACTION_UP -> { }        else -> return false    }    invalidate()    return true}

在 Jetpack Compose 当中,我们使用 pointerInteropFilter 修饰符以检测触摸操作。

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 之间的工作方式差异。

基于触控的路径绘制

如下图所示,检测触控与绘制的位置有所不同。

因此,为了触发绘图,我们需要使用 mutableState 值,其行为类似于传统开发中的 invalidate。此外,我们还需要 path 以存储所有坐标。

private val action: MutableState<Any?> = mutableStateOf(null)private val path = Path()

接下来,在检测到图形之后,我们可以更新 action 与 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 更新完成之后,只要能够访问 action、绘图即被触发,具体如下所示。

{    action.value?.let {        drawPath(                path = path,                color = Color.Green,                alpha = 1f,                style = Stroke(10f))    }}

完整代码

没错,只需要不到 50 行代码,我们就拥有了一款由 Jetpack Compose 开发而成的 Android 绘图应用。

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

  • 发表于:
  • 本文为 InfoQ 中文站特供稿件
  • 首发地址https://www.infoq.cn/article/W9tdH01cJQYrrGuSC8Jy
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券