翻译:English
Sketch 会调整图片的大小避免超出 Target 的需要造成内存浪费
调整图片大小依赖 ImageRequest 的 sizeResolver、precisionDecider、scaleDecider 属性,当他们都确定时会生成一个 Resize 交给 Decoder 使用
Decoder 先在解码时通过子采样或区域子采样降低图片大小,解码后如果大小依然不符合 Resize 要求就会再次调整
Resize 由 Size、Precision、Scale 构成
- Size:期望的宽和高
- Precision:精度。决定如何使用 Size 去调整图片的大小
- Scale:缩放。Precision 为 EXACTLY 或 SAME_ASPECT_RATIO 时决定如何裁剪原图
- START_CROP:保留头部部分
- CENTER_CROP:保留中间部分
- END_CROP:保留尾部部分
- FILL:全部保留,但会变形
ImageRequest 和 ImageOptions 都提供了 resize、size、precision、scale 方法用于配置 Resize,如下:
ImageRequest(context, "https://example.com/image.jpg") {
/* 一次设置三个属性 */
resize(
width = 100,
height = 100,
precision = Precision.SAME_ASPECT_RATIO,
scale = Scale.END_CROP
)
// 或
resize(
size = Size(100, 100),
precision = LongImagePrecisionDecider(Precision.SAME_ASPECT_RATIO),
scale = LongImageScaleDecider(longImage = Scale.START_CROP, otherImage = Scale.CENTER_CROP)
)
// 或
resize(
size = FixedSizeResolver(100, 100),
precision = LongImagePrecisionDecider(Precision.SAME_ASPECT_RATIO),
scale = LongImageScaleDecider(longImage = Scale.START_CROP, otherImage = Scale.CENTER_CROP)
)
/* 仅设置大小属性 */
size(100, 100)
// 或
size(Size(100, 100))
// 或
size(FixedSizeResolver(100, 100))
/* 仅设置精度属性 */
precision(Precision.SAME_ASPECT_RATIO)
// 或
precision(LongImagePrecisionDecider(Precision.SAME_ASPECT_RATIO))
/* 仅设置缩放属性 */
scale(Scale.END_CROP)
// 或
scale(LongImageScaleDecider(longImage = Scale.START_CROP, otherImage = Scale.CENTER_CROP))
}
Sketch 使用 Resolver 包装器为 ImageRequest 提供 Size,这是因为 View 或 Compose 组件的大小在构建 ImageRequest 时可能无法确定,需要等到绘制阶段才能获取,所以借助 SizeResolver 来解决这个问题
Sketch 同样使用 Decider 包装器为 ImageRequest 提供 Precision 和 Scale ,这样就可以在解码时根据图片大小和 Resize 动态决定使用何种 Precision 和 Scale
默认提供了以下实现:
- PrecisionDecider:精度决策器。根据图片大小和 Resize 的 Size 决定使用何种 Precision
- FixedPrecisionDecider:始终使用指定的 Precision
- LongImagePrecisionDecider:如果是长图就使用指定的 Precision,否则始终使用 LESS_PIXELS
- ScaleDecider:缩放决策器。根据图片大小和 Resize 的 Size 决定使用何种 Scale
- FixedScaleDecider:始终使用指定的 Scale
- LongImageScaleDecider:指定两个 Scale,长图使用第一个,否则使用第二个
Tip
- 使用 LongImagePrecisionDecider 和 LongImageScaleDecider 有助于提高长图在网格列表中的清晰度。了解更多
- 长图规则的默认实现为 DefaultLongImageDecider,你还可以在创建 LongImagePrecisionDecider 或 LongImageScaleDecider 时使用自定义的规则
在构建 ImageRequest 时确定这些属性的值还是有些复杂的,如下:
- Size:
- ImageRequest.Builder.sizeResolver
- Target.getImageOptions().sizeResolver
- ImageRequest.Builder.defaultOptions.sizeResolver
- Sketch.globalImageOptions.sizeResolver
- Target.getSizeResolver()
- View 或 Compose 组件的宽高
- DisplayMetrics size 或 LocalWindow containerSize
- PlatformContext.screenSize()
- Precision:
- ImageRequest.Builder.precisionDecider
- Target.getImageOptions().precisionDecider
- ImageRequest.Builder.defaultOptions.precisionDecider
- Sketch.globalImageOptions.precisionDecider
- Precision.LESS_PIXELS
- Scale:
- ImageRequest.Builder.scaleDecider
- Target.getImageOptions().scaleDecider
- ImageRequest.Builder.defaultOptions.scaleDecider
- Sketch.globalImageOptions.scaleDecider
- Scale.CENTER_CROP
Tip
- Target 是 ViewTarget 时优先取 View 的 LayoutParams 宽高,其次延迟到绘制阶段取 View 的测量宽高,如果没有执行到绘制阶段那么请求也不会执行
- 假如组件的宽是固定值(例如 100),高是 wrap 时,Size 将会是 '100x屏幕或容器的高'
- 详细构建规则请参考 ImageRequest.Builder.build() 方法
PlatformContext.screenSize() 方法用于获取屏幕的大小,构建 ImageRequest 时在无法获取 Size 的情况下会使用屏幕大小作为最终的 Size
Important
screenSize() 在非 Js 平台都能获取到准确的屏幕大小,但在 Js 平台会始终返回 Size(1920, 1080)
sizeMultiplier 用于对 size 进行缩放,例如 sizeMultiplier 为 2.0 时,size 为 100x100 时实际 size 为 200x200
这通常用于默认用组件的大小作为 size,但是组件太小,需要放大 size 以提高图片质量,如下:
ImageRequest(context, "https://example.com/image.jpg") {
sizeMultiplier(2.0f)
}
ImageRequest 和 ImageOptions 的 resizeOnDraw 属性用于将 Resize 应用到 Target 的 placeholder, error, result Image 上,在绘制期间改变 Image 的大小
resizeOnDraw 依赖 ResizeOnDrawHelper 实现,ResizeOnDrawHelper 会用 ResizeDrawable 或 ResizePainter 将 placeholder, error, result Image 包一层,对外用 Resize 的 Size 作为宽和高,内部用 Resize 的 Scale 对 Image 进行缩放
resizeOnDraw 搭配 CrossfadeTransition 可实现完美过渡。了解完美过度
Important
- ResizeOnDrawHelper 由 Target 提供,因此如果没有设置 Target,resizeOnDraw 属性也将无效