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,簡單方便
  • 而子控件經常隨着父控件變化而變化,推薦使用純代碼,靈活多變