概述
UIView类通过定义一个在屏幕和界面上的矩形区域来管理这块区域的内容。在运行时,视图对象处理其区域内的任何内容渲染,还处理与该内容的任何相互作用。
进入正题
一、初始化视图对象
// 纯代码初始化执行
public init(frame: CGRect)
// 使用 Interface Builder 构造界面执行这个
public init?(coder aDecoder: NSCoder)
现在开始测试:
先构建一个自定义View: TestInitView
, 并添加两个初始化函数,如下:
// 纯代码走这个
override init(frame: CGRect) {
super.init(frame: frame);
print("执行了 init(frame: CGRect)")
}
// 使用 Interface Builder 构造界面走这个
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder);
print("执行了 init?(coder aDecoder: NSCoder)")
}
1、纯代码构造界面
测试代码如下:
// test view 纯代码初始化
func testViewInit() {
let testView = TestInitView.init(frame: CGRect.init(x: 100, y: 100, width: 100, height: 100));
testView.backgroundColor = #colorLiteral(red: 0.1215686277, green: 0.01176470611, blue: 0.4235294163, alpha: 1);
self.view.addSubview(testView);
}
测试结果:
执行了 init(frame: CGRect)
注意:此方法是由自己调用,来初始化对象的。
2、使用 Interface Builder 构造界面
① 使用storyBoard来构建界面,并拖入一个View,并将此View的Class设置为 TestInitView
,如下:
② 运行程序,结果如下:
执行了 init?(coder aDecoder: NSCoder)
注意:由系统来调用,自己不能调用。
二、配置视图的视觉外观
// 视图的背景颜色
@NSCopying open var backgroundColor: UIColor?
// 视图的alpha值
open var alpha: CGFloat
// 确定视图是否不透明的布尔值(它却决定不了当前UIView是不是不透明),用处在于给绘图系统提供一个性能优化开关。
open var isOpaque: Bool
// 确定视图是否被隐藏的布尔值
open var isHidden: Bool
// 这个属性定义了一个非默认的着色颜色值,其值的设置会影响到以视图为根视图的整个视图层次结构。
@available(iOS 7.0, *)
open var tintColor: UIColor!
// 本视图及父视图的tintColor或tintAdjustmentMode属性改变时自动调用
@available(iOS 7.0, *)
open func tintColorDidChange()
// 一个枚举值,定义了tint color的调整模式。
@available(iOS 7.0, *)
open var tintAdjustmentMode: UIViewTintAdjustmentMode
// 决定子视图是否被限定在当前视图的bounds中
open var clipsToBounds: Bool
// 决定在视图重画之前是否先清理视图以前的内容
open var clearsContextBeforeDrawing: Bool
// 一个通过alpha通道来掩盖一个view的内容的可选view。
@available(iOS 8.0, *)
open var mask: UIView?
// 为此类的实例创建图层的类
open class var layerClass: Swift.AnyClass { get }
// UIView的视图层
open var layer: CALayer { get }
1、alpha && isOpaque && isHidden
测试代码如下:
func testalpha_isOpaque_isHidden() {
// test alpha
let leftAlphaView = self.getNewTestView(index_i: 0, index_j: 0);
leftAlphaView.alpha = 0.0;
let centerAlphaView = self.getNewTestView(index_i: 1, index_j: 0);
centerAlphaView.alpha = 0.5;
let rightAlphaView = self.getNewTestView(index_i: 2, index_j: 0);
rightAlphaView.alpha = 1.0;
// test isHidden
let leftIsHiddenView = self.getNewTestView(index_i: 0, index_j: 1);
leftIsHiddenView.isHidden = true;
let rightIsHiddenView = self.getNewTestView(index_i: 1, index_j: 1);
rightIsHiddenView.isHidden = false;
// test isOpaque
let leftDownOpaqueView = self.getNewTestView(index_i: 0, index_j: 2);
let leftUpOpaqueView = self.getNewTestView(index_i: 0, index_j: 3);
leftUpOpaqueView.alpha = 1.0;
leftUpOpaqueView.isOpaque = true;
leftUpOpaqueView.backgroundColor = #colorLiteral(red: 0.2196078449, green: 0.007843137719, blue: 0.8549019694, alpha: 1);
leftUpOpaqueView.center = CGPoint.init(x: leftDownOpaqueView.center.x, y: leftDownOpaqueView.center.y + 25);
let rightDownOpaqueView = self.getNewTestView(index_i: 1, index_j: 2);
let rightUpOpaqueView = self.getNewTestView(index_i: 1, index_j: 3);
rightUpOpaqueView.alpha = 0.5;
rightUpOpaqueView.isOpaque = false;
rightUpOpaqueView.backgroundColor = #colorLiteral(red: 0.2196078449, green: 0.007843137719, blue: 0.8549019694, alpha: 1)
rightUpOpaqueView.center = CGPoint.init(x: rightDownOpaqueView.center.x, y: rightDownOpaqueView.center.y + 25);
}
func getNewTestView(index_i: NSInteger, index_j: NSInteger) -> UIView {
let testView = UIView.init(frame: CGRect.init(x: 30 + index_i * 80, y: 80 + index_j * 80, width: 50, height: 50));
testView.backgroundColor = #colorLiteral(red: 0.7450980544, green: 0.1568627506, blue: 0.07450980693, alpha: 1);
self.view.addSubview(testView);
return testView;
}
测试结果如下:
注意:当把UIView的alpha属性设成0,或者把isHidden设成true的时候,当前UIView和它所包含的子UIView都会变成不可见,同时也不会再响应event事件。isOpaque,而不是决定View的是否是不透明。即View不透明时,isOpaque需要设置为true,来优化性能,有透明度时,isOpaque需要设置为false,防止不可预测事情发生(我也不知道啥事情,测试显示没啥区别!)。
2、tintColor && tintAdjustmentMode && tintColorDidChange
① 首先测试一下,tintColor的设置:
自定义 TIntColorTestView
:
// test tintColor
func testTintColor() {
self.label.frame = CGRect.init(x: 30, y: 80, width: 250, height: 50);
self.label.text = "这是王隆帅的label";
self.label.textColor = self.tintColor;
self.addSubview(self.label);
let button = UIButton.init(type: .system);
button.frame = CGRect.init(x: 30, y: 140, width: 250, height: 50);
button.addTarget(self, action: #selector(btnClick), for: .touchUpInside)
button.setTitle("这是王隆帅的btn", for: .normal);
self.addSubview(button);
var image = UIImage.init(named: "imageToColor");
image = image?.withRenderingMode(.alwaysTemplate);
let imageView = UIImageView.init(frame: CGRect.init(x: 30, y: 200, width: 250, height: 50));
imageView.image = image;
self.addSubview(imageView);
}
func btnClick() {
self.tintColor = UIColor.init(red: CGFloat(Double(arc4random() % 255) / 255.0), green: CGFloat(Double(arc4random() % 255) / 255.0), blue: CGFloat(Double(arc4random() % 255) / 255.0), alpha: 1.0);
}
override func tintColorDidChange() {
self.label.textColor = self.tintColor;
}
初始化这个View:
func testTintColor() {
let tintColorView = TIntColorTestView.init(frame: self.view.bounds);
self.view.addSubview(tintColorView);
}
运行程序,并不断点击btn,结果如下:
由上可知,tintColor会影响到以视图为根视图的整个视图层次结构。主要是改变系统的某些控件,比如 UIButton
, UISlider
, UIProgressView
, UIStepper
, UIImageView
等等。假如想要更改label的文字颜色,或者某些View的背景颜色等,可以监听 tintColorDidChange
,来做相应更改!
② 再来测试一下 tintAdjustmentMode
@available(iOS 7.0, *)
public enum UIViewTintAdjustmentMode : Int {
// 视图的着色调整模式与父视图一致
case automatic
// 视图的tintColor属性返回UIExtendedSRGBColorSpace 颜色空间的颜色
case normal
// 视图的tintColor属性返回 UIExtendedGrayColorSpace 颜色空间的颜色
case dimmed
}
测试代码,在上面的基础上 加上以下代码:
print("normal ----- \(self.tintAdjustmentMode.rawValue)");
print("normal ----- \(self.tintColor)");
self.tintAdjustmentMode = .dimmed;
print("dimmd ----- \(self.tintAdjustmentMode.rawValue)");
print("dimmd ----- \(self.tintColor)");
button.tintAdjustmentMode = .normal;
imageView.tintAdjustmentMode = .automatic;
测试结果如下:
normal ----- 1
normal ----- Optional(UIExtendedSRGBColorSpace 0 0.478431 1 1)
dimmd ----- 2
dimmd ----- Optional(UIExtendedGrayColorSpace 0.484669 0.8)
由图及打印可知,normal
及 dimmd
,确实对应着 UIExtendedSRGBColorSpace
及 UIExtendedGrayColorSpace
两个颜色空间!并且,imageView设置的 .automatic
是继承了父View的 .dimmed
属性。
想要了解更多关于颜色空间,可以看这篇文章。
3、clipsToBounds
测试代码如下:
// 测试 clipsToBounds
func testClipsToBounds() {
// clipsToBounds false
let clipsView1_down = self.getNewTestView(index_i: 0, index_j: 0);
clipsView1_down.clipsToBounds = false;
let clipsView1_up = self.getNewTestView(index_i: 0, index_j: 1);
clipsView1_up.backgroundColor = #colorLiteral(red: 0.1294117719, green: 0.2156862766, blue: 0.06666667014, alpha: 1);
clipsView1_up.center = CGPoint.init(x: 25, y: 50);
clipsView1_down.addSubview(clipsView1_up);
// clipsToBounds true
let clipsView2_down = self.getNewTestView(index_i: 1, index_j: 0);
clipsView2_down.clipsToBounds = true;
let clipsView2_up = self.getNewTestView(index_i: 1, index_j: 1);
clipsView2_up.backgroundColor = #colorLiteral(red: 0.1294117719, green: 0.2156862766, blue: 0.06666667014, alpha: 1);
clipsView2_up.center = CGPoint.init(x: 25, y: 50);
clipsView2_down.addSubview(clipsView2_up);
}
测试结果:
4、clearsContextBeforeDrawing
见名知意,此属性决定绘制前是否清屏,默认为true。当这个属性被设置为时true,UIKIt会在调用 drawRect:
方法之前,把即将被该方法更新的区域填充为透明的黑色。将这个属性设置为false可以取消相应的填充操作,view中原有内容会保留。
如果将此属性的值设置为false,则我们应该确保在 draw(:)
方法中正确绘制视图的内容。在此前提下,可以提高性能。
5、mask
测试代码如下:
// 测试 mask
func testMask() {
let view1 = UIView.init(frame: CGRect.init(x: 20, y: 80, width: 80, height: 80));
view1.backgroundColor = UIColor.blue;
let maskView1 = UIView.init(frame: view1.bounds);
maskView1.backgroundColor = UIColor.red;
maskView1.alpha = 0.1;
view1.mask = maskView1;
self.view.addSubview(view1);
let view2 = UIView.init(frame: CGRect.init(x: 120, y: 80, width: 80, height: 80));
view2.backgroundColor = UIColor.blue;
let maskView2 = UIView.init(frame: view2.bounds);
maskView2.backgroundColor = UIColor.green;
maskView2.alpha = 0.5;
view2.mask = maskView2;
self.view.addSubview(view2);
let view3 = UIView.init(frame: CGRect.init(x: 220, y: 80, width: 80, height: 80));
view3.backgroundColor = UIColor.blue;
let maskView3 = UIView.init(frame: view3.bounds);
maskView3.backgroundColor = UIColor.brown;
maskView3.alpha = 1.0;
view3.mask = maskView3;
self.view.addSubview(view3);
}
测试结果如下:
由上图可知,mask自带的颜色不会显示,最终效果图怎么显示只跟mask每个point的alpha相关。(本例是全部都是一样的alpha,假如想要部分为透明,可以添加含有alpha通道的图片)
可以这样理解,是将mask的每个point的alpha赋值给View的重叠部分相对应的point,这样view的重叠每个point都有个alpha值了,view重叠部分就可能显示多种透明色。
5、layer && layerClass
测试代码:
// 测试 layer
func testLayer() {
let layer = CALayer.init();
layer.bounds = CGRect.init(x: 0, y: 0, width: 100, height: 100);
layer.position = CGPoint.init(x: 100, y: 200);
layer.contents = UIImage.init(named: "imageToColor")?.cgImage;
layer.cornerRadius = 10.0;
layer.masksToBounds = true;
self.view.layer.addSublayer(layer);
}
测试结果:
总结:UIView和CALayer是相互依赖的关系。UIView依赖于CALayer提供的内容,CALayer依赖UIView提供的容器来显示绘制的内容。归根到底CALayer是这一切的基础,如果没有CALayer,UIView自身也不会存在,UIView是一个特殊的CALayer实现,添加了响应事件的能力。
想要更详细了解两者详细可以查看这两篇文章(第一篇,第二篇),这里就不再赘述了!
三、配置事件相关行为
// 设置视图的可交互性
open var isUserInteractionEnabled: Bool
// 设置是否支持多点触控
open var isMultipleTouchEnabled: Bool
// 设置控件接受事件时的排他性
open var isExclusiveTouch: Bool
1、isUserInteractionEnabled
当一个视图对象的 isUserInteractionEnabled
被置为 false
,则这个视图对象就被从响应者链里移除,它所负责响应的事件全部无效。它的 subviews
事件也会被丢弃。当重新设为 true
时,则事件可以正常的传递给该视图对象。额外的,UIImageView
、UILabel
默认的 isUserInteractionEnabled
是 false
,UIView
的 isUserInteractionEnabled
默认是 true
。
2、isMultipleTouchEnabled
测试代码如下:
// 测试 isMultipleTouchEnabled
var touchNums = 0;
func testIsMultipleTouchEnabled() {
self.view.isMultipleTouchEnabled = true;
}
override func touchesBegan(_ touches: Set, with event: UIEvent?) {
touchNums = touchNums + touches.count;
print(touchNums);
}
override func touchesEnded(_ touches: Set, with event: UIEvent?) {
touchNums = touchNums - touches.count;
print(touchNums);
}
override func touchesCancelled(_ touches: Set, with event: UIEvent?) {
touchNums = touchNums - touches.count;
print(touchNums);
}
分别用十个指头点击屏幕,测试结果如下:
2
4
5
2
0
由结果可知,屏幕最多支持五点触控。
将 isMultipleTouchEnabled
设置为 false
,可得以下结果:
1
0
1
0
即,最多支持一个触摸事件。
3、isExclusiveTouch
测试代码如下:
// 测试 isExclusiveTouch
func testIsExclusiveTouch() {
let btn1 = UIButton.init(frame: CGRect.init(x: 100, y: 100, width: 100, height: 100))
btn1.backgroundColor = UIColor.red;
// btn1.isExclusiveTouch = true;
btn1.addTarget(self, action: #selector(touchClickBtn), for: .touchUpInside);
self.view.addSubview(btn1);
let btn2 = UIButton.init(frame: CGRect.init(x: 220, y: 100, width: 100, height: 100))
btn2.backgroundColor = UIColor.blue;
// btn2.isExclusiveTouch = true;
btn2.addTarget(self, action: #selector(touchClickBtn), for: .touchUpInside);
self.view.addSubview(btn2);
}
func touchClickBtn() {
print("btn 被点击了!!");
}
运行程序,手指先点击红色按钮,摁住不放,另一个手指点击蓝色按钮,然后同时放开,得出下面结果:
btn 被点击了!!
btn 被点击了!!
由此可知,两个按钮同时响应了点击事件。
将代码中注释的代码打开,重新运行程序,并执行上面的操作,得出下面的结果:
btn 被点击了!!
即,设置了View接收事件的排他性为true,则同一时间在两个同级的View之间,只能有一个事件触发!
四、设置位置及大小
// 设置视图在其父视图中的位置及大小
open var frame: CGRect
// 设置视图在父坐标系下的大小
open var bounds: CGRect
// 设置视图在父视图中的位置
open var center: CGPoint
// 通过此属性可以修改对象的平移、缩放比例和旋转角度
open var transform: CGAffineTransform
1、frame && bounds && center
测试代码如下:
// 测试 frame && bounds && center
func testFrame() {
let view = UIView.init(frame: CGRect.init(x: 100, y: 200, width: 50, height: 50));
self.view.addSubview(view);
print(view.frame);
print(view.bounds);
print(view.center);
}
测试结果如下:
(100.0, 200.0, 50.0, 50.0)
(0.0, 0.0, 50.0, 50.0)
(125.0, 225.0)
由结果可知,bounds
属性只是提供了视图对象的大小,并不包含位置!
2、transform
transform
是一个非常重要的属性,它在矩阵变换的层面上改变视图的显示效果,完成旋转、形变、平移等等操作。
偷个懒,这个属性牵涉面较多,可以参看这篇文章。
五、管理视图层次结构
// 父视图
open var superview: UIView? { get }
// 子视图数组
open var subviews: [UIView] { get }
// 该视图所在的窗口视图
open var window: UIWindow? { get }
// 从父视图移除
open func removeFromSuperview()
// 在指定索引处插入某个子视图
open func insertSubview(_ view: UIView, at index: Int)
// 交换两个指定索引的子视图
open func exchangeSubview(at index1: Int, withSubviewAt index2: Int)
// 添加视图到子视图列表的末尾
open func addSubview(_ view: UIView)
// 在指定的子视图之上插入某个子视图
open func insertSubview(_ view: UIView, belowSubview siblingSubview: UIView)
// 在指定的子视图之下插入某个子视图
open func insertSubview(_ view: UIView, aboveSubview siblingSubview: UIView)
// 移动某个子视图到所有子视图的最上方
open func bringSubview(toFront view: UIView)
// 移动某个子视图到所有子视图的最下方
open func sendSubview(toBack view: UIView)
//
open func isDescendant(of view: UIView) -> Bool
测试代码如下:
// 测试 视图的层次结构
func testHierarchicalStructure() {
let view1 = self.createView(tag: 0);
self.view.addSubview(view1);
let view2 = self.createView(tag: 1);
self.view.addSubview(view2);
let view3 = self.createView(tag: 2);
self.view.addSubview(view3);
print("superView:\n" + String(describing: view1.superview));
self.printSubviews(name: "subviews");
let view101 = self.createView(tag: 100);
UIApplication.shared.keyWindow?.addSubview(view101);
print("\nwindow2:\n" + String(describing: view101.window))
view1.removeFromSuperview();
self.printSubviews(name: "removeFromSuperview");
self.view.insertSubview(view1, at: 1);
self.printSubviews(name: "insertSubviewAtIndex");
self.view.exchangeSubview(at: 0, withSubviewAt: 1);
self.printSubviews(name: "exchangeSubview");
let view4 = self.createView(tag: 3);
self.view.addSubview(view4);
self.printSubviews(name: "addSubview");
let view5 = self.createView(tag: 4);
self.view.insertSubview(view5, aboveSubview: view3);
self.printSubviews(name: "insertSubview:aboveSubview");
let view6 = self.createView(tag: 5);
self.view.insertSubview(view6, belowSubview: view3);
self.printSubviews(name: "insertSubview:belowSubview");
self.view.bringSubview(toFront: view2);
self.printSubviews(name: "bringSubview:toFront");
self.view.sendSubview(toBack: view2);
self.printSubviews(name: "sendSubview:Toback");
print("\nview2 && view3 isDescendant: " + String(view2.isDescendant(of: view3)));
print("view2 && self.view isDescendant: " + String(view2.isDescendant(of: self.view)));
print("self.view && view2 isDescendant: " + String(self.view.isDescendant(of: view2)));
print("view2 && view2 isDescendant: " + String(view2.isDescendant(of: view2)));
}
func createView(tag: NSInteger) -> UIView {
let view = UIView.init(frame: CGRect.init(x: 100, y: 100, width: 200, height: 200));
view.tag = tag;
return view;
}
func printSubviews(name: String) {
print("\n\(name):\n" + String(describing: self.view.subviews.map { (view: UIView) -> NSInteger in return view.tag; }));
}
结果如下:
superView:
Optional(>)
subviews:
[0, 1, 2]
window2:
Optional(; layer = >)
removeFromSuperview:
[1, 2]
insertSubviewAtIndex:
[1, 0, 2]
exchangeSubview:
[0, 1, 2]
addSubview:
[0, 1, 2, 3]
insertSubview:aboveSubview:
[0, 1, 2, 4, 3]
insertSubview:belowSubview:
[0, 1, 5, 2, 4, 3]
bringSubview:toFront:
[0, 5, 2, 4, 3, 1]
sendSubview:Toback:
[1, 0, 5, 2, 4, 3]
view2 && view3 isDescendant: false
view2 && self.view isDescendant: true
self.view && view2 isDescendant: false
view2 && view2 isDescendant: true
注意:isDescendant
这个属性在对比两个 View
的时候,前者是后者的同一 View
或子 view
才为 true
。
六、配置自动布局行为
// 控制autoresizingMask模式的开启与关闭
open var autoresizesSubviews: Bool
// 子视图相对于父视图的调整模式
open var autoresizingMask: UIViewAutoresizing
// 视图计算最合适的size(容纳子视图)并返回
open func sizeThatFits(_ size: CGSize) -> CGSize
// 计算合适Size,并更改本视图的size去包含子视图
open func sizeToFit()
// 当一个view的bounds变化的时候用于决定其内容怎么变化(变化模式)
open var contentMode: UIViewContentMode
1、autoresizingMask && autoresizesSubviews
public struct UIViewAutoresizing : OptionSet {
public init(rawValue: UInt)
// 自动调整view与父视图左边距,以保证右边距不变
public static var flexibleLeftMargin: UIViewAutoresizing { get }
// 自动调整view的宽度,保证左边距和右边距不变
public static var flexibleWidth: UIViewAutoresizing { get }
// 自动调整view与父视图右边距,以保证左边距不变
public static var flexibleRightMargin: UIViewAutoresizing { get }
// 自动调整view与父视图上边距,以保证下边距不变
public static var flexibleTopMargin: UIViewAutoresizing { get }
// 自动调整view的高度,以保证上边距和下边距不变
public static var flexibleHeight: UIViewAutoresizing { get }
// 自动调整view与父视图的下边距,以保证上边距不变
public static var flexibleBottomMargin: UIViewAutoresizing { get }
}
结构体的各个属性,如上所述,具体测试代码如下:
var firstView = UIView.init();
func testAutoresizingMask() {
self.firstView.frame = CGRect.init(x: 20, y: 80, width: 200, height: 200);
self.firstView.backgroundColor = UIColor.red;
self.view.addSubview(self.firstView);
let secondView = UIView.init(frame: CGRect.init(x: 10, y: 10, width: 180, height: 20));
secondView.backgroundColor = UIColor.brown;
secondView.autoresizingMask = [.flexibleWidth, .flexibleBottomMargin];
self.firstView.addSubview(secondView);
let thirdView = UIView.init(frame: CGRect.init(x: 10, y: 40, width: 180, height: 20));
thirdView.backgroundColor = UIColor.cyan;
thirdView.autoresizingMask = .flexibleLeftMargin;
self.firstView.addSubview(thirdView);
let fourthView = UIView.init(frame: CGRect.init(x: 10, y: 70, width: 180, height: 20));
fourthView.backgroundColor = UIColor.blue;
fourthView.autoresizingMask = .flexibleRightMargin;
self.firstView.addSubview(fourthView);
let fifthView = UIView.init(frame: CGRect.init(x: 10, y: 110, width: 180, height: 50));
fifthView.backgroundColor = UIColor.yellow;
fifthView.autoresizingMask = [.flexibleTopMargin, .flexibleHeight];
self.firstView.addSubview(fifthView);
let changeBtn = UIButton.init(type: .custom);
changeBtn.setTitle("更改frame", for: .normal);
changeBtn.frame = CGRect.init(x: 20, y: 500, width: 120, height: 40);
changeBtn.backgroundColor = UIColor.green;
changeBtn.addTarget(self, action: #selector(changeAutoresizingMaskFrame), for: .touchUpInside);
self.view.addSubview(changeBtn);
}
func changeAutoresizingMaskFrame() {
let framesArray = [220,250,270,300,320];
let index = Int(arc4random() % 5);
self.firstView.frame = CGRect.init(x: 20, y: 80, width: framesArray[index], height: framesArray[index]);
}
不断点击按钮,得到如下图结果:
由结果可知,API与其描述相符,设置 flexibleRight
则左侧距离保持不变,设置 flexibleTop
则子View距离底部距离保持不变,即关键字(如 left
、right
、top
、bottom
)代表的反方向的相对距离保持不变。
接着上面的测试,添加如下代码:
self.firstView.autoresizesSubviews = false;
重复上面的测试方法,不断点击按钮,得到结果如下图:
由上图可知,之前设置的 autoresizingMask
没有效果了,autoresizesSubviews
就是控制 autoresizingMask
模式的开关,默认是开启的。
2、sizeThatFits && sizeToFit
测试代码如下:
func testSizeFits() {
let sizeLabel = UILabel.init(frame: CGRect.init(x: 20, y: 100, width: 0, height: 0));
sizeLabel.font = UIFont.systemFont(ofSize: 20);
sizeLabel.text = "王隆帅的 王隆帅的博客 王隆帅!!!";
self.view.addSubview(sizeLabel);
let fitSize = sizeLabel.sizeThatFits(CGSize.zero);
print("sizeThatFits ------- \n" + String(describing: fitSize));
print("sizeThatFits 后 Label的尺寸 ------- \n" + String(describing: sizeLabel.frame.size));
sizeLabel.sizeToFit();
print("sizeToFit 后 Label的尺寸 ------- \n" + String(describing: sizeLabel.frame.size));
}
结果如下:
sizeThatFits -------
(333.5, 24.0)
sizeThatFits 后 Label的尺寸 -------
(0.0, 0.0)
sizeToFit 后 Label的尺寸 -------
(333.5, 24.0)
由结果可知 sizeThatFits
方法得到的自适应后的尺寸,但是并没有更改标签的实际大小,而sizeToFit
将自适应得到的尺寸(内部也是调用sizeThatFits
获取自适应尺寸)应用到相应的 label
上,是label的实际尺寸更改为自适应的尺寸。
3、contentMode
public enum UIViewContentMode : Int {
// 改变内容的高宽比例,缩放内容,UIView中完整显示内容,填满UIView
case scaleToFill
// 保持内容的高宽比,缩放内容,完整显示内容,最大化填充UIview,没填充上的区域透明
case scaleAspectFit
// 保持内容高宽比,缩放内容,超出视图的部分内容会被裁减,填充UIView
case scaleAspectFill
// 当View的bounds改变,系统会调用setNeedsDisplay,重新绘制视图
case redraw
// 不缩放,内容在视图中间
case center
// 不缩放,内容在视图头部
case top
// 不缩放,内容在视图底部
case bottom
// 不缩放,内容在视图左侧
case left
// 不缩放,内容在视图右侧
case right
// 不缩放,内容在视图头部及左侧
case topLeft
// 不缩放,内容在视图头部及右侧
case topRight
// 不缩放,内容在视图底部及左侧
case bottomLeft
// 不缩放,内容在视图底部及右侧
case bottomRight
}
测试代码就忽略不计了,具体效果如下图(图片来源是这里):
七、待续...
篇幅所限,因为UIView的内容略多,所以接下来会分篇来整理。