Compose中Image的使用

一、核心概念与基础用法

1. 核心参数

Image 最基础的构造函数包含 3 个核心参数:

参数名 作用
painter 图片绘制器(核心,指定图片来源)
contentDescription 图片描述(无障碍适配,必填;无描述则传 null,但需加 Modifier.semantics { contentDescription = null }
modifier 布局 / 样式修饰符(尺寸、裁剪、缩放、点击等)

2. 基础示例(加载本地资源图片)

kotlin 复制代码
@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 的多种实现)

painterImage 的核心,不同图片来源对应不同的 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 加载网络图片,步骤如下:

  1. 添加依赖(build.gradle.kts):
scss 复制代码
dependencies {
    // Coil for Compose
    implementation("io.coil-kt:coil-compose:2.6.0")
}

2.使用示例

ini 复制代码
@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 的尺寸(类似 ImageViewscaleType),常用值:

作用
ContentScale.Fit 等比例缩放,图片完整显示(可能留空白)
ContentScale.Crop 等比例缩放,填满容器(超出部分裁剪,常用作头像 / 封面)
ContentScale.FillBounds 拉伸图片填满容器(可能变形,不推荐)
ContentScale.Center 图片居中显示,不缩放(超出部分裁剪)
ContentScale.Inside 类似 Fit,但图片尺寸不超过原始尺寸

示例:

ini 复制代码
Image(
painter = painterResource(id = R.drawable.test_img),
contentDescription = "缩放示例",
modifier = Modifier.size(200.dp),
contentScale = ContentScale.Crop // 裁剪填充
)

2. 裁剪与形状(modifier + Clip)

通过 modifier.clip() 实现图片裁剪,支持多种形状:

ini 复制代码
@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. 边框与阴影

结合 bordershadow 修饰符给图片加边框 / 阴影:

ini 复制代码
@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 给图片加点击 / 长按事件:

ini 复制代码
@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. 加载状态处理(网络图片)

监听网络图片的加载状态(加载中、成功、失败),自定义界面:

ini 复制代码
@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. 图片淡入动画

给图片添加加载完成后的淡入效果:

ini 复制代码
@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

    ini 复制代码
    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,显示错误占位符 / 提示文字
图片边框超出裁剪范围 clipborder(顺序不能反),且边框形状和裁剪形状保持一致

六、总结

  1. Image 核心是 painter(图片来源) + modifier(布局 / 样式) + contentScale(缩放),本地图片用 painterResource,网络图片优先用 Coil 的 rememberAsyncImagePainter
  2. 样式配置重点:contentScale 控制缩放(Crop/Fit 最常用),clip 控制裁剪(圆形 / 圆角),border/shadow 增强视觉效果;
  3. 进阶技巧:监听加载状态实现占位 / 错误提示,结合动画实现淡入效果,注意性能优化(缓存、明确尺寸)和坑点(参数顺序、无障碍描述)。
相关推荐
阿巴斯甜3 小时前
Compose中 buildAnnotatedString的使用:
android jetpack
阿巴斯甜4 小时前
Compose中Text的使用:
android jetpack
阿巴斯甜1 天前
compose中 box的使用
android jetpack
阿巴斯甜1 天前
Android compose中 ConstraintLayout 的使用
android jetpack
阿巴斯甜1 天前
Android LazyRow的使用
android jetpack
阿巴斯甜1 天前
Android Row 的使用
android jetpack
林栩link1 天前
Now in Android 现代应用开发实践(三):架构设计(UI)
android·android jetpack
段娇娇1 天前
Android jetpack LiveData (二) 原理篇
android·android jetpack
阿巴斯甜1 天前
Android LazyColumn的使用
android jetpack