iOS UIView的學習筆記

UIView

UIView爲屏幕上的矩形區域管理內容的對象。視圖是應用程序用戶界面的基本構建塊,UIView類定義了全部視圖通用的行爲。視圖對象呈現其邊界矩形內的內容,並處理與該內容的任何交互。ios

UIView類是一個具體的類,您能夠實例化它並使用它來顯示固定的背景色。您還能夠將其子類化以繪製更復雜的內容。要顯示應用程序中常見的標籤、圖像、按鈕和其餘界面元素,請使用UIKit框架提供的視圖子類,而不要試圖定義本身的視圖子類。編程

由於視圖對象是應用程序與用戶交互的主要方式,因此它們有許多職責。如下是一些:數組

  1. 繪圖和動畫
  • 視圖使用UIKit或核心圖形在其矩形區域中繪製內容。
  • 某些視圖屬性能夠設置爲新值的動畫。
  1. 佈局和子視圖管理
  • 視圖能夠包含零個或多個子視圖。
  • 視圖能夠調整其子視圖的大小和位置。
  • 使用自動佈局來定義視圖調整大小和從新定位的規則,以響應視圖層次結構中的更改。

3.事件處理緩存

  • 視圖是UIResponder的子類,能夠響應觸摸和其它類型的事件。
  • 視圖能夠安裝手勢識別器來處理常見的手勢。
  • 視圖能夠嵌套在其餘視圖中以建立視圖層次結構,這爲組織相關內容提供了一種方便的方法。嵌套視圖在嵌套的子視圖(稱爲子視圖)和父視圖(稱爲父視圖)之間建立父子關係。父視圖能夠包含任意數量的子視圖,但每一個子視圖只有一個父視圖。默認狀況下,當子視圖的可見區域超出其父視圖的範圍時,不會發生子視圖內容的裁剪。使用clipsToBounds屬性更改該行爲。
  • 每一個視圖的幾何圖形由其框架和邊界屬性定義。frame屬性在其父視圖的座標系統中定義視圖的原點和維度。bounds屬性定義了視圖看到的內部尺寸,而且幾乎只在定製繪圖代碼中使用。center屬性提供了一種方便的方法來從新定位視圖,而無需直接更改其框架或邊界屬性。

UIView經常使用函數

- (instancetype)initWithFrame:(CGRect)frame NS_DESIGNATED_INITIALIZER;markdown

函數描述 : 使用指定的框架矩形初始化並返回新分配的視圖對象。新視圖對象必須插入到窗口的視圖層次結構中才能使用。若是以編程方式建立視圖對象,則此方法是UIView類的指定初始值設定項。子類能夠重寫此方法以執行任何自定義初始化,但必須在其實現開始時調用super。框架

若是使用Interface Builder設計接口,則在隨後從nib文件加載視圖對象時不調用此方法。nib文件中的對象被從新構造,而後使用它們的initWithCoder:方法進行初始化,該方法修改視圖的屬性以匹配存儲在nib文件中的屬性。ide

參數 :函數

frame : 視圖的邊框矩形,以點爲單位。框架的原點相對於要在其中添加它的超視圖。此方法使用框架矩形相應地設置中心和邊界屬性。佈局

返回值 : 初始化的視圖對象。性能

- (instancetype)initWithFrame:(CGRect)frame NS_DESIGNATED_INITIALIZER;
複製代碼

UIView(UIViewGeometry) - 視圖幾何圖形

經常使用屬性

@property(nonatomic) CGRect frame;

屬性描述 : 框架矩形,用於描述視圖在其父視圖座標系中的位置和大小。在佈局操做期間使用此矩形可設置視圖的大小和位置。設置此屬性會更改center屬性指定的點,並相應地更改邊界矩形中的大小。frame的座標老是以點表示。對該屬性的更改能夠被動畫化。

若是transform屬性不是identity轉換,則該屬性的值未定義,所以應該忽略。改變frame會自動從新顯示視圖,而無需調用它的drawRect:方法。若是你想讓UIKit在frame改變時調用drawRect:方法,將contentMode屬性設置爲UIViewContentModeRedraw。可是,若是transform屬性包含非標識轉換,那麼frame屬性的值是未定義的,不該該被修改。在這種狀況下,使用center屬性從新定位視圖,並使用bounds屬性調整大小。

@property(nonatomic) CGRect            frame;
複製代碼

@property(nonatomic) CGRect bounds;

函數描述 : 邊界矩形,它在本身的座標系統中描述視圖的位置和大小。默認邊界原點爲(0,0),大小與frame屬性中矩形的大小相同。更改此矩形的大小部分會使視圖相對於其中心點增大或縮小。更改大小還會更改frame屬性中矩形的大小以進行匹配。bounds的座標始終以點指定。對該屬性的更改能夠被動畫化。

改變bounds會自動從新顯示視圖,而無需調用它的drawRect:方法。若是你想讓UIKit調用drawRect:方法,將contentMode屬性設置爲UIViewContentModeRedraw。

@property(nonatomic) CGRect            bounds;  
複製代碼

@property(nonatomic) CGPoint center;

函數描述 : 視圖frame的中心點。中心點在其父視圖的座標系中以點指定。設置此屬性將相應地更新frame屬性中矩形的原點。若是要更改視圖的位置,請使用此屬性,而不是frame屬性。中心點始終有效,即便在將縮放或旋轉因子應用於視圖的變換時也是如此。對此屬性的更改能夠設置動畫。

@property(nonatomic) CGPoint           center;
複製代碼

@property(nonatomic) CGAffineTransform transform;

屬性描述 : 指定應用於視圖的相對於其邊界中心的轉換。使用這個屬性在父視圖的座標系統內縮放或旋轉視圖的frame。(要改變視圖的位置,請修改center屬性。)此屬性的默認值是CGAffineTransformIdentity。對該屬性的更改能夠被動畫化。

相對於視圖的錨點發生轉換。默認狀況下,定位點等於frame的中心點。要更改錨點,請修改視圖的底層CALayer對象的錨點屬性。

在ios8.0及之後版本中,transform屬性不會影響自動佈局。自動佈局計算一個視圖的對齊矩形基於它的未轉換的框架。

當此屬性的值不是identity轉換時,frame屬性中的值是未定義的,應該忽略。

@property(nonatomic) CGAffineTransform transform;
複製代碼

@property(nonatomic) CGFloat contentScaleFactor API_AVAILABLE(ios(4.0));

屬性描述 :應用於視圖的比例因子。比例因子決定如何將視圖中的內容從邏輯座標空間(以點度量)映射到設備座標空間(以像素度量)。這個值一般是1.0或2.0。較高的比例因子表示視圖中的每一個點都由底層的多個像素表示。例如,若是比例因子爲2.0,視圖幀大小爲50 x 50點,則用於顯示該內容的位圖的大小爲100 x 100像素。

此屬性的默認值是與當前顯示視圖的屏幕相關聯的比例因子。若是自定義視圖實現了一個自定義的drawRect:方法而且與一個窗口相關聯,或者若是使用GLKView類來繪製OpenGL ES內容,你的視圖以屏幕的全分辨率繪製。對於系統視圖,即便在高分辨率屏幕上,這個屬性的值也多是1.0。

一般,不須要修改此屬性中的值。可是,若是你的應用程序使用OpenGL ES繪圖,你可能想要改變比例因子以犧牲圖像質量來換取渲染性能。

@property(nonatomic) CGFloat           contentScaleFactor API_AVAILABLE(ios(4.0));
複製代碼

