Android开发 - Jetpack Compose能使用.9图吗

前言

在Android开发中,”.9图”(通常指的是.9.png文件)是一种特殊格式的PNG图像,它允许开发者定义哪些部分可以被拉伸以及哪些部分是内容区域。

这种图像格式非常有用,尤其是在需要适应不同屏幕尺寸和分辨率的情况下。

将制作好的.9图放入项目的res/drawable文件夹下,然后像引用普通Drawable资源一样在XML布局文件或者代码中引用即可。

黑线的作用

边缘位置 黑线作用 说明
左边(Left) 定义纵向可拉伸区域 标记哪些行(Y方向)可以被拉伸(复制),用于适应高度变化
上边(Top) 定义横向可拉伸区域 标记哪些列(X方向)可以被拉伸(复制),用于适应宽度变化
右边(Right) 定义内容的垂直显示范围(padding top/bottom) 控制子内容(如文字)在垂直方向上的安全区域
下边(Bottom) 定义内容的水平显示范围(padding left/right) 控制子内容在水平方向上的安全区域

注意:

  1. 黑线必须是纯黑色(#000000),且透明度为100%,不能使用灰色或半透明。
  2. 黑线只能画在最外层1像素的边缘上(即图像四周额外加的1px边框)。
  3. 如果未定义内容区域(右/下黑线),系统默认整个图像区域都可用于显示内容。

Jetpack Compose中怎样用

Jetpack Compose 中不支持”.9图”。

加载.9图会报错崩溃。

Jetpack Compose 原生不支持 Android 传统的 .9.png(点九图)格式

这是因为 Compose 的设计理念更倾向于使用声明式、矢量化的 UI 构建方式,而 .9.png 是一种基于位图的、依赖底层 Android View 系统的资源处理机制。

不过,在 Compose 中我们仍然可以通过其他方式实现类似 .9.png 的可拉伸背景效果

以下是几种推荐方案:

通过AndroidView包装传统ImageView

如果你必须使用 .9.png 并保留其拉伸行为,可以临时用 AndroidView 嵌入一个 ImageView

1
2
3
4
5
6
7
8
9
10
11
AndroidView(
factory = { context ->
AppCompatImageView(context).apply {
setImageResource(R.drawable.bg_button)
scaleType = ScaleType.FIT_XY
}
},
modifier = Modifier
.fillMaxWidth()
.height(60.dp)
)

优缺点

✅ 优点:完全兼容原有 .9.png
❌ 缺点:破坏 Compose 纯净性,性能略差,不推荐长期使用

改用Vector Drawable

如果背景是简单形状(如圆角矩形、带边框、阴影等),强烈建议用 VectorDrawable 替代 .9.png

例如,定义一个 res/drawable/bg_button.xml

1
2
3
4
5
6
7
8
9
10
<!-- res/drawable/bg_button.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="200dp"
android:height="60dp"
android:viewportWidth="200"
android:viewportHeight="60">
<path
android:pathData="M10,0 L190,0 Q200,0 200,10 L200,50 Q200,60 190,60 L10,60 Q0,60 0,50 L0,10 Q0,0 10,0 Z"
android:fillColor="#FF4CAF50"/>
</vector>

然后在 Compose 中使用:

1
2
3
4
5
6
7
8
Image(
painter = painterResource(R.drawable.bg_button),
contentDescription = null,
modifier = Modifier
.fillMaxWidth()
.height(60.dp)
.clip(RoundedCornerShape(10.dp)) // 如果需要额外圆角
)

优缺点

✅ 优点:无限缩放不失真、文件小、适配所有屏幕
✅ 完美契合 Compose 理念

用Compose自绘图形

对于简单背景(如圆角矩形、渐变、边框),直接用 Compose 绘制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Box(
modifier = Modifier
.fillMaxWidth()
.height(60.dp)
.drawBehind {
drawRoundRect(
color = Color.Green,
cornerRadius = CornerRadius(16f, 16f),
style = Fill
)
// 可添加描边、阴影等
}
.padding(16.dp),
contentAlignment = Alignment.Center
) {
Text("按钮文字", color = Color.White)
}

优缺点

✅ 优点:完全动态、可响应状态变化、无资源文件依赖
✅ 性能好,符合现代 Compose 最佳实践

总结

需求 推荐方案
简单背景(圆角、颜色、边框) drawBehind / Modifier.background()
复杂但可矢量化的图形 VectorDrawable
必须使用位图且需拉伸(如聊天气泡) ⚠️ 临时用 AndroidView + ImageView
长期维护、现代化项目 ❌ 避免 .9.png,全面转向矢量或 Compose 绘图

💡 最佳实践:

在新 Compose 项目中,尽量不要使用 .9.png

VectorDrawable 或 Compose 自绘代替,既简洁又高效。