一、概念
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 实现阴影,传给 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)
)
}

352

被折叠的 条评论
为什么被折叠?