@property(nonatomic,getter=isMultipleTouchEnabled) BOOL multipleTouchEnabled API_UNAVAILABLE(tvOS);

屬性描述 : 一個布爾值,指示視圖一次是否接收到多個觸摸。當設置爲YES時,視圖會接收與多點觸摸序列相關的全部觸摸,並在視圖的邊界內開始。當設置爲NO時,視圖只接收在視圖邊界內開始的多點觸摸序列中的第一個觸摸事件。此屬性的默認值爲NO。

此屬性不影響附加到視圖的手勢識別器。手勢識別器接收視圖中發生的全部觸摸。

當此屬性爲NO時,同一窗口中的其餘視圖仍然能夠接收觸摸事件。若是但願該視圖專門處理多點觸摸事件,請將此屬性和exclusiveTouch屬性的值設置爲YES。這個屬性不會阻止視圖被要求處理多個觸摸。例如,兩個子視圖可能都將它們的觸摸轉發到一個共同的父視圖,例如一個窗口或一個視圖控制器的根視圖。這個屬性決定有多少最初針對視圖的觸摸被傳遞到那個視圖。

@property(nonatomic,getter=isMultipleTouchEnabled) BOOL multipleTouchEnabled API_UNAVAILABLE(tvOS);
複製代碼

@property(nonatomic,getter=isExclusiveTouch) BOOL exclusiveTouch API_UNAVAILABLE(tvOS);

屬性描述 : 一個布爾值,指示接收器是否以獨佔方式處理觸摸事件。將此屬性設置爲YES會致使接收器阻止將觸摸事件傳遞到同一窗口中的其餘視圖。此屬性的默認值爲NO。

@property(nonatomic,getter=isExclusiveTouch) BOOL       exclusiveTouch API_UNAVAILABLE(tvOS); 
複製代碼

@property(nonatomic) BOOL autoresizesSubviews;

屬性描述 : 一個布爾值,用於肯定接收器在其邊界更改時是否自動調整其子視圖的大小。設置爲YES時,接收器在其邊界更改時調整其子視圖的大小。默認值爲YES。

@property(nonatomic) BOOL               autoresizesSubviews;
複製代碼

@property(nonatomic) UIViewAutoresizing autoresizingMask;

屬性描述 :一個整數位掩碼,用於肯定接收器在其父視圖的邊界更改時如何調整自身大小。當視圖的邊界更改時,該視圖會根據每一個子視圖的自動調整大小掩碼自動調整其子視圖的大小。經過使用C位或運算符組合UIViewAutoresizing中描述的常量,能夠指定此掩碼的值。經過組合這些常量,能夠指定視圖的哪些維度應相對於父視圖增大或縮小。此屬性的默認值爲UIViewAutoresizingNone,這表示不該調整視圖的大小。

當沿同一軸設置多個選項時,默認行爲是在柔性部分之間按比例分佈大小差。與其餘柔性部分相比,柔性部分越大,增加的可能性就越大。例如,假設此屬性包括UIViewAutoresizingFlexibleWidth和UIViewAutoresizingFlexibleRightMargin常量,但不包括UIViewAutoresizingFlexibleLeftMargin常量,從而指示視圖左邊距的寬度是固定的,但視圖的寬度和右邊距可能會更改。所以,當視圖寬度和視圖右側的間隙都增大時,視圖將錨定在其父視圖的左側。

若是自動調整大小的行爲不提供視圖所需的精確佈局,則可使用自定義容器視圖並重寫其layout subviews方法以更精確地定位子視圖。

@property(nonatomic) UIViewAutoresizing autoresizingMask;
複製代碼

UIViewAutoresizing的枚舉值 :

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
};
複製代碼

@property(nullable, nonatomic,copy) NSArray<__kindof UIGestureRecognizer *> *gestureRecognizers API_AVAILABLE(ios(3.2));

屬性描述:當前附加到視圖的手勢識別器對象。每一個對象都是抽象基類UIGestureRecognitizer的子類的實例。此屬性的默認值爲零。若是添加手勢識別器,而後將其刪除,則該屬性的值爲空數組。

@property(nullable, nonatomic,copy) NSArray<__kindof UIGestureRecognizer *> *gestureRecognizers API_AVAILABLE(ios(3.2));
複製代碼
經常使用函數

- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;

函數描述 : 返回視圖層次結構中包含指定點的接收者(包括它本身)的最遠子代。這個方法經過調用每一個子視圖的pointInside:withEvent:方法來遍歷視圖層次結構,以肯定哪一個子視圖應該接收一個觸摸事件。若是pointInside:withEvent:返回YES,那麼子視圖的層次結構將被遍歷,直到發現包含指定點的最前面的視圖爲止。若是視圖不包含該點,則忽略其視圖層次結構的分支。不多須要本身調用這個方法,可是能夠重寫它來對子視圖隱藏觸摸事件。

此方法忽略隱藏、禁用用戶交互或alpha級別小於0.01的視圖對象的過濾。此方法在肯定點擊時不考慮視圖的內容。所以,即便指定的點位於視圖內容的透明部分中,仍能夠返回該視圖。

位於接收器邊界以外的點永遠不會報告爲點擊,即便它們實際上位於接收器的子視圖中。若是當前視圖的clipsToBounds屬性設置爲NO,而且受影響的子視圖超出了視圖的邊界,則可能會發生這種狀況。

參數 :

point : 在接收器的局部座標系(邊界)中指定的點。

event : 保證調用此方法的事件。若是從事件處理代碼外部調用此方法,則能夠指定nil。

返回值 : 視圖對象,它是當前視圖的最遠子代,包含點。若是點徹底位於接收器的視圖層次結構以外,則返回nil。

- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;
複製代碼

- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;

函數描述 : 返回一個布爾值,該值指示接收器是否包含指定的點。

參數 :

point : 在接收器的局部座標系(邊界)中的點。

event : 保證調用此方法的事件。若是從事件處理代碼外部調用此方法,則能夠指定nil。

返回值 : 若是點在接收器的範圍內,則爲YES;不然爲NO。

- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event; 
複製代碼

- (CGPoint)convertPoint:(CGPoint)point toView:(nullable UIView *)view;

函數描述 : 將點從接收者的座標系統轉換爲指定視圖的座標系統。

參數 :

point : 在接收器的局部座標系(邊界)中指定的點。

view : 要轉換到其座標系點的視圖。若是view爲nil,則此方法將轉換爲窗口基座標。不然,視圖和接收器必須屬於同一個UIWindow對象。

返回值 : 轉換爲視圖座標系的點。

- (CGPoint)convertPoint:(CGPoint)point toView:(nullable UIView *)view;
複製代碼

簡單的示例,例如使超出父視圖的範圍的按鈕部分響應點擊

@interface testView : UIView

@property (nonatomic, strong)UIButton *testCodeButton;

@end

@implementation testView

- (instancetype)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if(self){
        self.testCodeButton = [UIButton buttonWithType:UIButtonTypeCustom];
        self.testCodeButton.backgroundColor = [UIColor blueColor];
        self.testCodeButton.alpha = 0.5;
        self.testCodeButton.titleLabel.font = [UIFont systemFontOfSize:15];
        [self.testCodeButton setTitle:@"測試代碼" forState:UIControlStateNormal];
        [self.testCodeButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
        [self addSubview:self.testCodeButton];
        
        [self.testCodeButton mas_makeConstraints:^(MASConstraintMaker *make) {
            make.top.equalTo(self.mas_top).offset(-35);
            make.centerX.equalTo(self);
            make.size.mas_equalTo(CGSizeMake(150, 55));
        }];
    }
    return self;
}

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    UIView *view = [super hitTest:point withEvent:event];
    if ([view isKindOfClass:[UIButton class]]) {
        return view;
    }else if (view == nil) {
        // 轉換座標系
        CGPoint newPoint = [self.testCodeButton convertPoint:point fromView:self];
        // 判斷觸摸點是否在button上
        if (CGRectContainsPoint(self.testCodeButton.bounds, newPoint)) {
            view = self.testCodeButton;
        }
    }
    return view;
}

