你看这个圆脸😁,又大又可爱~ (Compose低配版)


前言

阅读本文需要一定compose基础,如果没有请移步Jetpack Compose入门详解(实时更新)

在网上看到有人用css写出了下面这种效果;原文链接

我看到了觉得很好玩,于是用Compose撸了一个随手势移动眼珠的版本。


一、Canvas画图

这种笑脸常用的控件肯定实现不了,我们只能用Canvas自己画了

笑脸

我们先画脸

下例当中的size和center都是onDraw 的DrawScope提供的属性,drawCircle则是DrawScope提供的画圆的方法

kotlin 复制代码
Canvas(modifier = modifier
        .size(300.dp),
        onDraw = {

           // 脸
            drawCircle(
                color = Color(0xfffecd00),
                radius = size.width / 2,
                center = center
            )

    })

属性解释

  • color:填充颜色
  • radius: 半径
  • center: 圆心坐标

这里我们半径取屏幕宽度一半,圆心取屏幕中心,画出来的脸效果如下

微笑

微笑是一个弧形,我们使用drawArc来画微笑

kotlin 复制代码
// 微笑
        val smilePadding = size.width / 4

        drawArc(
            color = Color(0xffb57700),
            startAngle = 0f,
            sweepAngle = 180f,
            useCenter = true,
            topLeft = Offset(smilePadding, size.height / 2 - smilePadding / 2),
            size = Size(size.width / 2, size.height / 4)
        )

属性解释

  • color:填充颜色
  • startAngle: 弧形开始的角度,默认以3点钟方向为0度
  • sweepAngle:弧形结束的角度,默认以3点钟方向为0度
  • useCenter :指示圆弧是否要闭合边界中心的标志(上例加不加都无所谓)
  • topLeft :相对于当前平移从0的本地原点偏移,0开始
  • size:要绘制的圆弧的尺寸

效果如下

眼睛和眼珠子

眼睛也是drawCircle方法,只是位置不同,这边就不再多做解释

kotlin 复制代码
            // 左眼
            drawCircle(
                color = Color.White,
                center = Offset(smilePadding, size.height / 2 - smilePadding / 2),
                radius = smilePadding / 2
            )


                //左眼珠子
                drawCircle(
                    color = Color.Black,
                    center = Offset(smilePadding, size.height / 2 - smilePadding / 2),
                    radius = smilePadding / 4
                )



            // 右眼
            drawCircle(
                color = Color.White,
                center = Offset(smilePadding * 3, size.height / 2 - smilePadding / 2),
                radius = smilePadding / 2
            )


                //右眼珠子
                drawCircle(
                    color = Color.Black,
                    center = Offset(smilePadding * 3, size.height / 2 - smilePadding / 2),
                    radius = smilePadding / 4
                )

整个笑脸就画出来了,效果如下

二、跟随手势移动

在实现功能之前我们需要介绍transformableanimateFloatAsStatetranslate

transformable

transformablemodifier用于平移、缩放和旋转的多点触控手势的修饰符,此修饰符本身不会转换元素,只会检测手势。

animateFloatAsState

animateFloatAsState 是通过Float状态变化来控制动画 的状态

知道了这两个玩意过后我们就可以先通过transformable 监听手势滑动然后通过translate 方法和animateFloatAsState方法组成一个平移动画来实现眼珠跟随手势移动

完整的代码:

kotlin 复制代码
@Composable
fun SmileyFaceCanvas(
    modifier: Modifier
) {

    var x by remember {
        mutableStateOf(0f)
    }

    var y by remember {
        mutableStateOf(0f)
    }

    val state = rememberTransformableState { _, offsetChange, _ ->

        x = offsetChange.x
        if (offsetChange.x >50f){
            x = 50f
        }

        if (offsetChange.x < -50f){
            x=-50f
        }

        y = offsetChange.y
        if (offsetChange.y >50f){
            y= 50f
        }

        if (offsetChange.y < -50f){
            y=-50f
        }
    }

    val animTranslateX by animateFloatAsState(
        targetValue = x,
        animationSpec = TweenSpec(1000)
    )

    val animTranslateY by animateFloatAsState(
        targetValue = y,
        animationSpec = TweenSpec(1000)
    )



    Canvas(
        modifier = modifier
            .size(300.dp)
            .transformable(state = state)
    ) {



        // 脸
        drawCircle(
            Color(0xfffecd00),
            radius = size.width / 2,
            center = center
        )

        // 微笑
        val smilePadding = size.width / 4

        drawArc(
            color = Color(0xffb57700),
            startAngle = 0f,
            sweepAngle = 180f,
            useCenter = true,
            topLeft = Offset(smilePadding, size.height / 2 - smilePadding / 2),
            size = Size(size.width / 2, size.height / 4)
        )

        // 左眼
        drawCircle(
            color = Color.White,
            center = Offset(smilePadding, size.height / 2 - smilePadding / 2),
            radius = smilePadding / 2
        )

        translate(left = animTranslateX, top = animTranslateY) {
            //左眼珠子
            drawCircle(
                color = Color.Black,
                center = Offset(smilePadding, size.height / 2 - smilePadding / 2),
                radius = smilePadding / 4
            )
        }


        // 右眼
        drawCircle(
            color = Color.White,
            center = Offset(smilePadding * 3, size.height / 2 - smilePadding / 2),
            radius = smilePadding / 2
        )

        translate(left = animTranslateX, top = animTranslateY) {
            //右眼珠子
            drawCircle(
                color = Color.Black,
                center = Offset(smilePadding * 3, size.height / 2 - smilePadding / 2),
                radius = smilePadding / 4
            )
        }


    }
}

为了不让眼珠子从眼眶里蹦出来,我们将位移的范围限制在了50以内,运行效果如下


总结

通过Canvas中的一些方法配合简单的动画API实现了这个眼珠跟随手势移动的笑脸😁

相关推荐
云水一下35 分钟前
CSS3从零基础到精通(一):前世今生与基础入门
前端·css3
顾凌陵38 分钟前
CSRF&SSRF漏洞攻击的溯源分析与实战
前端·csrf
月月大王的3D日记40 分钟前
Three.js 材质篇(中):从兰伯特到PBR,一篇文章看懂五种光照材质
前端·javascript
且白41 分钟前
leaflet切片变色、地图滤镜逻辑实现 colorfilter
前端·javascript
用户887665426631 小时前
Linux 终端入门:新手必须掌握的常用命令和基本思路
前端·操作系统
李斯维1 小时前
Jetpack 可观察数据容器 LiveData 的入门与基础使用
android·android jetpack
用户125758524361 小时前
Vue3 后台框架的网络请求怎么设计?看 XYGo Admin 三套 Axios 实例与拦截器方案
前端
ZengLiangYi1 小时前
多格式文件解析:JSONL / SQLite / Event Stream
前端·javascript·后端
边界条件╝1 小时前
微前端进阶(一)
前端
ZC跨境爬虫1 小时前
跟着 MDN 学CSS day_34:(CSS 布局全面解析)
前端·css·ui·html·tensorflow