Compose 修饰符 - 阴影

官方介绍

一、概念

shadow() 会根据组件在屏幕位置呈现不同角度的光照阴影,可以设置阴影高度,更精细的自定义(如阴影扩散或半径等属性)使用另外两个。

Modifier.shadow()

高度阴影

Modifier.dropShadow()

外阴影

Modifier.innerShadow()

内阴影

调用顺序

在内容之上绘制,在其它内容(如背景)之后调用。

在内容之下绘制,在其它内容(如clip、background)之前调用。在内容之上绘制,在其它内容(如背景)之后调用。
绘制效果

从内容边界向内绘制阴影,由低变高。如果内边距不够,内容不是在阴影最高的那一圈内,重叠部分会显得割裂。

从内容边界向外绘制阴影,但边界内也会纯色填充。如果内容背景有透明度,重叠部分会颜色叠加效果。从内容边界向内绘制阴影。和内容的重叠部分会强覆盖。
Row(
    modifier = Modifier.width(500.dp).height(300.dp).background(Color.White),
    verticalAlignment = Alignment.CenterVertically,
    horizontalArrangement = Arrangement.SpaceEvenly
) {
    //【shadow】
    Box(
        modifier = Modifier
            .size(100.dp)
            //背景证明阴影是从边界向内绘制的
            .background(Color.Blue.copy(alpha = 0.1F))
            .shadow(
                elevation = 20.dp,
                shape = RectangleShape
            ),
        contentAlignment = Alignment.Center
    ) {
        Text(
            //边框证明内边距不够会割裂
            modifier = Modifier.border(1.dp,Color.Red),
            text = "shadow"
        )
    }

    //【dropShadow】
    Box(
        modifier = Modifier
            .size(100.dp)
            .dropShadow(
                shape = RectangleShape,
                shadow = Shadow(
                    radius = 5.dp,
                    spread = 5.dp,
                    color = Color.Red
                )
            )
            //背景有透明度,呈现颜色叠加效果(紫色)
            .background(Color.Blue.copy(alpha = 0.5F)),
        contentAlignment = Alignment.Center
    ) {
        Text("dropShadow")
    }

    //【innerShadow】
    Box(
        modifier = Modifier
            .size(100.dp)
            //背景无透明度,呈现强覆盖效果
            .background(Color.Blue.copy(alpha = 1F))
            .innerShadow(
                shape = RectangleShape,
                shadow = Shadow(
                    radius = 5.dp,
                    spread = 5.dp,
                    color = Color.Red
                )
            ),
        contentAlignment = Alignment.Center
    ) {
        Text("innerShadow")
    }
}

二、参数说明

@Immutable
class Shadow private constructor(
    val radius: Dp,        //模糊半径
    val spread: Dp,        //扩散距离
    val offset: DpOffset,        //阴影位置偏移
    color: Color,
    brush: Brush?,
    @FloatRange(from = 0.0, to = 1.0) alpha: Float,
    val blendMode: BlendMode,
)

实现阴影,传给 dropShadow() 或 innerShadow() 使用。

2.1 shadow()

fun Modifier.shadow(
    elevation: Dp,        //阴影高度
    shape: Shape = RectangleShape,        //阴影形状
    clip: Boolean = elevation > 0.dp,
    ambientColor: Color = DefaultShadowColor,
    spotColor: Color = DefaultShadowColor,
)

2.2 dropShadow()

fun Modifier.dropShadow(
    shape: Shape,
    shadow: Shadow
): Modifier

2.3 innerShadow()

fun Modifier.innerShadow(
    shape: Shape,
    shadow: Shadow
): Modifier

三、结合动画使用动态阴影

3.1 按压

将 Shadow 对象的属性与动画结合,当用户按下的时候阴影发生变化,从而提供视觉反馈。

@Composable
fun PressEffect() {
    Box(
        modifier = Modifier.size(500.dp).background(Color.White),
        contentAlignment = Alignment.Center
    ) {
        val interactionSource = remember { MutableInteractionSource() }
        val isPressed by interactionSource.collectIsPressedAsState()

        val outerShadowColor by animateColorAsState(
            targetValue = if (isPressed) Color.Transparent else Color.Blue,
            animationSpec = tween(durationMillis = 1000)
        )
        val innerShadowColor by animateColorAsState(
            targetValue = if (isPressed) Color.Red else Color.Transparent,
            animationSpec = tween(durationMillis = 1000)
        )

        Box(
            modifier = Modifier
                .size(100.dp)
                .clickable(
                    interactionSource = interactionSource,
                    indication = null
                ) { }
                .dropShadow(
                    shape = RoundedCornerShape(70.dp),
                    shadow = Shadow(
                        radius = 10.dp,
                        spread = 5.dp,
                        color = outerShadowColor,
                    )
                )
                .background(
                    color = Color(0xFFFFFFFF),
                    shape = RoundedCornerShape(70.dp)
                )
                .innerShadow(
                    shape = RoundedCornerShape(70.dp),
                    shadow = Shadow(
                        radius = 10.dp,
                        spread = 5.dp,
                        color = innerShadowColor,
                    )
                ),
            contentAlignment = Alignment.Center
        ) {
            Text("按压效果")
        }
    }
}

3.2 呼吸

@Composable
fun BreathEffect() {
    Box(
        modifier = Modifier.size(500.dp).background(Color.White),
        contentAlignment = Alignment.Center
    ) {
        //每秒在 true/false 切换
        val value by remember {
            flow {
                var defaultValue = false
                while (true) {
                    emit(defaultValue)
                    defaultValue = !defaultValue
                    delay(1000)
                }
            }
        }.collectAsState(false)
        //添加动画
        val animatedDp by animateDpAsState(
            targetValue = if (value) 10.dp else 0.dp,
            animationSpec = tween(1000)
        )

        Box(
            modifier = Modifier
                .size(100.dp)
                .dropShadow(
                    shape = RoundedCornerShape(70.dp),
                    shadow = Shadow(
                        radius = animatedDp,
                        spread = animatedDp,
                        //笔刷使用扫描渐变
                        brush = Brush.sweepGradient(
                            listOf(Color.Red, Color.Cyan, Color.Yellow, Color.Green, Color.Blue)
                        )
                    )
                )
                .clip(RoundedCornerShape(70.dp))
                .background(Color(0xFF673AB7)),
            contentAlignment = Alignment.Center
        ) {
            Text("呼吸效果")
        }
    }
}

3.3 拟态

使用与背景色近似的颜色,一个更亮,一个更暗,错位显示。

作为对比,右图移除按钮背景,就是将两个阴影错位。

@Composable
fun Nitai() {
    val shape = RoundedCornerShape(30.dp)
    val bgColor = Color(0xFFe0e0e0)
    val lightShadow = Color(0xFFFFFFFF)
    val darkShadow = Color(0xFFb1b1b1)
    val upperOffset = (-10).dp
    val lowerOffset = 10.dp
    val radius = 15.dp
    val spread = 0.dp
    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(bgColor)
            .wrapContentSize(Alignment.Center)
            .size(240.dp)
            .dropShadow(
                shape,
                shadow = Shadow(
                    radius = radius,
                    color = lightShadow,
                    spread = spread,
                    offset = DpOffset(upperOffset, upperOffset)
                ),
            )
            .dropShadow(
                shape,
                shadow = Shadow(
                    radius = radius,
                    color = darkShadow,
                    spread = spread,
                    offset = DpOffset(lowerOffset, lowerOffset)
                ),

                )
            .background(bgColor, shape)
    )
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值