@end


@interface TestCodeController ()

@property (nonatomic, strong) testView *tview;

@end

@implementation TestCodeController

- (void)viewDidLoad {
    
    [super viewDidLoad];
    self.navigationItem.title = @"測試代碼控制器";
    
    self.tview = [[testView alloc]initWithFrame:CGRectMake(CGRectGetMaxX(self.view.frame) / 2 - 150 / 2, CGRectGetMaxY(self.view.frame) / 2 - 150 / 2, 150, 150)];
    self.tview.backgroundColor = [UIColor redColor];
    [self.tview.testCodeButton addTarget:self action:@selector(testCode) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:self.tview];
    
}

///測試按鈕點擊
- (void)testCode{
    YSUIntent *intent = [[YSUIntent alloc]initWithClassName:@"ShadowViewController"];
    intent.useNavigationToPush = YES;
    intent.method = OPEN_METHOD_POP;
    [self openIntent:intent];
}

@end
複製代碼

沒有實現hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event函數時:

Jietu20200713-230732.gif

實現hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event函數時:

Jietu20200713-231706.gif

- (CGSize)sizeThatFits:(CGSize)size;

函數描述 :要求視圖計算並返回最適合指定大小的大小。此方法的默認實現將返回視圖的現有大小。子類能夠重寫此方法,以根據任何子視圖的指望佈局返回自定義值。例如,一個UISwitch對象返回一個固定大小值,該值表示一個switch視圖的標準大小,而一個UIImageView對象返回它當前顯示的圖像的大小。此方法不調整接收器的大小。

參數 :

size : 視圖應計算其最佳擬合大小的大小

返回值 : 適合接收者子視圖的新大小。

- (CGSize)sizeThatFits:(CGSize)size;   
複製代碼

- (void)sizeToFit;

函數描述 : 調整接收器視圖的大小並移動它,使其將它的子視圖括起來。若是要調整當前視圖的大小以使其使用最合適的空間量,請調用此方法。特定的UIKit視圖根據本身的內部需求調整本身的大小。在某些狀況下,若是視圖沒有超視圖,它可能會根據屏幕邊界調整自身大小。所以,若是但願給定視圖將自身調整爲其父視圖的大小,則應在調用此方法以前將其添加到父視圖。

不該重寫此方法。若是要更改視圖的默認大小信息,請改成重寫sizeThatFits:。該方法執行任何所需的計算並將其返回給該方法,而後由該方法進行更改。

- (void)sizeToFit; 
複製代碼

注:通常在使用UILabel的時候會用到,使用這兩個方法以前,必需要給label賦值,不然不會顯示內容的。sizeThatFits會計算出最優的 size 可是不會改變 本身的 size。sizeToFit會計算出最優的 size 並且會改變本身的size。

UIView(UIViewHierarchy) - 視圖層次結構

經常使用函數

- (void)removeFromSuperview;

函數描述 : 從父視圖及其窗口中取消視圖的連接,並將其從響應鏈中移除。若是視圖的父視圖不是nil,則父視圖釋放該視圖。調用此方法將刪除指向要刪除的視圖的任何約束,或指向要刪除的視圖的子樹中的任何視圖的約束。

注 : 永遠不要從視圖的drawRect:方法中調用這個方法。

- (void)removeFromSuperview;
複製代碼

例如處理 bug,當頁面刷新的時候,狀況是這樣的:

屏幕快照 2019-06-05 上午11.54.06.png

想到的解決辦法就是在每次刷新前將視圖中的子視圖移除:

  1. makeObjectsPerformSelector :簡化循環代碼,數組的每一個元素都會執行@selector(removeFromSuperview)指定的removeFromSuperview方法。前提是元素的類型要擁有這個方法,不然會出現unrecognized selector sent to instance錯誤。

  2. removeFromSuperview :將當前視圖從其父視圖移除。

[self.imgBackView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
複製代碼
- (void)removeFromSuperview{
    [self.imgBackView.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull subView, NSUInteger idx, BOOL * _Nonnull stop) {
        [subView removeFromSuperview];
    }];
}
複製代碼

處理完在此頻繁刷新,是這樣的:

屏幕快照 2019-06-05 下午1.37.45.png

- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index;

函數描述 : 在指定的索引處插入子視圖。該方法創建了視圖的強引用,並將它的下一個響應器設置爲接收器,這是它的新父視圖。視圖只能有一個父視圖。若是視圖已經有一個父視圖,而該視圖不是接收器(接收器指調用函數的對象),則此方法在使接收器成爲其新父視圖以前刪除先前的父視圖。

參數 :

view : 要插入的視圖。這個值不能爲空。

index : 要在其中插入視圖的子視圖屬性數組中的索引。子視圖索引從0開始,而且不能大於子視圖的數量。

- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index;
複製代碼

- (void)exchangeSubviewAtIndex:(NSInteger)index1 withSubviewAtIndex:(NSInteger)index2;

函數描述 : 交換指定索引處的子視圖。每一個索引表示子視圖屬性中數組中相應視圖的位置。子視圖索引從0開始,而且不能大於子視圖的數量。這個方法不改變任何一個視圖的父視圖,而只是交換它們在子視圖數組中的位置。

參數 :

index1 : 接收器中第一個子視圖的索引。

index2 : 接收器中第二個子視圖的索引。

- (void)exchangeSubviewAtIndex:(NSInteger)index1 withSubviewAtIndex:(NSInteger)index2;
複製代碼

例如交換兩個視圖的層級:

@interface TestCodeController ()

@property (nonatomic, strong) UIView *view1;
@property (nonatomic, strong) UIView *view2;

@end

@implementation TestCodeController

