UIPageControl 的 autoresizingMask 属性导致布局异常

今天被反馈了一个 UIPageControl 莫名错位的线上问题, 本应在屏幕底部中间的指示器, 突然跑到了屏幕的右下角, 经过定位, 是 pageControl的宽度由 428 变成了 856 导致的, hook 了 pageControl 的 setFrame: 后, 断点停在了自动布局的堆栈, 系统自动布局计算宽度就是 856, 一番 Google 后最后发现是 autoresizingMask 的问题.

出错现象:

出错原因

UIPageControl 的 autoresizingMask 属性默认是 UIViewAutoresizingFlexibleWidth, 即为与 superView 左右边距保持一致.
出 bug 的原因在于我们将 pageControl 加到 superView 时, 做了一些特殊的操作, 导致此时 superViewframeCGRectZero, 而 pageControl 的宽是 428, 因此此时的规则是

  1. pageControl 左边与 superView一样
  2. pageControl 右边比与 superView大 428
  3. pageControl 宽度是 428, 并且宽度可变

当布局后 superView 宽度设置为正常的 428, 执行以上三条规则后, pageControl 宽度就变成了 856. 即pageControl 左边距与superView一致, 右边距比superView右边距大 428, superView此时宽度是428, 计算得到 pageControl 为 428+428.

autoresizesSubviews && autoresizingMask

UIView.autoresizesSubviews 决定 autoresizingMask 属性是否生效, 默认YES生效.

根据官方文档描述autoresizingMask

When a view’s bounds change, that view automatically resizes its subviews according to each subview’s autoresizing mask.
当视图的边界发生变化时,该视图会根据每个子视图的自动布局属性autoresizingMask调整其子视图的大小。

autoresizingMask 默认值一般是 UIViewAutoresizingNone 具体定义如下

1
2
3
4
5
6
7
8
9
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexibleLeftMargin = 1 << 0,
UIViewAutoresizingFlexibleWidth = 1 << 1,
UIViewAutoresizingFlexibleRightMargin = 1 << 2,
UIViewAutoresizingFlexibleTopMargin = 1 << 3,
UIViewAutoresizingFlexibleHeight = 1 << 4,
UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};

简单解释下具体含义

属性值 含义
UIViewAutoresizingNone (默认值)不进行自动布局
UIViewAutoresizingFlexibleLeftMargin 自动调整与父视图左边距, 保持右边距不变
UIViewAutoresizingFlexibleWidth 自动调整本身的宽度, 保持和父视图的左右边距不变
UIViewAutoresizingFlexibleRightMargin 自动调整与父视图右边距, 保持左边距不变
UIViewAutoresizingFlexibleTopMargin 自动调整与父视图上边距, 保持下边距不变
UIViewAutoresizingFlexibleHeight 自动调整本身的高度, 保持上边距和下边距不变
UIViewAutoresizingFlexibleBottomMargin 自动调整与父视图的下边距, 保持上边距不变

同时这些属性是可以组合的, 比如保持在父视图右下角相对固定位置可以设置为

1
view.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin |UIViewAutoresizingFlexibleTopMargin;

而比较特殊的是,几乎所有的 UIView 的子类autoresizingMask 默认值都是UIViewAutoresizingNone, 除了 UIPageControl 默认值是UIViewAutoresizingFlexibleWidth

-------------本文结束感谢您的阅读-------------

欢迎关注我的其它发布渠道