這一塊由兩個東西組成:一個imageView和一個label。首先咱們新建一個繼承自UIView的類MyView.佈局
在MyView的.m文件裏,你能夠根據本身的意願將兩個子控件設置成MyView的屬性或者成員變量,這裏咱們設置爲屬性。atom
@property (nonatomic, strong) UIImageView *imageView; @property (nonatomic, strong) UILabel *label;
那接下來,就是要向自定義的view裏面添加控件咯。
一般的思路是重寫UIView的構造方法。那麼這裏要說第一個注意了:debug
1.要重寫UIView的initWithFrame:方法而不是init方法code
爲何呢?由於當外部調用init的方法的時候,其內部也會默默地調用initWithFrame:方法,你不能保證別的同事在調用你的類的時候不會直接調用initWithFrame:方法,這時若是你僅重寫了init方法,那麼兩個子控件便無從建立.繼承
因而咱們寫成這樣:get
- (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { /* 添加子控件的代碼*/ } return self; }
接下開始添加子控件,不知道還會不會有小夥伴是這樣寫的:it
- (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.imageView = [[UIImageView alloc]init]; self.imageView.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.width); [self addSubview:self.imageView]; } return self; }
這樣有什麼問題嗎?若是所有寫好運行起來,能看到imageView嗎?答案是不肯定的.問題出如今給imageView的frame賦值那裏.
imageView的寬和高直接用self.frame.size.width,但這個時候self.frame多是沒有值的.table
上面咱們說過,若是外部調用了MyView的init方法,也會執行到這裏,這時候frame尚未賦值.變量
因此第二個注意:bug
2.不要在構造方法裏面直接取自身(self,或者說本視圖)的寬高,這時候取到的寬高是不許的.
我想初學自定義tableViewCell的小夥伴都遇到過相似這樣的問題:
重寫cell的初始化方法向cell內添加子控件時
(假設cell的高度設爲100,想要添加一個label在cell的底部),
因而這樣寫:
label.frame = CGRectMake(0,self.frame.size.height - 20, 100, 20),
運行出來卻發現添加的label並不在咱們指望的位置(底部),
而是在cell比較偏上的位置(實際y的值是44-20而不是100-20).
而後在debug的時候發現:雖然cell的高度已經設定成爲100,但在初始化方法裏面取到的cell的高度仍然是默認的44.
這其實也是剛纔說的緣由致使的:咱們不能在控件的構造方法裏面取其frame或者bounds,這時候取值是不許確的.
因此在從新構造方法的時候,咱們只須要把控件放進去,暫時先不用考慮他們在什麼位置:
- (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.imageView = [[UIImageView alloc]init]; [self addSubview:self.imageView]; self.label = [[UILabel alloc]init]; self.label.textAlignment = NSTextAlignmentCenter; [self addSubview:self.label]; } return self; }
那麼在何時設置子控件的frame呢?
第三個注意:
3.在layoutSubViews方法裏面佈局子控件
以下:
- (void)layoutSubviews { // 必定要調用super的方法 [super layoutSubviews]; // 肯定子控件的frame(這裏獲得的self的frame/bounds纔是準確的) CGFloat width = self.bounds.size.width; CGFloat height = self.bounds.size.height; self.imageView.frame = CGRectMake(0, 0, width, width); self.label.frame = CGRectMake(0, width, width, height - width); }
這裏要注意的就是須要在佈局以前必定要先調用父類的layoutSubviews方法.
因爲在這個方法裏能夠獲取MyView準確的寬和高,咱們直接取它的寬高來設置imageView和label的寬高就能夠
固然,子控件的建立不必定要寫在MyView的構造方法裏面,既然聲明成爲屬性,使用懶加載(重寫屬性的get方法)也是一個不錯的選擇.