- (void)viewDidLoad {
    
    [super viewDidLoad];
    self.navigationItem.title = @"測試代碼控制器";
    
    self.view1 = [[UIView alloc]initWithFrame:CGRectMake(CGRectGetMaxX(self.view.frame) / 2 - 150 / 2, CGRectGetMaxY(self.view.frame) / 2 - 150 / 2, 150, 150)];
    self.view1.backgroundColor = [UIColor redColor];
    [self.view addSubview:self.view1];
    
    self.view2 = [[UIView alloc]initWithFrame:CGRectMake(CGRectGetMaxX(self.view.frame) / 2 - 150 / 2, CGRectGetMaxY(self.view.frame) / 2 - 150 / 2, 150, 150)];
    self.view2.backgroundColor = [UIColor greenColor];
    [self.view addSubview:self.view2];
    
    UIButton *testCodeButton = [UIButton buttonWithType:UIButtonTypeCustom];
    testCodeButton.frame = CGRectMake(CGRectGetMaxX(self.view.frame) / 2 - 75 / 2, CGRectGetMaxY(self.view1.frame) + 20, 75, 30);
    testCodeButton.backgroundColor = [UIColor blueColor];
    testCodeButton.titleLabel.font = [UIFont systemFontOfSize:15];
    [testCodeButton setTitle:@"測試代碼" forState:UIControlStateNormal];
    [testCodeButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    [testCodeButton addTarget:self action:@selector(testCode) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:testCodeButton];
}

///測試按鈕點擊
- (void)testCode{
    [self testexchangeSubviewAtIndex:self.view1 andView:self.view2];
}

///交換視圖層級
- (void)testexchangeSubviewAtIndex:(UIView *)view1 andView:(UIView *)view2{
    NSInteger index1 = 0;
    NSInteger index2 = 0;
    for (int i = 0; i < self.view.subviews.count; i++) {
        if([self.view.subviews[i] isEqual:view1]){
            index1 = I;
        }else if([self.view.subviews[i] isEqual:view2]){
            index2 = I;
        }
    }
    if(index1 != index2){
        [self.view exchangeSubviewAtIndex:index1 withSubviewAtIndex:index2];
    }
}

複製代碼

效果如圖:

Jietu20200220-214404.gif

- (void)addSubview:(UIView *)view;

函數描述 : 將視圖添加到接收器的子視圖列表的末尾。該方法創建了視圖的強引用,並將它的下一個響應器設置爲接收器,這是它的新父視圖。視圖只能有一個父視圖。若是視圖已經有一個父視圖,而該視圖不是接收方,則此方法在使接收器成爲其新父視圖以前刪除先前的父視圖。

參數 :

view : 要添加的視圖。添加後,此視圖將出如今任何其餘子視圖之上。

- (void)addSubview:(UIView *)view;
複製代碼

- (void)insertSubview:(UIView *)view belowSubview:(UIView *)siblingSubview;

函數描述 : 在視圖層次結構中的另外一個視圖下方插入視圖。該方法創建了視圖的強引用,並將它的下一個響應器設置爲接收器,這是它的新父視圖。視圖只能有一個父視圖。若是視圖已經有一個父視圖,而該視圖不是接收器,則此方法在使接收器成爲其新父視圖以前刪除先前的父視圖。

參數 :

view : 要在另外一個視圖下插入的視圖。若是它不是siblingSubview的同級,則從其superview中移除。

siblingSubview : 插入視圖上方的同級視圖。

- (void)insertSubview:(UIView *)view belowSubview:(UIView *)siblingSubview;
複製代碼

例如在視圖層次結構中的另外一個視圖下方插入視圖:

#import "TestCodeController.h"

@interface TestCodeController ()

@property (nonatomic, strong) UIView *view1;
@property (nonatomic, strong) UIView *view2;
@property (nonatomic, strong) UIView *view3;

@end

@implementation TestCodeController

- (void)viewDidLoad {
    
    [super viewDidLoad];
    self.navigationItem.title = @"測試代碼控制器";
    
    self.view1 = [[UIView alloc]initWithFrame:CGRectMake(CGRectGetMaxX(self.view.frame) / 2 - 150 / 2, CGRectGetMaxY(self.view.frame) / 2 - 150 / 2, 150, 150)];
    self.view1.backgroundColor = [UIColor redColor];
    [self.view addSubview:self.view1];
    
    self.view2 = [[UIView alloc]initWithFrame:CGRectMake(CGRectGetMaxX(self.view.frame) / 2 - 150 / 2, CGRectGetMinY(self.view1.frame) + 30, 150, 150)];
    self.view2.backgroundColor = [UIColor greenColor];
    [self.view addSubview:self.view2];
    
    self.view3 = [[UIView alloc]initWithFrame:CGRectMake(CGRectGetMaxX(self.view.frame) / 2 - 150 / 2, CGRectGetMinY(self.view1.frame) + 15, 150, 150)];
    self.view3.backgroundColor = [UIColor yellowColor];
    
    UIButton *testCodeButton = [UIButton buttonWithType:UIButtonTypeCustom];
    testCodeButton.frame = CGRectMake(CGRectGetMaxX(self.view.frame) / 2 - 75 / 2, CGRectGetMaxY(self.view1.frame) + 40, 75, 30);
    testCodeButton.backgroundColor = [UIColor blueColor];
    testCodeButton.titleLabel.font = [UIFont systemFontOfSize:15];
    [testCodeButton setTitle:@"測試代碼" forState:UIControlStateNormal];
    [testCodeButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    [testCodeButton addTarget:self action:@selector(testCode) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:testCodeButton];
}

///測試按鈕點擊
- (void)testCode{
    [self testInsertSubview:self.view3 belowSubview:self.view2];
}

///在視圖層次結構中的另外一個視圖下方插入視圖
- (void)testInsertSubview:(UIView *)view belowSubview:(UIView *)siblingSubview{
    
    [self.view insertSubview:view belowSubview:siblingSubview];
}
複製代碼

效果如圖 :

Jietu20200225-101740.gif

- (void)insertSubview:(UIView *)view aboveSubview:(UIView *)siblingSubview;

函數描述 : 在視圖層次結構中的另外一個視圖上方插入視圖。此方法創建對視圖的強引用,並將其下一個響應者設置爲接收器,這是它的新父視圖。視圖只能有一個父視圖。若是視圖已經有一個父視圖,而該視圖不是接收器,則此方法在使接收器成爲其新父視圖以前刪除先前的父視圖。

參數 :

view : 要插入的視圖。若是它不是siblingSubview的同級,則從其superview中移除。

siblingSubview : 插入的視圖下面的同級視圖。

- (void)insertSubview:(UIView *)view aboveSubview:(UIView *)siblingSubview;
複製代碼

- (void)bringSubviewToFront:(UIView *)view;

函數描述 : 移動指定的子視圖,使其顯示在其同級視圖的頂部。此方法將指定的視圖移動到「subviews 」屬性中視圖數組的末尾。

參數 :

view : 要移到前面的子視圖。

- (void)bringSubviewToFront:(UIView *)view;
複製代碼

例如移動指定的子視圖,使其顯示在其同級視圖的頂部:

#import "TestCodeController.h"

@interface TestCodeController ()

@property (nonatomic, strong) UIView *view1;
@property (nonatomic, strong) UIView *view2;
@property (nonatomic, strong) UIView *view3;

@end

@implementation TestCodeController

- (void)viewDidLoad {
    
    [super viewDidLoad];
    self.navigationItem.title = @"測試代碼控制器";
    
    self.view1 = [[UIView alloc]initWithFrame:CGRectMake(CGRectGetMaxX(self.view.frame) / 2 - 150 / 2, CGRectGetMaxY(self.view.frame) / 2 - 150 / 2, 150, 150)];
    self.view1.backgroundColor = [UIColor redColor];
    [self.view addSubview:self.view1];
    
    self.view2 = [[UIView alloc]initWithFrame:CGRectMake(CGRectGetMaxX(self.view.frame) / 2 - 150 / 2, CGRectGetMinY(self.view1.frame) + 30, 150, 150)];
    self.view2.backgroundColor = [UIColor greenColor];
    [self.view addSubview:self.view2];
    
    self.view3 = [[UIView alloc]initWithFrame:CGRectMake(CGRectGetMaxX(self.view.frame) / 2 - 150 / 2, CGRectGetMinY(self.view1.frame) + 15, 150, 150)];
    self.view3.backgroundColor = [UIColor yellowColor];
    [self.view addSubview:self.view3];
    
    UIButton *testCodeButton = [UIButton buttonWithType:UIButtonTypeCustom];
    testCodeButton.frame = CGRectMake(CGRectGetMaxX(self.view.frame) / 2 - 75 / 2, CGRectGetMaxY(self.view1.frame) + 40, 75, 30);
    testCodeButton.backgroundColor = [UIColor blueColor];
    testCodeButton.titleLabel.font = [UIFont systemFontOfSize:15];
    [testCodeButton setTitle:@"測試代碼" forState:UIControlStateNormal];
    [testCodeButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    [testCodeButton addTarget:self action:@selector(testCode) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:testCodeButton];
}

///測試按鈕點擊
- (void)testCode{
    [self testBringSubviewToFront:self.view1];
}

///移動指定的子視圖,使其顯示在其同級視圖的頂部
- (void)testBringSubviewToFront:(UIView *)view{
    [self.view bringSubviewToFront:view];
}

複製代碼

效果如圖 :

Jietu20200225-215556.gif

- (void)sendSubviewToBack:(UIView *)view;

函數描述 : 移動指定的子視圖,使其顯示在其同級視圖的後面。此方法將指定的視圖移動到「subviews」屬性中視圖數組的開頭。

參數 :

view : 要移到後面的子視圖。

- (void)sendSubviewToBack:(UIView *)view;
複製代碼

- (void)didAddSubview:(UIView *)subview;

函數描述 : 告訴視圖已添加子視圖。此方法的默認實現不起任何做用。子類能夠重寫它,以便在添加子視圖時執行其餘操做。此方法是在使用任何相關視圖方法添加子視圖時調用的。

參數 :

subview : 做爲子視圖添加的視圖。

- (void)didAddSubview:(UIView *)subview;
複製代碼

例如 :

@interface TestView : UIView

@property (nonatomic, assign) NSInteger number;

@end

@implementation TestView

- (void)didAddSubview:(UIView *)subview{
    [super didAddSubview:subview];
    self.number += 1;
    NSLog(@"添加%ld次視圖了",(long)self.number);
}

@end

@interface TestCodeController ()

@property (nonatomic, strong) TestView *contentView;
@property (nonatomic, strong) UIView *view1;
@property (nonatomic, strong) UIView *view2;
@property (nonatomic, strong) UIView *view3;

@end

@implementation TestCodeController

- (void)viewDidLoad {
    
    [super viewDidLoad];
    self.navigationItem.title = @"測試代碼控制器";
    
    self.contentView = [[TestView alloc]initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame))];
    [self.view addSubview:self.contentView];
    
    self.view1 = [[UIView alloc]initWithFrame:CGRectMake(CGRectGetMaxX(self.view.frame) / 2 - 150 / 2, CGRectGetMaxY(self.view.frame) / 2 - 150 / 2, 150, 150)];
    self.view1.backgroundColor = [UIColor redColor];
    [self.contentView addSubview:self.view1];
    
    self.view2 = [[UIView alloc]initWithFrame:CGRectMake(CGRectGetMaxX(self.view.frame) / 2 - 150 / 2, CGRectGetMinY(self.view1.frame) + 30, 150, 150)];
    self.view2.backgroundColor = [UIColor greenColor];
    [self.contentView addSubview:self.view2];
    
    self.view3 = [[UIView alloc]initWithFrame:CGRectMake(CGRectGetMaxX(self.view.frame) / 2 - 150 / 2, CGRectGetMinY(self.view1.frame) + 15, 150, 150)];
    self.view3.backgroundColor = [UIColor yellowColor];
    [self.contentView addSubview:self.view3];
    
    UIButton *testCodeButton = [UIButton buttonWithType:UIButtonTypeCustom];
    testCodeButton.frame = CGRectMake(CGRectGetMaxX(self.view.frame) / 2 - 75 / 2, CGRectGetMaxY(self.view1.frame) + 40, 75, 30);
    testCodeButton.backgroundColor = [UIColor blueColor];
    testCodeButton.titleLabel.font = [UIFont systemFontOfSize:15];
    [testCodeButton setTitle:@"測試代碼" forState:UIControlStateNormal];
    [testCodeButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    [testCodeButton addTarget:self action:@selector(testCode) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:testCodeButton];
}

複製代碼

輸出如圖 :

截屏2020-02-25下午10.27.31.png

- (void)willRemoveSubview:(UIView *)subview;

函數描述 : 告訴視圖子視圖即將被刪除。此方法的默認實現不起任何做用。子類能夠重寫它,以便在刪除子視圖時執行其餘操做。當子視圖的父視圖更改或子視圖從視圖層次結構中徹底刪除時,將調用此方法。

參數 :

subview : 將被刪除的子視圖。

- (void)willRemoveSubview:(UIView *)subview;
複製代碼

- (void)layoutSubviews;

函數描述 : 在某個類的內部調整子視圖位置時,須要調用這個方法,默認沒有作任何事情,須要子類進行重寫 。 系統在不少時候會去調用這個方法,初始化不會觸發layoutSubviews,可是若是設置了不爲CGRectZero的frame並添加到父視圖的時候就會觸發,要在實現的最後調用[super layoutSubviews]。不該直接調用此方法。若是要強制進行佈局更新,請在下次圖形更新以前調用setNeedsLayout方法。若是要當即更新視圖的佈局,請調用layoutIfNeeded方法。

layoutSubviews方法的觸發: 1.直接調用[self setNeedsLayout]; 2.addSubview的時候。 3.當view的size發生改變的時候,前提是frame的值設置先後發生了變化。 4.滑動UIScrollView的時候。 5.旋轉Screen會觸發父UIView上的layoutSubviews事件

- (void)layoutSubviews;
複製代碼

一般也能夠在layoutSubviews函數中對錶視圖的cell添加CALayer對象進行佈局操做,好比添加分割線或者漸變圖層,這裏以簡單的添加分割線爲例,例如添加相似的分割線:

截屏2021-07-06上午10.42.44.png

若是在表視圖的cell初始化時添加CALayer,經過self.contentView.frame獲取的寬高一般不許確。

cell初始化函數中添加CALayer的代碼片斷:

///底部分割線
self.separatorLineLayer = [[CALayer alloc] init];
NSLog(@"%f",CGRectGetHeight(self.contentView.frame));
NSLog(@"%f",CGRectGetWidth(self.contentView.frame));
self.separatorLineLayer.frame = CGRectMake(0, CGRectGetHeight(self.contentView.frame) - 0.5, CGRectGetWidth(self.contentView.frame), 0.6);
[self.contentView.layer addSublayer:_separatorLineLayer];
self.separatorLineLayer.backgroundColor = [UIColor grayColor].CGColor;
複製代碼

打印的結果爲:

截屏2021-07-06上午10.28.16.png

視圖樣式爲:

截屏2021-07-06上午10.31.56.png

爲了更加精確的佈局cell中的CALayer對象,則能夠在cell初始化函數中初始化做爲分割線的CALayer對象,但不設置frame,將frame在layoutSubviews中進行佈局,則能獲得更爲 精確的佈局。

cell初始化函數中添加CALayer的代碼片斷:

///底部分割線
self.separatorLineLayer = [[CALayer alloc] init];
[self.contentView.layer addSublayer:_separatorLineLayer];
self.separatorLineLayer.backgroundColor = [UIColor grayColor].CGColor;
複製代碼

在layoutSubviews函數中設置frame的代碼片斷:

///底部分割線
- (void)layoutSubviews {
    [super layoutSubviews];
    NSLog(@"%f",CGRectGetHeight(self.contentView.frame));
    NSLog(@"%f",CGRectGetWidth(self.contentView.frame));
    self.separatorLineLayer.frame = CGRectMake(0, CGRectGetHeight(self.contentView.frame) - 0.5, CGRectGetWidth(self.contentView.frame), 0.6);
}
複製代碼

打印的結果爲:

截屏2021-07-06上午10.41.47.png

視圖樣式爲:

截屏2021-07-06上午10.42.44.png

- (void)setNeedsLayout;

函數描述 : 使接收器的當前佈局無效,並在下一個更新週期中觸發佈局更新。若是要調整視圖子視圖的佈局,請在應用程序的主線程上調用此方法。此方法記錄請求並當即返回。因爲此方法不強制當即更新,而是等待下一個更新週期,所以可使用它在更新任何視圖以前使多個視圖的佈局無效。此行爲容許您將全部佈局更新合併到一個更新週期,這一般對性能更好。

設置佈局,告知系統這個視圖須要更新佈局,這個方法會當即返回,可是view會在下一次的更新週期中更新,調用視圖的layoutSubviews。

- (void)setNeedsLayout;
複製代碼

例如 :

- (void)setBgColor:(UIColor *)bgColor {
    _bgColor = bgColor;
    
    self.backgroundColor = bgColor;
    [self setNeedsLayout];
}
複製代碼

- (void)layoutIfNeeded;

函數描述 : 若是佈局更新掛起,則當即佈局子視圖。使用此方法強制視圖當即更新其佈局。使用自動佈局時,佈局引擎根據須要更新視圖的位置,以知足約束的更改。使用接收消息的視圖做爲根視圖,此方法從根開始佈置視圖子樹。若是沒有更新佈局,則該方法退出而不修改佈局或調用任何與佈局相關的回調。

layoutIfNeeded不必定會觸發view的layoutSubviews。系統會檢測layoutSubviews的觸發條件,若是符合條件,那麼會當即觸發layoutSubviews,不會等待下一次的更新週期。但若是不符合layoutSubviews的觸發條件則不會觸發。

- (void)layoutIfNeeded;
複製代碼

例如 :在視圖動畫塊代碼中使用Masonry更改佈局,在調用layoutIfNeeded後纔會觸發動畫:

[UIView animateWithDuration:1 animations:^{
    [self.customSelectRecurrenceView mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.bottom.equalTo(self.view.mas_bottom).offset(-YSLCommonPadding * 2);
        make.centerX.equalTo(self.view);
        make.size.mas_equalTo(CGSizeMake(SCREEN_WIDTH - 20, 540));
    }];
    [self.view layoutIfNeeded];
 } completion:^(BOOL finished) {
    self.repetitionModeTableView.hidden = YES;
 }];
複製代碼

UIView(UIViewRendering) - 視圖渲染

經常使用屬性

@property(nonatomic) BOOL clipsToBounds;

屬性描述 : 一個布爾值,用於肯定子視圖是否限制在視圖的邊界內。將此值設置爲「YES」將致使子視圖被剪裁到接收器的邊界。若是設置爲「NO」,則不會剪裁幀超出接收器可見邊界的子視圖。默認值爲NO。

@property(nonatomic)                 BOOL              clipsToBounds; 
複製代碼

@property(nullable, nonatomic,copy) UIColor *backgroundColor UI_APPEARANCE_SELECTOR;

屬性描述 : 視圖的背景色。對此屬性的更改能夠設置動畫。默認值爲nil,這將產生透明的背景色。

@property(nullable, nonatomic,copy)            UIColor          *backgroundColor UI_APPEARANCE_SELECTOR;
複製代碼

@property(nonatomic) CGFloat alpha;

屬性描述:視圖的alpha值。此屬性的值是介於0.0到1.0之間的浮點數,其中0.0表示徹底透明,1.0表示徹底不透明。更改此屬性的值僅更新當前視圖的alpha值。可是,該alpha值賦予的透明度會影響視圖的全部內容,包括其子視圖。例如,嵌入到alpha值爲0.5的父視圖中的alpha值爲1.0的子視圖將顯示在屏幕上,就好像它的alpha值也是0.5同樣。對此屬性的更改能夠設置動畫。

@property(nonatomic)                 CGFloat           alpha; 
複製代碼

@property(nonatomic,getter=isOpaque) BOOL opaque;

屬性描述 : 決定視圖是否不透明的布爾值。這個屬性向繪圖系統提供了應該如何處理視圖的提示。若是設置爲YES,繪圖系統將視圖視爲徹底不透明的,這容許繪圖系統優化一些繪圖操做並提升性能。若是設置爲NO,繪圖系統將正常地將視圖與其餘內容組合在一塊兒。這個屬性的默認值是YES。

不透明視圖應該用徹底不透明的內容填充其邊界——也就是說,內容的alpha值應該爲1.0。若是視圖是不透明的,或者沒有填充其邊界,或者包含徹底或部分透明的內容,結果是不可預測的。若是視圖是徹底或部分透明的,則應該始終將此屬性的值設置爲NO。

只須要在UIView的子類中爲opaque屬性設置一個值,這些子類使用drawRect:方法繪製本身的內容。不透明屬性在系統提供的類(如UIButton、UILabel、UITableViewCell等)中不起做用。

@property(nonatomic,getter=isOpaque) BOOL              opaque;
複製代碼

@property(nonatomic) BOOL clearsContextBeforeDrawing;

屬性描述 : 一個布爾值,用來決定是否在繪製前自動清除視圖的邊界。當設置爲YES時,繪製緩衝區在調用drawRect:方法以前自動清除爲透明黑色。此行爲可確保在從新繪製視圖內容時不會留下任何視覺瑕疵。若是視圖的opaque屬性也設置爲YES,則視圖的backgroundColor屬性不能爲nil,不然可能會出現繪製錯誤。這個屬性的默認值是YES。

若是將此屬性的值設置爲NO,則負責確保在drawRect:方法中正確繪製視圖的內容。若是圖形代碼已經進行了大量優化,則將此屬性設置爲「否」能夠提升性能,尤爲是在滾動視圖時,可能只須要從新繪製視圖的一部分。

@property(nonatomic)                 BOOL              clearsContextBeforeDrawing;
複製代碼

@property(nonatomic,getter=isHidden) BOOL hidden;

屬性描述 : 肯定視圖是否隱藏的布爾值。將此屬性的值設置爲「YES」將隱藏接收器,將其設置爲「NO」將顯示接收器。默認值爲「NO」。

隱藏視圖將從其窗口中消失,而且不接收輸入事件。不過,它仍保留在其superview的子視圖列表中,並像往常同樣參與自動調整大小。隱藏包含子視圖的視圖的效果是隱藏這些子視圖及其可能具備的任何視圖後代。這種效果是隱式的,不會改變接收者後代的隱藏狀態。

隱藏做爲窗口當前第一響應程序的視圖會致使視圖的下一個有效鍵視圖成爲新的第一響應程序。

此屬性的值僅反映接收器的狀態,而不說明接收器祖先在視圖層次結構中的狀態。所以,這個屬性能夠是NO,可是若是一個祖先是隱藏的,那麼接收者可能仍然是隱藏的。

@property(nonatomic,getter=isHidden) BOOL              hidden; 
複製代碼

@property(nonatomic) UIViewContentMode contentMode;

屬性描述:當視圖的邊界改變時,用來肯定視圖如何佈局其內容的標誌。內容模式指定了當視圖的邊界改變時如何調整緩存的視圖層位圖。此屬性一般用於實現可調整大小的控件。不用每次都從新繪製視圖的內容,可使用此屬性來指定但願縮放內容(有或沒有失真)或將它們固定到視圖上的一個特定位置。

@property(nonatomic)                 UIViewContentMode contentMode; 
複製代碼

UIViewContentMode的枚舉值

typedef NS_ENUM(NSInteger, UIViewContentMode) {
    //根據須要經過更改內容的縱橫比來縮放內容以適合其自身大小的選項。
    //UIImageView使用時,圖片拉伸填充至整個UIImageView(圖片可能會變形)
    UIViewContentModeScaleToFill,
    //經過保持縱橫比縮放內容以適應視圖大小的選項。視圖邊界的任何剩餘區域都是透明的。
    //UIImageView使用時,圖片拉伸至徹底顯示在UIImageView裏面爲止(圖片不會變形),但可能長或寬某一方向留白
    UIViewContentModeScaleAspectFit, 
    //縮放內容以填充視圖大小的選項。內容的某些部分可能會被剪裁以填充視圖的邊界。
    //UIImageView使用時,圖片拉伸至徹底顯示在UIImageView裏面爲止(圖片不會變形),但可能超過UIImageView的邊界而被裁減
    UIViewContentModeScaleAspectFill, 
    //當邊界改變時經過調用setNeedsDisplay方法從新顯示視圖的選項。
    UIViewContentModeRedraw, 
    //使內容在視圖邊界居中的選項,保持比例不變。
    UIViewContentModeCenter, 
    //將內容居中對齊視圖邊界頂部的選項。
    UIViewContentModeTop,
    //使內容在視圖邊界的底部居中的選項
    UIViewContentModeBottom,
    //在視圖左側對齊內容的選項。
    UIViewContentModeLeft,
    //在視圖右側對齊內容的選項。
    UIViewContentModeRight,
    //在視圖左上角對齊內容的選項。
    UIViewContentModeTopLeft,
    //在視圖右上角對齊內容的選項。
    UIViewContentModeTopRight,
    //對齊視圖左下角內容的選項。
    UIViewContentModeBottomLeft,
    //對齊視圖右下角內容的選項。
    UIViewContentModeBottomRight,
};
複製代碼
經常使用函數

- (void)setNeedsDisplay;

將接收者的整個邊界矩形標記爲須要從新繪製。可使用此方法或setNeedsDisplayInRect:通知系統須要從新繪製視圖的內容。此方法記錄請求並當即返回。直到下一個繪圖週期(此時將更新全部無效的視圖)時,視圖才實際從新繪製。

若是你的視圖是由一個CAEAGLLayer對象支持的,這個方法沒有效果。它只用於使用本地繪圖技術(如UIKit和Core Graphics)來呈現內容的視圖。應該使用此方法來請求僅在視圖的內容或外觀更改時從新繪製視圖。若是隻是更改視圖的幾何形狀,則一般不會從新繪製視圖。相反,它的現有內容是根據視圖的contentMode屬性中的值進行調整的。從新顯示現有內容能夠避免從新繪製內容,從而提升性能

與setNeedsLayout方法類似。該方法在調用時,會自動調用drawRect方法。drawRect方法主要用來畫圖。因此,當須要刷新佈局時,用setNeedsLayout方法;當須要從新繪畫時,調用setNeedsDisplay方法。

- (void)setNeedsDisplay;
複製代碼

例如 :

- (void)setFillColor:(UIColor *)fillColor {
    if (fillColor) {
        _fillColor = fillColor;
    } else {
        _fillColor = [UIColor whiteColor];
    }
    [self setNeedsDisplay];
}
複製代碼

- (void)drawRect:(CGRect)rect;

屬性描述 : 該方法默認在視圖加載過程當中不作任何處理,當子類繪製視圖內容時就能夠在該方法中添加繪製的代碼。若是在UIView初始化時沒有設置Rect大小,將直接致使drawRect不被自動調用。若是設置了Rect,能夠直接調用setNeedsDisplay觸發。若是視圖以其餘方式設置其內容,則不須要重寫此方法。例如,若是視圖僅顯示背景色,或者視圖直接使用基礎層對象設置其內容,則不須要重寫此方法。

在調用此方法時,UIKit已經爲視圖配置了適當的繪圖環境,能夠簡單地調用渲染內容所需的任何繪圖方法和函數。具體來講,UIKit建立和配置圖形上下文,並調整該上下文的轉換,使其原點與視圖邊框矩形的原點匹配。可使用UIGraphicsGetCurrentContext函數獲取對圖形上下文的引用,但不要創建對圖形上下文的強引用,由於它能夠在對drawRect:方法的調用之間進行更改。

此方法在首次顯示視圖或發生使視圖的可見部分無效的事件時調用。你不該該本身直接調用這個方法。若要使視圖的一部分無效,從而致使該部分被重繪,請改成調用setNeedsDisplay或setNeedsDisplayInRect:方法。

參數 :

rect : 視圖邊界中須要更新的部分。第一次繪製視圖時,這個矩形一般是視圖的整個可見邊界。可是,在隨後的繪圖操做期間,矩形可能只指定視圖的一部分。

- (void)drawRect:(CGRect)rect;
複製代碼

UIView(UIViewAnimationWithBlocks) - 視圖動畫代碼塊

經常使用函數

+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations API_AVAILABLE(ios(4.0));

函數描述 : 使用指定的持續時間對一個或多個視圖的更改設置動畫。此方法使用UIViewAnimationOptionCurveEaseInOut和UIViewAnimationOptionTransitionNone動畫選項當即執行指定的動畫。

在動畫期間,將暫時禁用正在設置動畫的視圖的用戶交互。(在iOS 5以前,對整個應用程序禁用用戶交互。)

參數 :

duration : 動畫的總持續時間,以秒爲單位。若是指定負值或0,則在不設置動畫的狀況下進行更改。

animations : 包含要提交到視圖的更改的塊對象。這是以編程方式更改視圖層次結構中視圖的任何可設置動畫的屬性的地方。此塊不接受任何參數,也沒有返回值。此參數不能爲NULL。

+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations API_AVAILABLE(ios(4.0));
複製代碼

+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion API_AVAILABLE(ios(4.0));

函數描述 : 使用指定的持續時間和完成處理程序爲一個或多個視圖的更改設置動畫。此方法使用UIViewAnimationOptionCurveEaseInOut和UIViewAnimationOptionTransitionNone動畫選項當即執行指定的動畫。

在動畫期間,將暫時禁用正在設置動畫的視圖的用戶交互。(在iOS 5以前,對整個應用程序禁用用戶交互。)

參數 :

duration : 動畫的總持續時間,以秒爲單位。若是指定負值或0,則在不設置動畫的狀況下進行更改。

animations : 包含要提交到視圖的更改的塊對象。這是以編程方式更改視圖層次結構中視圖的任何可設置動畫的屬性的地方。此塊不接受任何參數,也沒有返回值。此參數不能爲NULL。

completion : 動畫序列結束時執行的塊對象。這個塊沒有返回值,只有一個布爾參數,用來指示動畫在完成處理程序被調用以前是否已經完成。若是動畫的持續時間是0,這個塊將在下一個運行循環的開始執行。該參數能夠爲NULL。

+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion API_AVAILABLE(ios(4.0));
複製代碼

+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion API_AVAILABLE(ios(4.0));

函數描述:使用指定的持續時間、延遲、選項和完成處理程序爲一個或多個視圖的更改設置動畫。

此方法啓動一組要在視圖上執行的動畫。animations參數中的block對象包含用於設置一個或多個視圖特性動畫的代碼。

在動畫期間,將暫時禁用正在設置動畫的視圖的用戶交互。(在iOS 5以前,對整個應用程序禁用用戶交互。)若是但願用戶可以與視圖交互,請在options參數中包含UIViewAnimationOptionAllowUserInteraction常量。

參數 :

duration : 動畫的總持續時間,以秒爲單位。若是指定負值或0,則在不設置動畫的狀況下進行更改。

delay :開始動畫以前等待的時間量(以秒爲單位)。指定值0以當即開始動畫。

options : 指示如何執行動畫的選項掩碼。

animations : 包含要提交到視圖的更改的塊對象。這是以編程方式更改視圖層次結構中視圖的任何可設置動畫的屬性的地方。此塊不接受任何參數,也沒有返回值。此參數不能爲NULL。

completion : 動畫序列結束時執行的塊對象。這個塊沒有返回值,只有一個布爾參數,用來指示動畫在完成處理程序被調用以前是否已經完成。若是動畫的持續時間是0,這個塊將在下一個運行循環的開始執行。該參數能夠爲空。

+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion API_AVAILABLE(ios(4.0));
複製代碼

簡單的練習代碼片斷:

- (void)testAnimationBlock{
    //建立測試動畫的標籤
    UILabel *animationLabel = [[UILabel alloc]initWithFrame:CGRectMake(20, CGRectGetMaxY(self.view.frame) / 2, 200, 20)];
    animationLabel.textColor = [UIColor whiteColor];
    animationLabel.backgroundColor = [UIColor blueColor];
    animationLabel.text = @"我出現後就準備跑路了";
    animationLabel.textAlignment = NSTextAlignmentCenter;
    animationLabel.layer.cornerRadius = 8.0;
    animationLabel.layer.masksToBounds = YES;
    animationLabel.alpha = 0.0;
    [self.view addSubview:animationLabel];
    
    [UIView animateWithDuration:5.0 delay:10.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
        animationLabel.alpha = 1.0;
    } completion:^(BOOL finished) {
        [UIView animateWithDuration:2.0 animations:^{
            CGRect newAnimationLabelFrame = animationLabel.frame;
            newAnimationLabelFrame.origin.x = CGRectGetMaxX(self.view.frame) - 200 - 20;
            animationLabel.frame = newAnimationLabelFrame;
        } completion:^(BOOL finished) {
            animationLabel.text = @"我就跑路到這裏吧";
        }];
    }];
}
複製代碼

