用Compose实现一下炫酷的头像悬停效果

408 阅读2分钟

前两天看到这样一个效果,感觉挺有意思(原文地址:A Fancy Hover Effect For Your Avatar | CSS-Tricks - CSS-Tricks) 就想用安卓也实现一个挺简单的,就分享下实现)

放置图片并实现缩放效果

这一步很简单就是放置一个Image 附上使用的图片链接 assets.codepen.io/1480814/av+…

var scaled by remember {
    mutableStateOf(false)
}
val imgScale by animateFloatAsState(targetValue = if (scaled) 1.25f else 1f)
Box(modifier = Modifier
    .border(5.dp, Color.Red, CircleShape)
    .clip(CircleShape)
    .pointerInteropFilter {
        when (it.action) {
            MotionEvent.ACTION_DOWN -> {
                scaled = true
            }
            MotionEvent.ACTION_MOVE -> {}
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                scaled = false
            }
            else -> false
        }
        true
    }) {
    Image(
        modifier = Modifier
            .size(300.dp)
            .scale(imgScale),
        painter = painterResource(id = R.drawable.ic_avatar),
        contentDescription = null
    )
}

效果如下:

屏幕录制2023-02-12 16.44.13.gif

实现头像悬浮效果

借鉴原作者的思路,只要裁切时的形状是如下的绿幕形状即可

image.png

实现代码如下

class HoverShape() : Shape {
    override fun createOutline(
        size: Size,
        layoutDirection: LayoutDirection,
        density: Density
    ): Outline {
        return Outline.Rounded(
            RoundRect(
                left = 0f,
                top = -size.height,
                right = size.width,
                bottom = size.height,
                bottomLeftCornerRadius = CornerRadius(size.width),
                bottomRightCornerRadius = CornerRadius(size.width)
            )
        )
    }
}

@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun FancyHoverAvatar(modifier: Modifier) {
    var scaled by remember {
        mutableStateOf(false)
    }
    val imgScale by animateFloatAsState(targetValue = if (scaled) 1.25f else 1f)
    Box(modifier = modifier
        .clip(HoverShape())
        .drawWithContent {
            val width = size.width * 0.025f
            drawCircle(Color(0xFFECD078))
            drawArc(
                color = Color(0xFFC02942),
                startAngle = 180f,
                sweepAngle = 180f,
                topLeft = Offset(width / 2, width / 2),
                size = Size(size.width - width, size.height - width),
                useCenter = false,
                style = Stroke(width),
            )
            drawContent()
            drawArc(
                color = Color(0xFFC02942),
                startAngle = 0f,
                sweepAngle = 180f,
                topLeft = Offset(width / 2, width / 2),
                size = Size(size.width - width, size.height - width),
                useCenter = false,
                style = Stroke(width),
            )
        }
        .pointerInteropFilter {
            when (it.action) {
                MotionEvent.ACTION_DOWN -> {
                    scaled = true
                }

                MotionEvent.ACTION_MOVE -> {}
                MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                    scaled = false
                }

                else -> false
            }
            true
        }) {

        Image(
            modifier = Modifier
                .size(300.dp)
                .scale(imgScale),
            painter = painterResource(id = R.drawable.ic_avatar),
            contentDescription = null
        )
    }
}

(简要说说实现,因为没啥人看)

圆环绘制

原本的圆环部分不再用border实现,因为上下两部分的和图片的层级关系不一致,就直接调用drawArc的方式控制先后绘制顺序

裁切效果

继承Shape类后,按照原作者的绿幕形状进行实现即可,可查看上面的HoverShape部分,很容易

椭圆变形效果(未实现)

写到上面部分就懒下来了

最终效果

屏幕录制2023-02-12 16.54.43.gif

结语

用Compose可以极快的实现一些特定的效果,欢迎大家也来尝试!