一、核心概念与基础用法
1. 核心参数
Image 最基础的构造函数包含 3 个核心参数:
| 参数名 | 作用 |
|---|---|
painter | 图片绘制器(核心,指定图片来源) |
contentDescription | 图片描述(无障碍适配,必填;无描述则传 null,但需加 Modifier.semantics { contentDescription = null }) |
modifier | 布局 / 样式修饰符(尺寸、裁剪、缩放、点击等) |
2. 基础示例(加载本地资源图片)
@Composable
fun BasicImageDemo() {
// 加载 res/drawable 目录下的图片(如 ic_launcher.png)
Image(
painter = painterResource(id = R.drawable.ic_launcher_background),
contentDescription = "应用图标", // 无障碍描述
modifier = Modifier
.size(100.dp) // 设置图片宽高(宽高相同用 size,不同用 width/height)
.padding(16.dp)
)
}
二、图片来源(painter 的多种实现)
painter 是 Image 的核心,不同图片来源对应不同的 Painter 实现:
| 图片来源 | 实现方式 | 适用场景 |
|---|---|---|
| 本地资源(res/drawable) | painterResource(id = R.drawable.xxx) | 应用内置图片(图标、背景) |
| 网络图片 | 第三方库(Coil/Glide)提供的 rememberAsyncImagePainter | 远程图片(接口返回的 URL) |
| 本地文件 / Uri | rememberImagePainter(File("/path/to/img"))(Coil) | 手机本地文件图片 |
| 矢量图(VectorDrawable) | painterResource(id = R.drawable.ic_vector) | 矢量图标(适配不同分辨率) |
关键示例:加载网络图片(主流方案:Coil 库)
Compose 官方推荐用 Coil 加载网络图片,步骤如下:
- 添加依赖(build.gradle.kts):
dependencies {
// Coil for Compose
implementation("io.coil-kt:coil-compose:2.6.0")
}
2.使用示例:
@Composable
fun NetworkImageDemo() {
val imageUrl = "https://img1.baidu.com/it/u=600722015,3838115472&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=750"
// 加载网络图片(rememberAsyncImagePainter 自动处理缓存、加载状态)
val painter = rememberAsyncImagePainter(
model = imageUrl,
// 配置加载占位符/错误占位符
placeholder = painterResource(id = R.drawable.ic_launcher_background),
error = painterResource(id = R.drawable.ic_launcher_background)
)
Image(
painter = painter,
contentDescription = "网络图片",
modifier = Modifier
.size(200.dp)
.clip(RoundedCornerShape(8.dp)), // 圆角裁剪
contentScale = ContentScale.Crop // 缩放模式
)
}
三、核心样式配置
1. 缩放模式(contentScale)
控制图片如何适配 Image 的尺寸(类似 ImageView 的 scaleType),常用值:
| 值 | 作用 |
|---|---|
ContentScale.Fit | 等比例缩放,图片完整显示(可能留空白) |
ContentScale.Crop | 等比例缩放,填满容器(超出部分裁剪,常用作头像 / 封面) |
ContentScale.FillBounds | 拉伸图片填满容器(可能变形,不推荐) |
ContentScale.Center | 图片居中显示,不缩放(超出部分裁剪) |
ContentScale.Inside | 类似 Fit,但图片尺寸不超过原始尺寸 |
示例:
Image(
painter = painterResource(id = R.drawable.test_img),
contentDescription = "缩放示例",
modifier = Modifier.size(200.dp),
contentScale = ContentScale.Crop // 裁剪填充
)
2. 裁剪与形状(modifier + Clip)
通过 modifier.clip() 实现图片裁剪,支持多种形状:
@Composable
fun ImageClipDemo() {
Column(modifier = Modifier.padding(16.dp)) {
// 1. 圆角图片
Image(
painter = painterResource(id = R.drawable.ic_launcher_background),
contentDescription = "圆角图片",
modifier = Modifier
.size(100.dp)
.clip(RoundedCornerShape(16.dp)), // 圆角半径
contentScale = ContentScale.Crop
)
Spacer(modifier = Modifier.height(16.dp))
// 2. 圆形图片(头像常用)
Image(
painter = painterResource(id = R.drawable.ic_launcher_background),
contentDescription = "圆形头像",
modifier = Modifier
.size(100.dp)
.clip(CircleShape), // 圆形裁剪
contentScale = ContentScale.Crop
)
Spacer(modifier = Modifier.height(16.dp))
// 3. 自定义形状(如矩形带倒角)
Image(
painter = painterResource(id = R.drawable.ic_launcher_background),
contentDescription = "自定义形状",
modifier = Modifier
.size(100.dp)
.clip(RoundedCornerShape(topStart = 20.dp, bottomEnd = 20.dp)),
contentScale = ContentScale.Crop
)
}
}
3. 边框与阴影
结合 border 和 shadow 修饰符给图片加边框 / 阴影:
@Composable
fun ImageBorderShadowDemo() {
Image(
painter = painterResource(id = R.drawable.ic_launcher_background),
contentDescription = "带边框和阴影的图片",
modifier = Modifier
.size(100.dp)
.shadow( // 阴影:半径、颜色、偏移
elevation = 8.dp,
shape = CircleShape,
//color = Color.Gray.copy(alpha = 0.5f)
)
.clip(CircleShape) // 先裁剪形状,再加边框
.border( // 边框:宽度、颜色、形状
width = 2.dp,
color = Color.Blue,
shape = CircleShape
),
contentScale = ContentScale.Crop
)
}
4. 点击事件
通过 modifier.clickable 给图片加点击 / 长按事件:
@Composable
fun ClickableImageDemo() {
//在最外层获取
val context = LocalContext.current
Image(
painter = painterResource(id = R.drawable.ic_launcher_background),
contentDescription = "可点击图片",
modifier = Modifier
.size(100.dp)
.clip(CircleShape)
.clickable( // 点击事件
onClick = {
Toast.makeText(context, "图片被点击", Toast.LENGTH_SHORT).show()
},
),
contentScale = ContentScale.Crop
)
}
四、进阶用法
1. 加载状态处理(网络图片)
监听网络图片的加载状态(加载中、成功、失败),自定义界面:
@Composable
fun ImageLoadingStateDemo() {
val imageUrl = "https://img2.baidu.com/it/u=2376489989,3127732063&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=657"
val painter = rememberAsyncImagePainter(
model = imageUrl,
placeholder = painterResource(id = R.drawable.ic_launcher_background)
)
// 获取加载状态
val state = painter.state
Column(modifier = Modifier.padding(16.dp)) {
Image(
painter = painter,
contentDescription = "加载状态示例",
modifier = Modifier.size(200.dp),
contentScale = ContentScale.Crop
)
// 根据状态显示提示文字
when (state) {
is AsyncImagePainter.State.Loading -> {
Text(text = "图片加载中...", modifier = Modifier.padding(top = 8.dp))
}
is AsyncImagePainter.State.Success -> {
Text(text = "图片加载成功", modifier = Modifier.padding(top = 8.dp))
}
is AsyncImagePainter.State.Error -> {
Text(
text = "图片加载失败",
color = Color.Red,
modifier = Modifier.padding(top = 8.dp)
)
}
else -> {}
}
}
}
2. 图片淡入动画
给图片添加加载完成后的淡入效果:
@Composable
fun ImageFadeInDemo() {
val imageUrl = "https://img2.baidu.com/it/u=2376489989,3127732063&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=657"
val painter = rememberAsyncImagePainter(model = imageUrl)
// 动画状态:加载成功后从 0f 变为 1f
val alpha by animateFloatAsState(
targetValue = if (painter.state is AsyncImagePainter.State.Success) 1f else 0f,
animationSpec = tween(durationMillis = 500) // 动画时长 500ms
)
Image(
painter = painter,
contentDescription = "淡入图片",
modifier = Modifier
.size(200.dp)
.alpha(alpha), // 透明度动画
contentScale = ContentScale.Crop
)
}
五、性能优化与注意事项
1. 性能优化
-
缓存图片资源:本地图片用
remember缓存Painter(避免每次重组重新加载):kotlin
val painter = remember { painterResource(id = R.drawable.test_img) } -
网络图片优化:Coil 已内置缓存(内存 + 磁盘),无需额外处理;避免频繁修改
model(如 URL)导致重复请求。 -
尺寸优化:给
Image明确设置size/width/height,避免图片自适应导致的额外布局计算。 -
避免过度绘制:图片加背景时,优先用
modifier.background()而非嵌套Box,减少层级。
2. 常见坑点
| 坑点 | 解决方案 |
|---|---|
contentDescription 报错 | 必传参数:有描述则传字符串,无描述则传 null + Modifier.semantics { contentDescription = null } |
| 图片拉伸变形 | 用 contentScale = ContentScale.Crop/Fit,避免 FillBounds |
| 圆形图片有锯齿 | 给 clip(CircleShape) 前加 shadow(微小阴影),或用高分辨率图片 |
| 网络图片加载失败无提示 | 监听 painter.state,显示错误占位符 / 提示文字 |
| 图片边框超出裁剪范围 | 先 clip 再 border(顺序不能反),且边框形状和裁剪形状保持一致 |
六、总结
Image核心是painter(图片来源) +modifier(布局 / 样式) +contentScale(缩放),本地图片用painterResource,网络图片优先用 Coil 的rememberAsyncImagePainter;- 样式配置重点:
contentScale控制缩放(Crop/Fit 最常用),clip控制裁剪(圆形 / 圆角),border/shadow增强视觉效果; - 进阶技巧:监听加载状态实现占位 / 错误提示,结合动画实现淡入效果,注意性能优化(缓存、明确尺寸)和坑点(参数顺序、无障碍描述)。