iOS中自定義view的封裝

語言: CN / TW / HK

highlight: a11y-dark theme: cyanosis


「這是我參與11月更文挑戰的第26天,活動詳情檢視:2021最後一次更文挑戰

自定義view的封裝

  • 如果一個 view 內部的子控制元件比較多,一般會考慮自定義一個 view,把它內部的子控制元件建立並封裝起來,不讓外界看見
  • 外界可以傳入對應的資料模型給 viewview 拿到模型資料後,給內部子控制元件設定對應的資料

程式碼封裝自定義view

  • 程式碼封裝自定義 view 的步驟

    1. 新建一個繼承 UIView 的類
    2. initWithFrame: 方法中新增子控制元件(也可以使用懶載入)
    3. 重寫模型屬性 set 方法,在 set 方法中設定模型屬性到子控制元件上
    4. layoutSubviews 方法中設定子控制元件的 frame(一定要呼叫 [super layoutSubviews]
  • 關於 layoutSubviews 在以下情況下會被呼叫

    • init 初始化不會觸發 layoutSubviews
    • addSubview 會觸發 layoutSubviews
    • 設定 viewFrame 會觸發 layoutSubviews,當然前提是 frame 的值設定前後發生了變化
    • 滾動一個 UIScrollView 會觸發 layoutSubviews
    • 旋轉 Screen 會觸發父 UIView 上的 layoutSubviews 事件
    • 改變一個 UIView 大小的時候也會觸發父 UIView 上的 layoutSubviews 事件

示例

js @class ImageData; @interface ImageDataView : UIView //設定模型屬性 @property (nonatomic,strong) ImageData *imageData; @end

```js

import "ImageData.h"

@interface ImageDataView() @property (nonatomic,strong) UIImageView imageView; @property (nonatomic,strong) UILabel label; @end

@implementation ImageDataView - (instancetype)initWithFrame:(CGRect)frame{ if (self = [super initWithFrame:frame]) {

}
return self;

}

pragma mark- 懶載入

  • (UIImageView )imageView{ if (_imageView == nil) { UIImageView imageView = [[UIImageView alloc]init]; [imageView setBackgroundColor:[UIColor blueColor]]; [self addSubview:imageView]; _imageView = imageView; } return _imageView; }
  • (UILabel )label{ if (_label == nil) { UILabel label = [[UILabel alloc]init]; [label setBackgroundColor:[UIColor redColor]]; label.textAlignment = NSTextAlignmentCenter; [self addSubview:label]; _label = label; } return _label; }

pragma mark- 模型賦值

  • (void)setImageData:(ImageData *)imageData{ _imageData = imageData; self.imageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"%@",imageData.icon]]; self.label.text = imageData.name; }

pragma mark- 子控制元件座標

//這個方法專門用於佈局子控制元件,一般在這裡設定子控制元件的frame //當控制元件本身的尺寸傳送改變時,系統會自動呼叫這個方法 - (void)layoutSubviews{ [super layoutSubviews];

CGFloat personW = self.frame.size.width;
CGFloat personH = self.frame.size.height;

self.imageView.frame = CGRectMake(0, 0, personW, personH-20);
self.label.frame = CGRectMake(0, personH-20, personW, 20);

} @end ```

方法呼叫 js ImageData *imageData = [[ImageData alloc]initWithDic:dic]; ImageDataView *view = [[ImageDataView alloc]init]; view.imageData = imageData; view.frame = CGRectMake(shopX, shopY, imageW, imageH); [bgView addSubview:view];


xib封裝自定義view

  1. 新建一個繼承 UIView 的類
  2. 新建一個xib檔案(xib的檔名最好和控制元件名一樣,修改最外面那個控制元件的 class 為控制元件類名 )

    11975486-154d5a2a195c6dfe-2.png

  3. 新增子控制元件、設定子控制元件屬性 11975486-4dde8f0084d56ec1.png

  4. 載入 xib 檔案 ```js [[[NSBundle mainBundle]loadNibNamed:NSStringFromClass([self class]) owner:self options:nil] lastObject] ````

  5. 重寫模型屬性 set 方法,在 set 方法中設定模型屬性到子控制元件上

示例 ```js

import "ImageDataView.h"

import "ImageData.h"

@interface ImageDataView() @property (weak, nonatomic) IBOutlet UIImageView imageView; @property (weak, nonatomic) IBOutlet UILabel label; @end

@implementation ImageDataView + (instancetype)shareImageDataView{ return [[[NSBundle mainBundle]loadNibNamed:NSStringFromClass([self class]) owner:self options:nil] lastObject]; }

pragma mark- 模型賦值

  • (void)setImageData:(ImageData *)imageData{ _imageData = imageData; self.imageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"%@",imageData.icon]]; self.label.text = imageData.name; } @end ```

兩種方法封裝自定義view的比較

  • 在調整子控制元件的 frame 時,使用純程式碼比 xib 更靈活,子控制元件可以在 layoutSubviews 方法中靈活調整自己的 frame。而用 xib 相對於比較死板,但是更簡單,更方便
  • 自定義 view 時,如果該 view 一直一個樣式,推薦使用xib,簡單方便
  • 而子控制元件經常隨著父控制元件變化而變化,推薦使用純程式碼,靈活多變