1. 程式人生 > IOS開發 >iOS UIView的學習筆記

iOS UIView的學習筆記

UIView

UIView為螢幕上的矩形區域管理內容的物件。檢視是應用程式使用者介面的基本構建塊,UIView類定義了所有檢視通用的行為。檢視物件呈現其邊界矩形內的內容,並處理與該內容的任何互動。

UIView類是一個具體的類,您可以例項化它並使用它來顯示固定的背景色。您還可以將其子類化以繪製更復雜的內容。要顯示應用程式中常見的標籤、影象、按鈕和其他介面元素,請使用UIKit框架提供的檢視子類,而不要試圖定義自己的檢視子類。

因為檢視物件是應用程式與使用者互動的主要方式,所以它們有許多職責。以下是一些:

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

3.事件處理

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

UIView常用屬性

@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(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常用函式

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

函式描述 : 使用指定的框架矩形初始化並返回新分配的檢視物件。新檢視物件必須插入到視窗的檢視層次結構中才能使用。如果以程式設計方式建立檢視物件,則此方法是UIView類的指定初始值設定項。子類可以重寫此方法以執行任何自定義初始化,但必須在其實現開始時呼叫super。

如果使用Interface Builder設計介面,則在隨後從nib檔案載入檢視物件時不呼叫此方法。nib檔案中的物件被重新構造,然後使用它們的initWithCoder:方法進行初始化,該方法修改檢視的屬性以匹配儲存在nib檔案中的屬性。

引數 :

frame : 檢視的邊框矩形,以點為單位。框架的原點相對於要在其中新增它的超檢視。此方法使用框架矩形相應地設定中心和邊界屬性。

返回值 : 初始化的檢視物件。

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

- (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,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 *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,CGRectGetMinY(self.view1.frame) + 30,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)];
    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,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,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,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 *view3;

@end

@implementation TestCodeController

- (void)viewDidLoad {
    
    [super viewDidLoad];
    self.navigationItem.title = @"測試程式碼控制器";
    
    self.contentView = [[TestView alloc]initWithFrame:CGRectMake(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,150)];
    self.view1.backgroundColor = [UIColor redColor];
    [self.contentView addSubview:self.view1];
    
    self.view2 = [[UIView alloc]initWithFrame:CGRectMake(CGRectGetMaxX(self.view.frame) / 2 - 150 / 2,150)];
    self.view2.backgroundColor = [UIColor greenColor];
    [self.contentView addSubview:self.view2];
    
    self.view3 = [[UIView alloc]initWithFrame:CGRectMake(CGRectGetMaxX(self.view.frame) / 2 - 150 / 2,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,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;
複製程式碼

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; 
複製程式碼

layoutSubviews

- (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;
複製程式碼

setNeedsLayout

- (void)setNeedsLayout;

函式描述 : 使接收器的當前佈局無效,並在下一個更新週期中觸釋出局更新。如果要調整檢視子檢視的佈局,請在應用程式的主執行緒上呼叫此方法。此方法記錄請求並立即返回。由於此方法不強制立即更新,而是等待下一個更新週期,因此可以使用它在更新任何檢視之前使多個檢視的佈局無效。此行為允許您將所有佈局更新合併到一個更新週期,這通常對效能更好。

設定佈局,告知系統這個檢視需要更新佈局,這個方法會立即返回,但是view會在下一次的更新週期中更新,呼叫檢視的layoutSubviews。

- (void)setNeedsLayout;
複製程式碼

例如 :

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

setNeedsDisplay

- (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];
}
複製程式碼

layoutIfNeeded

- (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;
            }];
複製程式碼

drawRect

- (void)drawRect:(CGRect)rect;

屬性描述 : 該方法預設在檢視載入過程中不做任何處理,當子類繪製檢視內容時就可以在該方法中新增繪製的程式碼。如果在UIView初始化時沒有設定Rect大小,將直接導致drawRect不被自動呼叫。如果設定了Rect,可以直接呼叫setNeedsDisplay觸發。如果檢視以其他方式設定其內容,則不需要重寫此方法。例如,如果檢視僅顯示背景色,或者檢視直接使用基礎層物件設定其內容,則不需要重寫此方法。

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

此方法在首次顯示檢視或發生使檢視的可見部分無效的事件時呼叫。你不應該自己直接呼叫這個方法。若要使檢視的一部分無效,從而導致該部分被重繪,請改為呼叫setNeedsDisplay或setNeedsDisplayInRect:方法。

引數 :

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

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

sizeThatFits與sizeToFit

- (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。

updateConstraints

- (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;
複製程式碼

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));
複製程式碼