HarmonyOS resizable 图片拉伸实战:从九宫格到网格矩阵完整方案
摘要: resizable属性用于图片适配不同尺寸容器,避免关键区域(如圆角、边框)变形。提供两种实现方案: slice(九宫格):通过偏移值划分四个固定角和可拉伸区域,适用于聊天气泡等场景。 lattice(网格矩阵):通过坐标数组划分网格,偶数行列交叉区域固定,适用于带Logo占位图等场景。 关键点: slice:需指定上下左右偏移值(建议用px单位),四个角固定不变。 lattice:需调整
一、啥场景需要 resizable
图片要适配不同尺寸容器时,直接拉伸容易导致关键区域变形。比如圆角、边框、图案细节这些地方一旦拉伸,视觉效果就崩了。
典型例子:聊天消息气泡。气泡背景要随内容长度和高度动态调整,但四周圆角和小三角指示符不能变形。
Image 组件的 resizable 属性能精准指定图片的可拉伸区域和固定区域,确保不同尺寸容器里都能保持好效果。
本文用两个场景讲 resizable:
- 聊天消息气泡
- 可拉伸占位图(中间 Logo 不变形)
二、实现原理:固定区域和可拉伸区域
resizable 核心原理:用特定规则划分图片固定区域和可拉伸区域。拉伸时只拉伸可拉伸区域,固定区域保持原始尺寸形态不变。
resizable 参数类型是 ResizableOptions,有两种方案:
slice:九宫格方式lattice:网格矩阵方式
slice 方式:九宫格
通过 slice 参数指定原图片上下左右四个方向偏移值(px),把图片划分为九宫格布局:
- 四个角区域为固定区域
- 其余为可拉伸区域

拉伸时各区域效果:
- 四个角保持固定宽高
- 中间区域可上下左右拉伸
- 顶部和底部可拉伸区域保持高度不变
- 左右两侧可拉伸区域保持宽度不变

slice 除了 resizable,还能在 backgroundImageResizable 里使用。
注意:坐标参数传数字时默认单位是 vp,最终转成 px。要让固定区域在不同设备保持一致效果,要传 px 单位数据:
Image($r('app.media.bg_right_message'))
.resizable({
slice: {
left: '40px',
top: '80px',
right: '70px',
bottom: '40px'
}
})
lattice 方式:网格矩阵
通过 lattice 参数设置横向和纵向坐标点数组(px),把图片划分为规则矩形网格。行列数为数组长度 + 1。
关键规则:偶数行与偶数列交叉处的格子为固定区域(蓝色部分),其余为可拉伸区域。拉伸时固定区域保持原尺寸,其他区域根据需要拉伸。

比如上图用 x 轴坐标点数组 [1, 50, 648] 和 y 轴坐标点数组 [1, 50, 253],划分成 3 行 3 列网格。蓝色区域是偶数行偶数列交叉的固定区域。
行列计数从 0 开始:
- 0 行 0 列、0 行 2 列、2 行 0 列、2 行 2 列 → 均为偶数行列交叉区域,固定不可拉伸
示例代码:
// x轴坐标点数组(图片分割)
private xDivs: Array<number> = [1, 60, 243];
// y轴坐标点数组(图片分割)
private yDivs: Array<number> = [1, 50, 253];
// 创建网格对象
private drawingLatticeFirst: DrawingLattice =
drawing.Lattice.createImageLattice(this.xDivs, this.yDivs, this.xDivs.length, this.yDivs.length);
// 应用
Image($r('app.media.placeholder_img'))
.height(this.imgHeight)
.width('100%')
.resizable({
lattice: this.drawingLatticeFirst
})
slice 和 lattice 对比:
| 对比维度 | slice | lattice |
|---|---|---|
| 核心逻辑 | 上下左右四个偏移量定义四个角为固定区域 | 横向纵向坐标点划分网格矩阵,偶数行列交叉区域为固定 |
| 适用场景 | 四个角不拉伸,如聊天气泡、输入框背景、优惠券 | 中间区域不拉伸,如带 Logo 占位图、复杂边框弹窗 |
三、slice 实现聊天消息气泡
场景咋回事
聊天消息气泡是社交应用常见场景。消息内容长度高度不同时,气泡要保持四周圆角和小三角指示符形状不变。

实现步骤
第一步:划分网格确定偏移值
通过 UX 提供的坐标点或 PhotoShop 等工具,找到原图固定区域上下左右准确偏移值。

