uni-app图片变形是跨端渲染差异与配置偏差叠加所致,需按端分别处理:Android启动图用.9.png,iOS用原生Assets,页面图片依端设置mode和CSS,Canvas绘图须动态计算宽高比。
uni-app 图片变形不是单一问题,而是跨端渲染机制差异叠加配置偏差导致的复合现象。直接改 mode 或加 width: 100% 很可能无效,甚至让 h5 和小程序表现更不一致。
安卓启动图(splash)拉伸:必须用 .9.png,不能只靠尺寸匹配
很多开发者以为只要放一张高分辨率 PNG 就行,结果在中低端机型上严重拉伸——因为 Android 原生层默认按整张图等比缩放到屏幕尺寸,不识别“内容安全区”。
-
splash.9.png必须用draw9patch.bat工具生成,上下边黑线定义水平可拉伸区域,左右边黑线定义垂直可拉伸区域 - 内容区域(即文字/ logo 所在区)要用右、下边的黑线框出,否则会被压缩或拉长
- 图片本身不能带透明边距或白边,否则 9.png 的拉伸逻辑会把空白也当内容处理
- manifest.json 中
"display": "portrait"必须与图片实际方向一致;横屏设备设为"landscape"但需额外提供横版 .9.png
页面内 在不同端行为不一致:别依赖统一 CSS 写法
同一个 ,在微信小程序里留黑边,在 H5 里能用 object-fit: contain 修复,但在 App 端(尤其 Android)可能被 x5 内核忽略,最终还是拉伸。
- App 端优先用
mode="widthfix"+ 容器固定宽高 +flex: 1布局,避免高度塌陷引发的强制缩放 - H5 端可加 class:
.img-contain { width: 100%; height: auto; object-fit: contain; },但需条件编译#ifdef H5 - 微信小程序若容器高度固定(如
height: 400rpx),mode="aspectfit"一定会留白;此时改用mode="scaleToFill"并配合overflow: hidden裁剪,比拉伸更可控 - rpx 在高刷屏(如 90Hz/120Hz)设备上存在转换精度漂移,慎用固定
height: 300rpx控制图片高度
Canvas 绘图时图片变形:关键在动态计算裁剪坐标,不是硬写宽高
直接调 ctx.drawImage(img, x, y, width, height) 是变形主因——你把任意比例的原图强行塞进固定矩形。
- 先用
uni.getImageInfo拿到原始width和height,再算宽高比ratio = width / height - 目标区域宽高为
boxWidth、boxHeight,则:- 若
boxWidth / boxHeight > ratio,说明目标更宽,应以高度为基准:imgH = boxHeight,imgW = ratio * imgH - 反之以宽度为基准:
imgW = boxWidth,imgH = imgW / ratio
- 若
- 用
ctx.save()+ctx.clip()先画目标区域并裁剪,再用计算出的imgW/imgH绘图,确保等比且不溢出 - 别在
drawImage里传死值,比如ctx.drawImage(img, 0, 0, 300, 300)—— 这是绝大多数海报生成变形的根源
iOS 启动图(LaunchScreen.storyboard)和 App 端图片边缘拉伸:需原生介入
uni-app 自身不提供 iOS 启动图的九宫格能力,.9.png 仅限 Android;iOS 必须走原生 Assets.xcassets 配置 LaunchImage,并确保各尺寸图宽高比与设备屏幕严格一致。
- 对按钮、气泡等需要边缘拉伸的 UI 元素,纯前端无法实现精准控制;必须通过原生插件调用:
- iOS:
resizableImageWithCapInsets指定上下左右保留像素 - Android:仍用 .9.png,但需插件将资源注入
drawable-xhdpi等对应目录
- iOS:
- 插件返回的 base64 图片才能用于
,直接引用本地路径的 .9.png 在 App 端不会生效 - uni-app 的
static目录下放的 .9.png 只对 splash 生效,对运行时加载的图片无效
最常被忽略的一点:所有图片适配方案都依赖「原始尺寸信息」。如果用 uni.chooseImage 拿到的是压缩图(sizeType: ['compressed']),width/height 就不准,后续等比计算全错。真要精确控制,得强制取原图或提前预知目标尺寸。











