概述
UIView類通過(guò)定義一個(gè)在屏幕和界面上的矩形區(qū)域來(lái)管理這塊區(qū)域的內(nèi)容。在運(yùn)行時(shí),視圖對(duì)象處理其區(qū)域內(nèi)的任何內(nèi)容渲染,還處理與該內(nèi)容的任何相互作用。
進(jìn)入正題
一、初始化視圖對(duì)象
// 純代碼初始化執(zhí)行
public init(frame: CGRect)
// 使用 Interface Builder 構(gòu)造界面執(zhí)行這個(gè)
public init?(coder aDecoder: NSCoder)
現(xiàn)在開始測(cè)試:
先構(gòu)建一個(gè)自定義View: TestInitView
, 并添加兩個(gè)初始化函數(shù),如下:
// 純代碼走這個(gè)
override init(frame: CGRect) {
super.init(frame: frame);
print("執(zhí)行了 init(frame: CGRect)")
}
// 使用 Interface Builder 構(gòu)造界面走這個(gè)
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder);
print("執(zhí)行了 init?(coder aDecoder: NSCoder)")
}
1、純代碼構(gòu)造界面
測(cè)試代碼如下:
// 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);
}
測(cè)試結(jié)果:
執(zhí)行了 init(frame: CGRect)
注意:此方法是由自己調(diào)用,來(lái)初始化對(duì)象的。
2、使用 Interface Builder 構(gòu)造界面
① 使用storyBoard來(lái)構(gòu)建界面,并拖入一個(gè)View,并將此View的Class設(shè)置為 TestInitView
,如下:
② 運(yùn)行程序,結(jié)果如下:
執(zhí)行了 init?(coder aDecoder: NSCoder)
注意:由系統(tǒng)來(lái)調(diào)用,自己不能調(diào)用。
二、配置視圖的視覺外觀
// 視圖的背景顏色
@NSCopying open var backgroundColor: UIColor?
// 視圖的alpha值
open var alpha: CGFloat
// 確定視圖是否不透明的布爾值(它卻決定不了當(dāng)前UIView是不是不透明),用處在于給繪圖系統(tǒng)提供一個(gè)性能優(yōu)化開關(guān)。
open var isOpaque: Bool
// 確定視圖是否被隱藏的布爾值
open var isHidden: Bool
// 這個(gè)屬性定義了一個(gè)非默認(rèn)的著色顏色值,其值的設(shè)置會(huì)影響到以視圖為根視圖的整個(gè)視圖層次結(jié)構(gòu)。
@available(iOS 7.0, *)
open var tintColor: UIColor!
// 本視圖及父視圖的tintColor或tintAdjustmentMode屬性改變時(shí)自動(dòng)調(diào)用
@available(iOS 7.0, *)
open func tintColorDidChange()
// 一個(gè)枚舉值,定義了tint color的調(diào)整模式。
@available(iOS 7.0, *)
open var tintAdjustmentMode: UIViewTintAdjustmentMode
// 決定子視圖是否被限定在當(dāng)前視圖的bounds中
open var clipsToBounds: Bool
// 決定在視圖重畫之前是否先清理視圖以前的內(nèi)容
open var clearsContextBeforeDrawing: Bool
// 一個(gè)通過(guò)alpha通道來(lái)掩蓋一個(gè)view的內(nèi)容的可選view。
@available(iOS 8.0, *)
open var mask: UIView?
// 為此類的實(shí)例創(chuàng)建圖層的類
open class var layerClass: Swift.AnyClass { get }
// UIView的視圖層
open var layer: CALayer { get }
1、alpha && isOpaque && isHidden
測(cè)試代碼如下:
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;
}
測(cè)試結(jié)果如下:
注意:當(dāng)把UIView的alpha屬性設(shè)成0,或者把isHidden設(shè)成true的時(shí)候,當(dāng)前UIView和它所包含的子UIView都會(huì)變成不可見,同時(shí)也不會(huì)再響應(yīng)event事件。isOpaque,而不是決定View的是否是不透明。即View不透明時(shí),isOpaque需要設(shè)置為true,來(lái)優(yōu)化性能,有透明度時(shí),isOpaque需要設(shè)置為false,防止不可預(yù)測(cè)事情發(fā)生(我也不知道啥事情,測(cè)試顯示沒(méi)啥區(qū)別!)。
2、tintColor && tintAdjustmentMode && tintColorDidChange
① 首先測(cè)試一下,tintColor的設(shè)置:
自定義 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;
}
初始化這個(gè)View:
func testTintColor() {
let tintColorView = TIntColorTestView.init(frame: self.view.bounds);
self.view.addSubview(tintColorView);
}
運(yùn)行程序,并不斷點(diǎn)擊btn,結(jié)果如下:
由上可知,tintColor會(huì)影響到以視圖為根視圖的整個(gè)視圖層次結(jié)構(gòu)。主要是改變系統(tǒng)的某些控件,比如 UIButton
, UISlider
, UIProgressView
, UIStepper
, UIImageView
等等。假如想要更改label的文字顏色,或者某些View的背景顏色等,可以監(jiān)聽 tintColorDidChange
,來(lái)做相應(yīng)更改!
② 再來(lái)測(cè)試一下 tintAdjustmentMode
@available(iOS 7.0, *)
public enum UIViewTintAdjustmentMode : Int {
// 視圖的著色調(diào)整模式與父視圖一致
case automatic
// 視圖的tintColor屬性返回UIExtendedSRGBColorSpace 顏色空間的顏色
case normal
// 視圖的tintColor屬性返回 UIExtendedGrayColorSpace 顏色空間的顏色
case dimmed
}
測(cè)試代碼,在上面的基礎(chǔ)上 加上以下代碼:
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;
測(cè)試結(jié)果如下:
normal ----- 1
normal ----- Optional(UIExtendedSRGBColorSpace 0 0.478431 1 1)
dimmd ----- 2
dimmd ----- Optional(UIExtendedGrayColorSpace 0.484669 0.8)
由圖及打印可知,normal
及 dimmd
,確實(shí)對(duì)應(yīng)著 UIExtendedSRGBColorSpace
及 UIExtendedGrayColorSpace
兩個(gè)顏色空間!并且,imageView設(shè)置的 .automatic
是繼承了父View的 .dimmed
屬性。
3、clipsToBounds
測(cè)試代碼如下:
// 測(cè)試 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);
}
測(cè)試結(jié)果:
4、clearsContextBeforeDrawing
見名知意,此屬性決定繪制前是否清屏,默認(rèn)為true。當(dāng)這個(gè)屬性被設(shè)置為時(shí)true,UIKIt會(huì)在調(diào)用 drawRect:
方法之前,把即將被該方法更新的區(qū)域填充為透明的黑色。將這個(gè)屬性設(shè)置為false可以取消相應(yīng)的填充操作,view中原有內(nèi)容會(huì)保留。
如果將此屬性的值設(shè)置為false,則我們應(yīng)該確保在 draw(:)
方法中正確繪制視圖的內(nèi)容。在此前提下,可以提高性能。
5、mask
測(cè)試代碼如下:
// 測(cè)試 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);
}
測(cè)試結(jié)果如下:
由上圖可知,mask自帶的顏色不會(huì)顯示,最終效果圖怎么顯示只跟mask每個(gè)point的alpha相關(guān)。(本例是全部都是一樣的alpha,假如想要部分為透明,可以添加含有alpha通道的圖片)
可以這樣理解,是將mask的每個(gè)point的alpha賦值給View的重疊部分相對(duì)應(yīng)的point,這樣view的重疊每個(gè)point都有個(gè)alpha值了,view重疊部分就可能顯示多種透明色。
5、layer && layerClass
測(cè)試代碼:
// 測(cè)試 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);
}
測(cè)試結(jié)果:
總結(jié):UIView和CALayer是相互依賴的關(guān)系。UIView依賴于CALayer提供的內(nèi)容,CALayer依賴UIView提供的容器來(lái)顯示繪制的內(nèi)容。歸根到底CALayer是這一切的基礎(chǔ),如果沒(méi)有CALayer,UIView自身也不會(huì)存在,UIView是一個(gè)特殊的CALayer實(shí)現(xiàn),添加了響應(yīng)事件的能力。
想要更詳細(xì)了解兩者詳細(xì)可以查看這兩篇文章(第一篇,第二篇),這里就不再贅述了!
三、配置事件相關(guān)行為
// 設(shè)置視圖的可交互性
open var isUserInteractionEnabled: Bool
// 設(shè)置是否支持多點(diǎn)觸控
open var isMultipleTouchEnabled: Bool
// 設(shè)置控件接受事件時(shí)的排他性
open var isExclusiveTouch: Bool
1、isUserInteractionEnabled
當(dāng)一個(gè)視圖對(duì)象的 isUserInteractionEnabled
被置為 false
,則這個(gè)視圖對(duì)象就被從響應(yīng)者鏈里移除,它所負(fù)責(zé)響應(yīng)的事件全部無(wú)效。它的 subviews
事件也會(huì)被丟棄。當(dāng)重新設(shè)為 true
時(shí),則事件可以正常的傳遞給該視圖對(duì)象。額外的,UIImageView
、UILabel
默認(rèn)的 isUserInteractionEnabled
是 false
,UIView
的 isUserInteractionEnabled
默認(rèn)是 true
。
2、isMultipleTouchEnabled
測(cè)試代碼如下:
// 測(cè)試 isMultipleTouchEnabled
var touchNums = 0;
func testIsMultipleTouchEnabled() {
self.view.isMultipleTouchEnabled = true;
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
touchNums = touchNums + touches.count;
print(touchNums);
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
touchNums = touchNums - touches.count;
print(touchNums);
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
touchNums = touchNums - touches.count;
print(touchNums);
}
分別用十個(gè)指頭點(diǎn)擊屏幕,測(cè)試結(jié)果如下:
2
4
5
2
0
由結(jié)果可知,屏幕最多支持五點(diǎn)觸控。
將 isMultipleTouchEnabled
設(shè)置為 false
,可得以下結(jié)果:
1
0
1
0
即,最多支持一個(gè)觸摸事件。
3、isExclusiveTouch
測(cè)試代碼如下:
// 測(cè)試 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 被點(diǎn)擊了!!");
}
運(yùn)行程序,手指先點(diǎn)擊紅色按鈕,摁住不放,另一個(gè)手指點(diǎn)擊藍(lán)色按鈕,然后同時(shí)放開,得出下面結(jié)果:
btn 被點(diǎn)擊了!!
btn 被點(diǎn)擊了!!
由此可知,兩個(gè)按鈕同時(shí)響應(yīng)了點(diǎn)擊事件。
將代碼中注釋的代碼打開,重新運(yùn)行程序,并執(zhí)行上面的操作,得出下面的結(jié)果:
btn 被點(diǎn)擊了!!
即,設(shè)置了View接收事件的排他性為true,則同一時(shí)間在兩個(gè)同級(jí)的View之間,只能有一個(gè)事件觸發(fā)!
四、設(shè)置位置及大小
// 設(shè)置視圖在其父視圖中的位置及大小
open var frame: CGRect
// 設(shè)置視圖在父坐標(biāo)系下的大小
open var bounds: CGRect
// 設(shè)置視圖在父視圖中的位置
open var center: CGPoint
// 通過(guò)此屬性可以修改對(duì)象的平移、縮放比例和旋轉(zhuǎn)角度
open var transform: CGAffineTransform
1、frame && bounds && center
測(cè)試代碼如下:
// 測(cè)試 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);
}
測(cè)試結(jié)果如下:
(100.0, 200.0, 50.0, 50.0)
(0.0, 0.0, 50.0, 50.0)
(125.0, 225.0)
由結(jié)果可知,bounds
屬性只是提供了視圖對(duì)象的大小,并不包含位置!
2、transform
transform
是一個(gè)非常重要的屬性,它在矩陣變換的層面上改變視圖的顯示效果,完成旋轉(zhuǎn)、形變、平移等等操作。
偷個(gè)懶,這個(gè)屬性牽涉面較多,可以參看這篇文章。
五、管理視圖層次結(jié)構(gòu)
// 父視圖
open var superview: UIView? { get }
// 子視圖數(shù)組
open var subviews: [UIView] { get }
// 該視圖所在的窗口視圖
open var window: UIWindow? { get }
// 從父視圖移除
open func removeFromSuperview()
// 在指定索引處插入某個(gè)子視圖
open func insertSubview(_ view: UIView, at index: Int)
// 交換兩個(gè)指定索引的子視圖
open func exchangeSubview(at index1: Int, withSubviewAt index2: Int)
// 添加視圖到子視圖列表的末尾
open func addSubview(_ view: UIView)
// 在指定的子視圖之上插入某個(gè)子視圖
open func insertSubview(_ view: UIView, belowSubview siblingSubview: UIView)
// 在指定的子視圖之下插入某個(gè)子視圖
open func insertSubview(_ view: UIView, aboveSubview siblingSubview: UIView)
// 移動(dòng)某個(gè)子視圖到所有子視圖的最上方
open func bringSubview(toFront view: UIView)
// 移動(dòng)某個(gè)子視圖到所有子視圖的最下方
open func sendSubview(toBack view: UIView)
//
open func isDescendant(of view: UIView) -> Bool
測(cè)試代碼如下:
// 測(cè)試 視圖的層次結(jié)構(gòu)
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; }));
}
結(jié)果如下:
superView:
Optional(<UIView: 0x7ffe63104190; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x610000029fa0>>)
subviews:
[0, 1, 2]
window2:
Optional(<UIWindow: 0x7ffe5f707510; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x618000050da0>; layer = <UIWindowLayer: 0x61800002fbc0>>)
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
這個(gè)屬性在對(duì)比兩個(gè) View
的時(shí)候,前者是后者的同一 View
或子 view
才為 true
。
六、配置自動(dòng)布局行為
// 控制autoresizingMask模式的開啟與關(guān)閉
open var autoresizesSubviews: Bool
// 子視圖相對(duì)于父視圖的調(diào)整模式
open var autoresizingMask: UIViewAutoresizing
// 視圖計(jì)算最合適的size(容納子視圖)并返回
open func sizeThatFits(_ size: CGSize) -> CGSize
// 計(jì)算合適Size,并更改本視圖的size去包含子視圖
open func sizeToFit()
// 當(dāng)一個(gè)view的bounds變化的時(shí)候用于決定其內(nèi)容怎么變化(變化模式)
open var contentMode: UIViewContentMode
1、autoresizingMask && autoresizesSubviews
public struct UIViewAutoresizing : OptionSet {
public init(rawValue: UInt)
// 自動(dòng)調(diào)整view與父視圖左邊距,以保證右邊距不變
public static var flexibleLeftMargin: UIViewAutoresizing { get }
// 自動(dòng)調(diào)整view的寬度,保證左邊距和右邊距不變
public static var flexibleWidth: UIViewAutoresizing { get }
// 自動(dòng)調(diào)整view與父視圖右邊距,以保證左邊距不變
public static var flexibleRightMargin: UIViewAutoresizing { get }
// 自動(dòng)調(diào)整view與父視圖上邊距,以保證下邊距不變
public static var flexibleTopMargin: UIViewAutoresizing { get }
// 自動(dòng)調(diào)整view的高度,以保證上邊距和下邊距不變
public static var flexibleHeight: UIViewAutoresizing { get }
// 自動(dòng)調(diào)整view與父視圖的下邊距,以保證上邊距不變
public static var flexibleBottomMargin: UIViewAutoresizing { get }
}
結(jié)構(gòu)體的各個(gè)屬性,如上所述,具體測(cè)試代碼如下:
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]);
}
不斷點(diǎn)擊按鈕,得到如下圖結(jié)果:
由結(jié)果可知,API與其描述相符,設(shè)置 flexibleRight
則左側(cè)距離保持不變,設(shè)置 flexibleTop
則子View距離底部距離保持不變,即關(guān)鍵字(如 left
、right
、top
、bottom
)代表的反方向的相對(duì)距離保持不變。
接著上面的測(cè)試,添加如下代碼:
self.firstView.autoresizesSubviews = false;
重復(fù)上面的測(cè)試方法,不斷點(diǎn)擊按鈕,得到結(jié)果如下圖:
由上圖可知,之前設(shè)置的 autoresizingMask
沒(méi)有效果了,autoresizesSubviews
就是控制 autoresizingMask
模式的開關(guān),默認(rèn)是開啟的。
2、sizeThatFits && sizeToFit
測(cè)試代碼如下:
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 = "王隆帥的簡(jiǎn)書 王隆帥的博客 王隆帥!!!";
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));
}
結(jié)果如下:
sizeThatFits -------
(333.5, 24.0)
sizeThatFits 后 Label的尺寸 -------
(0.0, 0.0)
sizeToFit 后 Label的尺寸 -------
(333.5, 24.0)
由結(jié)果可知 sizeThatFits
方法得到的自適應(yīng)后的尺寸,但是并沒(méi)有更改標(biāo)簽的實(shí)際大小,而sizeToFit
將自適應(yīng)得到的尺寸(內(nèi)部也是調(diào)用sizeThatFits
獲取自適應(yīng)尺寸)應(yīng)用到相應(yīng)的 label
上,是label的實(shí)際尺寸更改為自適應(yīng)的尺寸。
3、contentMode
public enum UIViewContentMode : Int {
// 改變內(nèi)容的高寬比例,縮放內(nèi)容,UIView中完整顯示內(nèi)容,填滿UIView
case scaleToFill
// 保持內(nèi)容的高寬比,縮放內(nèi)容,完整顯示內(nèi)容,最大化填充UIview,沒(méi)填充上的區(qū)域透明
case scaleAspectFit
// 保持內(nèi)容高寬比,縮放內(nèi)容,超出視圖的部分內(nèi)容會(huì)被裁減,填充UIView
case scaleAspectFill
// 當(dāng)View的bounds改變,系統(tǒng)會(huì)調(diào)用setNeedsDisplay,重新繪制視圖
case redraw
// 不縮放,內(nèi)容在視圖中間
case center
// 不縮放,內(nèi)容在視圖頭部
case top
// 不縮放,內(nèi)容在視圖底部
case bottom
// 不縮放,內(nèi)容在視圖左側(cè)
case left
// 不縮放,內(nèi)容在視圖右側(cè)
case right
// 不縮放,內(nèi)容在視圖頭部及左側(cè)
case topLeft
// 不縮放,內(nèi)容在視圖頭部及右側(cè)
case topRight
// 不縮放,內(nèi)容在視圖底部及左側(cè)
case bottomLeft
// 不縮放,內(nèi)容在視圖底部及右側(cè)
case bottomRight
}
測(cè)試代碼就忽略不計(jì)了,具體效果如下圖(圖片來(lái)源是這里):
七、待續(xù)...
篇幅所限,因?yàn)閁IView的內(nèi)容略多,所以接下來(lái)會(huì)分篇來(lái)整理。