第二步:实现消息气泡布局
slice 支持 backgroundImageResizable 属性。给消息内容 Text 组件设置 backgroundImage,作为内容背景图片。内容宽高不同时背景图片随之伸缩。把偏移值赋给 backgroundImageResizable 的 slice 参数:
Text(this.message)
.fontSize($r('sys.float.Body_L'))
.fontColor($r('sys.color.font_primary'))
// 设置背景图片
.backgroundImage($r('app.media.bg_left_message'))
// 设置最大宽度和最小宽高,避免内容过多或过少时异常
.constraintSize({
maxWidth: 'calc(100% - 90vp)',
minHeight: 40,
minWidth: 50
})
// 设置内容内边距
.padding({
left: 20,
top: 10,
right: 10,
bottom: 10
})
// 设置背景图片尺寸
.backgroundImageSize({
height: '100%',
width: '100%'
})
// 设置固定区域偏移值(九宫格 slice)
.backgroundImageResizable({
slice: {
left: '70px',
top: '80px',
right: '40px',
bottom: '40px'
}
})
关键点:
backgroundImage:设置背景图片资源backgroundImageSize:设置背景图片尺寸为 100%backgroundImageResizable:设置 slice 偏移值,px 单位
四、lattice 实现可拉伸占位图
场景咋回事
可拉伸占位图需要边缘区域可拉伸,中间 Logo 区域保持不变。

实现步骤
第一步:划分网格确定坐标点数组
中间 Logo 区域是固定部分。根据 lattice 原理,划分时要把中间区域放在偶数行偶数列交叉点。
Logo 区域坐标数组可由 UX 提供,或用 PhotoShop 手动定位。示例中 x 轴坐标数组为 [150, 648],y 轴为 [150, 733]。
直接用这坐标点,图片被划分为 3 行 3 列网格。Logo 位于第 1 行第 1 列(非偶数行列),达不到预期效果:

解决办法:在 x 轴和 y 轴各增加一个坐标点,使 Logo 位于第 2 行第 2 列(偶数行列)。
在原坐标前添加一个较小值如 1,新 x 轴坐标变成 [1, 150, 648],y 轴变成 [1, 150, 733]:

第二步:实现可拉伸占位图布局
根据获得的坐标点数组,用 createImageLattice() 创建网格对象,设给 lattice 参数:
@Component
struct PlaceholderImgView {
// 默认图片高度
@State imgHeight: Length = '35%';
// 是否放大
@State isEnlarge: boolean = false;
// x轴坐标点数组
private xDivs: Array<number> = [1, 60, 243];
// y轴坐标点数组
private yDivs: Array<number> = [1, 50, 253];
// 创建网格对象
private drawingLatticeFirst: DrawingLattice =
drawing.Lattice.createImageLattice(this.xDivs, this.yDivs, this.xDivs.length, this.yDivs.length);
build() {
NavDestination() {
Stack() {
Image($r('app.media.placeholder_img'))
.height(this.imgHeight)
.width('100%')
.resizable({
lattice: this.drawingLatticeFirst
})
.onClick(() => {
if (this.isEnlarge) {
this.imgHeight = '35%';
} else {
this.imgHeight = '100%';
}
this.isEnlarge = !this.isEnlarge;
})
}
}
}
}
点击图片切换高度,验证拉伸效果。
五、踩坑总结
坑一:不同设备拉伸区域显示不一致
用 slice 设置不拉伸区域后,手机显示正常,平板上固定区域变形。
原因:传数字参数默认单位是 vp。不同设备对 vp 的 px 换算比例有差异,导致固定区域效果不一致。
解决:用 px 单位:
.resizable({
slice: {
left: '40px',
top: '80px',
right: '70px',
bottom: '40px'
}
})
坑二:resizable 未生效,图片仍变形
设置了 slice 或 lattice,不可拉伸区域依然变形。
原因:
- 坐标值定位不准确,无法精准锁定目标区域
- 参数配置异常,比如坐标值超出图片宽高范围,或无效参数值
解决:
- 坐标点定位不准 → 参考原理章节重新校准划分
- 参数异常 → 保证坐标点在图片区域内
- lattice x 轴坐标:大于等于 0,小于图片宽度
- lattice y 轴坐标:大于等于 0,小于图片高度
- slice 参数范围:参考 ResizableOptions 说明
六、使用建议
- 四个角不拉伸 → 用 slice(简单,九宫格)
- 中间区域不拉伸 → 用 lattice(灵活,网格矩阵)
- 多设备一致性 → 用 px 单位
- 坐标点定位 → 用 PhotoShop 或 UX 提供数值
记住核心原理:固定区域不变,可拉伸区域拉伸。slice 是九宫格,lattice 是网格矩阵。两者适用场景不同,别混用。
更多推荐



所有评论(0)