動畫效果如圖 :

Jietu20210220-140144.gif

UIView (UIConstraintBasedLayoutLayering) - 基於約束的佈局分層

經常使用屬性

@property(nonatomic, readonly) CGSize intrinsicContentSize API_AVAILABLE(ios(6.0));

屬性描述 : 接收視圖的天然大小,僅考慮視圖自己的屬性。自定義視圖一般顯示佈局系統不知道的內容。經過設置此屬性,自定義視圖能夠根據其內容與佈局系統通訊其但願的大小。這個內在大小必須獨立於內容框架,由於例如,沒法根據更改的高度將更改的寬度動態地傳遞給佈局系統。若是自定義視圖沒有給定維度的內部大小,則能夠對該維度使用UIViewNoIntrinsicMetric。

@property(nonatomic, readonly) CGSize intrinsicContentSize API_AVAILABLE(ios(6.0));
複製代碼

例如在自定義導航視圖時,添加按鈕不響應點擊事件:

截屏2020-05-07下午8.05.31.png

能夠在自定義的視圖.h文件中覆蓋intrinsicContentSize屬性,在實例化自定義視圖時設置intrinsicContentSize屬性的值,例如 :

@interface YSCNavigationItemTitleView : UIView

@property(nonatomic, assign) CGSize intrinsicContentSize; //重寫intrinsicContentSize屬性
@property(nonatomic, strong) UILabel *titleLabel; //標題標籤
@property(nonatomic, strong) UIButton *orderTypeSelectionButton; //訂單類型選擇按鈕
@property(nonatomic, strong) UIButton *labelMakeButton;//標題標籤遮罩按鈕

