Kingfisher 源码阅读笔记(6)——ImageModifier

1,208 阅读2分钟

这是我参与更文挑战的第16天,活动详情查看: 更文挑战

本文为在阅读 Kingfisher 源码时的收货。

Kingfisher 源码阅读笔记(1)

Kingfisher 源码阅读笔记(2)

Kingfisher 源码阅读笔记(3)

Kingfisher 源码阅读笔记(4)

Kingfisher 源码阅读笔记(5)

Kingfisher 中有一个协议 ImageModifier,用于在图片缓存序列化之后、实际使用之前修改图像的属性。此修改后的图片仅用于渲染目的,而不会影响到序列化、缓存的过程。

作者提供了三个实现 ImageModifier 协议的结构体 RenderingModeImageModifierFlipsForRightToLeftLayoutDirectionImageModifierAlignmentRectInsetsImageModifier。下面分别介绍一下各自的使用场景。

RenderingModeImageModifier

用于修改 UIImage 的 renderingMode 属性,定义如下:

 public enum RenderingMode : Int {
    case automatic = 0 // Use the default rendering mode for the context where the image is used
    case alwaysOriginal = 1 // Always draw the original image, without treating it as a template
    case alwaysTemplate = 2 // Always draw the image as a template image, ignoring its color information
}
  • automatic:根据当前所处的上下文来决定是渲染图片的原始状态,或是当做模板来渲染。例如 UINavigationBar、UITabBar、UIToolBar、UISegmentedControl 等控件,会自动把其上面的图片(foreground images)当做模板来渲染;而 UIImageView、UIWebView 则会渲染图片的原始状态。
  • alwaysOriginal:使用原始状态渲染。
  • alwaysTemplate:当做模板来渲染。

模板(template)就是忽略掉了图片的所有不透明的颜色信息,取而代之的是它所在的控件的 tintColor。创建 UIImage 时, 默认的 renderingMode.automatic。所以在设置 UINavigationBar 的图片时,图片会显示为 tintColor 的纯色图片。

所以,在 UINavigationBar、UITabBar 这些具有上下文的控件上加载网络图片时,可以使用 RenderingModeImageModifier 来修改图片。

FlipsForRightToLeftLayoutDirectionImageModifier

用于在使用 UIImage 之前调用 imageFlippedForRightToLeftLayoutDirection()。当 UIImage 处于从右到左的布局(right-to-left layout)时,会返回一个将当前图片水平翻转后的新 UIImage。

在处理国际化,特别是要考虑从右到左阅读的国家时,可以使用 FlipsForRightToLeftLayoutDirectionImageModifier 来处理图片。

AlignmentRectInsetsImageModifier

用于在使用 UIImage 之前调用 withAlignmentRectInsets(_:)

如果 UIImageView 要显示的图片包含阴影、徽章等装饰元素,在给 UIImageView 添加约束时,有两种处理方式:

  1. 设置 UIImageView 为整个图片的大小;
  2. 忽略装饰元素,根据核心区域约束 UIImageView 的大小。此时可以通过修改 UIImage 的 alignmentRect,调整对齐矩形,插入内边距来达到目的。

如果是UIView,则可以通过重写UIView的方法alignmentRectInsets,调整对齐矩形。

alignmentRect 可视化

在 Scheme 中的 Arguments 中添加 -UIViewShowAlignmentRects YES 可以可视化 alignmentRect。

image.png

let image = UIImage(named: "HOT")
        
leftImageView.image = image?.withAlignmentRectInsets(UIEdgeInsets(top: 10, left: 0, bottom: 0, right: 10))

rightImageView.image = image

HOT 图片为:

HOT@3x.png

运行时的效果

image.png

参考

自动布局 Auto Layout (原理篇) 【iOS Tip】UIImage的renderingMode