- 首先你進入任意一個工程 ,然后:command+shift+o 疗隶,搜索 UIView佑笋。
嗯,好多屬性和方法斑鼻。一眼掃過去蒋纬,其實很多都會。
開發(fā)中經常會使用到自定義View。那么下面的幾個方法你會了嗎蜀备?
好关摇,我們來看看這幾個比較容易混淆的方法:
- (instancetype)initWithFrame:(CGRect)frame
1、 你經常是這樣寫:
- (id)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];// 先調用父類的initWithFrame方法
if (self) {
// 再自定義該類(UIView子類)的初始化操作碾阁。
_imageView = [[UIImageView alloc] initWithFrame:self.bounds];
[_imageView setFrame:CGRectMake(0, 0, 200, 200)];
_imageView.contentSize = CGSizeMake(320*5, 200);
[self addSubview:_imageView];
}
return self;
}
以上的那樣是OK的输虱,沒出現(xiàn)問題,因為脂凶,你在初始化的時候就明確了具體的大小了宪睹。
如果你使用init 方法,那么結果是什么呢艰猬?
答:答案是啥也沒有横堡!
- (instancetype)init
{
self = [super init];
if (self) {
// 前提是使用了,frame 或bounds 不是具體的尺寸
}
return self;
}
如果要是這樣:把數(shù)字替換成當前的視圖的frame 或bounds的話冠桃,那就會出現(xiàn)莫名其妙的事了,因為可能沒有值:
- (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;
}
2道宅、 嗯食听,解決這個問題,那就要使用 layoutSubviews 了污茵。
- (void)layoutSubviews {
[super layoutSubviews];
// 這里拿到的大小才是真實的
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);
}
2樱报、1 稍微擴展一下:frame 和 bounds 。frame是針對它的父視圖的泞当,bounds 是針對它本身的大小迹蛤。 說白了就是:參照物不同(一個是參照父視圖,一個是參照自己)襟士。
給你看看一張經典的圖:
1盗飒、bounds的原點是(0,0)點(就是view本身的坐標系統(tǒng),默認永遠都是0陋桂,0點逆趣,除非認為setbounds)
2、而frame的原點卻是任意的(相對于父視圖中的坐標位置)嗜历。
//所以:以后如果你想獲得某個view 或視圖的大小宣渗,就可以使用:
CGFloat width = self.bounds.size.width;
CGFloat height = self.bounds.size.height;
總結: 養(yǎng)成好習慣,在initWithFrame 里設置想要的控件梨州。在layoutSubviews 設置控件的大小痕囱。
3、另外一種自定義控件的方法就是采用懶加載方式暴匠。在重寫get方法里直接設置大小也是OK的鞍恢。
比如說:我這個就不用layoutSubviews 來設置大小了。
4、哪 layoutSubviews 又是什么有序,怎么使用抹腿?
答:layoutSubviews 是刷新子對象布局。
蘋果是這樣子說的:
You should override this method only if the autoresizing behaviors of the subviews do not offer the behavior you want.layoutSubviews.
意思是:只要你的子視圖尺寸發(fā)生改變或調整尺寸時旭寿,那么就要重寫該方法警绩。
1、init初始化不會觸發(fā)layoutSubviews盅称, 但是是用initWithFrame 進行初始化時肩祥,當rect的值不為CGRectZero時,也會觸發(fā)
2、addSubview會觸發(fā)layoutSubviews
3缩膝、設置view的Frame會觸發(fā)layoutSubviews混狠,當然前提是frame的值設置前后發(fā)生了變化
4、滾動一個UIScrollView會觸發(fā)layoutSubviews
5疾层、旋轉Screen會觸發(fā)父UIView上的layoutSubviews事件
6将饺、改變一個UIView大小的時候也會觸發(fā)父UIView上的layoutSubviews事件
(void)setNeedsLayout;
需要重新布局,異步調用layoutIfNeeded刷新布局痛黎,不立即刷新予弧,但layoutSubviews一定會被調用。(void)layoutIfNeeded;
// override point. called by layoutIfNeeded automatically. As of iOS 6.0,
when constraints-based layout is used the base implementation applies the constraints-based layout, otherwise it does nothing.(void)layoutSubviews;
這個方法湖饱,默認沒有做任何事情掖蛤,需要子類進行重寫
5、iOS重繪機制drawRect
- (void)drawRect:(CGRect)rect;
重寫 此方法井厌,執(zhí)行重繪任務
// default is UIViewContentModeScaleToFill
@property(nonatomic) UIViewContentMode contentMode;
- (void)drawRect:(CGRect)rect {
// Drawing code.
//獲得處理的上下文
CGContextRef context = UIGraphicsGetCurrentContext();
//設置線條樣式
CGContextSetLineCap(context, kCGLineCapSquare);
//設置線條粗細寬度
CGContextSetLineWidth(context, 1.0);
//設置顏色
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
//開始一個起始路徑
CGContextBeginPath(context);
//起始點設置為(0,0):注意這是上下文對應區(qū)域中的相對坐標蚓庭,
CGContextMoveToPoint(context, 0, 0);
//設置下一個坐標點
CGContextAddLineToPoint(context, 100, 100);
//設置下一個坐標點
CGContextAddLineToPoint(context, 0, 150);
//設置下一個坐標點
CGContextAddLineToPoint(context, 50, 180);
//連接上面定義的坐標點
CGContextStrokePath(context);
}
(void)setNeedsDisplay;
標記為需要重繪,異步調用drawRect
在UIView中,重寫drawRect: (CGRect) aRect方法,可以自己定義想要畫的圖案.且此方法一般情況下只會畫一次.也就是說這個drawRect方法一般情況下只會被掉用一次. 當某些情況下想要手動重畫這個View,只需要掉用[self setNeedsDisplay]方法即可.(void)setNeedsDisplayInRect:(CGRect)rect;
標記為需要局部重繪