@end

複製代碼
- (void)createNavigationTitleView:(NSString *)text{
    //初始化訂單彙總的自定義標題視圖
    YSCNavigationItemTitleView *navigationItemTitleView = [[YSCNavigationItemTitleView alloc]initWithFrame:CGRectZero];
    //計算文本矩形
    CGRect rect = [navigationItemTitleView.titleLabel.text boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, [YSCUiUtils singleCharactorSizeWithFont:[YSCUiUtils fontOne]].height) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:20]} context:nil];
    //設置訂單彙總的自定義標題視圖大小
    navigationItemTitleView.intrinsicContentSize = CGSizeMake(rect.size.width, [YSCUiUtils singleCharactorSizeWithFont:[YSCUiUtils fontOne]].height);
}
複製代碼

UIView (UIConstraintBasedLayoutCoreMethods) - 基於約束的佈局核心方法

經常使用函數

- (void)updateConstraints API_AVAILABLE(ios(6.0)) NS_REQUIRES_SUPER;

函數描述 : 主要功能是更新view的約束,並會調用其全部子視圖的該方法去更新約束。自定義視圖應該經過重寫此方法來設置更新本身的約束,而後調用setNeedsUpdateConstraints標記約束須要更新。系統在進行佈局layout以前,會調用updateConstraints。要在實現的最後調用[super updateConstraints]。

注 :在發生影響的更改後當即更新約束幾乎老是更乾淨和更容易的。例如,若是要響應按鈕點擊更改約束,請直接在按鈕的操做方法中進行更改。

僅當在位更改約束太慢或視圖正在生成大量冗餘更改時,才應重寫此方法。 要計劃更改,請對視圖調用setNeedsUpdateConstraints。而後,系統在佈局發生以前調用updateConstraint的實現。能夠在自定義視圖的屬性未更改時驗證內容的全部必要約束是否已到位。

實現必須儘量高效。不要停用全部約束,而後從新激活所需的約束。相反,應用必須有某種方法來跟蹤約束,並在每次更新過程當中驗證它們。只更改須要更改的項。在每次更新過程當中,必須確保對應用程序的當前狀態具備適當的約束。

不要在實現中調用setNeedsUpdateConstraints。調用setNeedsUpdateConstraints將調度另外一個更新遍歷,建立一個反饋循環。 調用[super updateConstraints]做爲實現的最後一步。

- (void)updateConstraints API_AVAILABLE(ios(6.0)) NS_REQUIRES_SUPER;
複製代碼

IOS中View進行layout方法

- (void)layoutSubviews;
- (void)setNeedsLayout;
- (void)setNeedsDisplay;
- (void)layoutIfNeeded;
- (void)drawRect:(CGRect)rect;
- (CGSize)sizeThatFits:(CGSize)size;
- (void)sizeToFit;
- (void)updateConstraints;
- (void)setNeedsUpdateConstraints; 
複製代碼

updateViewConstraints

- (void)updateViewConstraints API_AVAILABLE(ios(6.0));

函數描述 :當視圖控制器的視圖須要更新其約束時調用, updateViewConstraints的出現方便了viewController,不用專門去重寫controller的view,當view的updateConstraints被調用時,該view如有controller,該controller的updateViewConstraints便會被調用。 要在實現的最後調用[super updateViewConstraints]。

- (void)updateViewConstraints API_AVAILABLE(ios(6.0));
複製代碼
相關文章
相關標籤/搜索