ios开发 自定义btn_iOS一步步实现一个高度自定义UIButton控件
需求背景
日常開(kāi)發(fā)中UIButton的圖片與標(biāo)題默認(rèn)的布局是固定的,是在水平方向左右排列。但是我們會(huì)經(jīng)常需要更改image和title的位置來(lái)實(shí)現(xiàn)需求,這是個(gè)很常見(jiàn)的需求就不多說(shuō)了。所以下面就來(lái)談?wù)勅绾我徊讲降膶?shí)現(xiàn)一個(gè)高度自定義的UIButton控件。
實(shí)現(xiàn)思路
默認(rèn)情況下,在button有固定的寬高值的時(shí)候,image和title是以相對(duì)左右排列,整體居中于button來(lái)顯示的,如果沒(méi)有固定的寬高值,即大小自適應(yīng)的情況下,整個(gè)UIButton將自動(dòng)縮放到剛好可以容納image和title的大小。如圖所示:
自適應(yīng)大小.png
了解UIButton的各個(gè)屬性
在準(zhǔn)備自定義之前,我們需要了解UIButton的各個(gè)屬性都是怎么運(yùn)用和實(shí)現(xiàn)的,因?yàn)橐薷膖itle和image的位置與這些屬性是密不可分的。
因?yàn)檫@些都是基本的開(kāi)發(fā)知識(shí),我就不再過(guò)多敘述,分別以圖片來(lái)展示效果:
UIControlContentVerticalAlignment
UIControlContentVerticalAlignment各種效果.png
UIControlContentHorizontalAlignment
UIControlContentHorizontalAlignment各種效果.png
通過(guò)上面兩張圖可以清楚地看到UIControlContentVerticalAlignment和UIControlContentHorizontalAlignment在不同值下的效果,灰色背景的就是一個(gè)button的實(shí)際大小,center就是系統(tǒng)默認(rèn)的值,明顯的在兩種fill值下,圖片都出現(xiàn)了拉伸的情況,而且在水平fill下,圖片并沒(méi)有像垂直情況下水平鋪滿整個(gè)控件,image和title還重疊到了一起去。
UIEdgeInsets
UIButton的另一個(gè)重要的屬性就是這個(gè)了,稱之為偏移量,他分別有contentEdgeInsets,imageEdgeInsets,titleEdgeInsets三個(gè)相關(guān)屬性。
默認(rèn)情況下:contentEdgeInsets的top、left、bottom、right都是相對(duì)于button本身,控制著image和title整體的偏移量;
imageEdgeInsets的top、left、bottom相對(duì)于button,right相對(duì)于title,控制著image的相對(duì)偏移量;
titleEdgeInsets的top、bottom、right相對(duì)于button,left相對(duì)于image,控制著title的相對(duì)偏移量;
我用一張圖來(lái)解釋一下:
偏移量.png
上圖的正負(fù)值就代表偏移方向
我們想要的效果
寫(xiě)到這里,我們需要考慮一下我們的需求,我們并不是來(lái)分析button的實(shí)現(xiàn)原理,而是要實(shí)現(xiàn)一個(gè)自定義的button,自定義image和title的相對(duì)位置是最起碼的要求。相信看到這里大家也知道我們只需要修改imageEdgeInsets和titleEdgeInsets的值就可以隨意布局image和title的相對(duì)位置。比如左title右image,上image下title。
要實(shí)現(xiàn)這個(gè)需求有兩種方式:新建一個(gè)UIButton的分類UIButton + xx,在layoutSubviews里修改imageEdgeInsets和titleEdgeInsets的值。這種方式可以簡(jiǎn)單實(shí)現(xiàn)我們的基本需求,但如果想要添加更多的自定義屬性還需要通過(guò)runtime來(lái)實(shí)現(xiàn),好處就是擁有調(diào)用系統(tǒng)API的舒爽,直接UIButton調(diào)用,沒(méi)什么代碼侵入性。
封裝一個(gè)繼承自UIButton的CustomButton,可以自由添加自定義方法、屬性,在layoutSubviews里重置image和title的frame來(lái)實(shí)現(xiàn)不同的布局方式。
其實(shí)這兩種方式都可以實(shí)現(xiàn)自定義的效果,具體選用哪個(gè)就看你自己的需求了,我這里就第二種方式來(lái)實(shí)現(xiàn)一下。
上面所說(shuō)到的contentEdgeInsets,imageEdgeInsets,titleEdgeInsets默認(rèn)值都是zero,但是我們現(xiàn)在假設(shè)他們都有一個(gè)默認(rèn)值x;
button簡(jiǎn)易圖示.png
這里實(shí)現(xiàn)的思路就是通過(guò)self.bounds減去四周的偏移量先獲取整個(gè)content的實(shí)際size,再由contentSize減去image和title的對(duì)應(yīng)偏移量來(lái)獲取image和title的實(shí)際size。總之就是先獲取image和title的實(shí)際大小,然后根據(jù)不同的布局重置image和title的x、y坐標(biāo)和bound,從而得到對(duì)應(yīng)的frame,就可以實(shí)現(xiàn)自由布局了。
上面所說(shuō)的是button有固定寬高值的情況,如果button的寬高自適應(yīng),即調(diào)用sizeToFit方法時(shí),我們需要在- (CGSize)sizeThatFits:(CGSize)size內(nèi)針對(duì)不同情況重新計(jì)算出button的size,不然的話,系統(tǒng)會(huì)根據(jù)image和title的大小默認(rèn)返回它們左右排列的size,此時(shí)的size是錯(cuò)誤的,如圖:
沒(méi)做適配的結(jié)果.png
具體的布局分析思路就是這些了,因?yàn)榇a太多,就不在這里粘貼詳細(xì)代碼了,如果需要代碼的可以在文章底部找到demo的下載鏈接,demo里面也有詳細(xì)的注釋說(shuō)明。
但是,到這里我們只是自定義了image和title的相對(duì)布局,我們的目的是自定義整個(gè)UIButton,所以系統(tǒng)默認(rèn)的點(diǎn)擊效果,CALayer的所有默認(rèn)動(dòng)畫(huà)都需要移除掉,替換成我們自定義的layer效果。比如說(shuō)系統(tǒng)button的默認(rèn)高亮狀態(tài)下圖片顏色也會(huì)加深,這個(gè)其實(shí)很惡心,所以我們應(yīng)該移除掉,就像圖下所示:
系統(tǒng)button高亮狀態(tài).png
ok,現(xiàn)在我們來(lái)整理一下需要的常用屬性,分別為normal、highlighted、disabled這幾種狀態(tài)下的背景色,透明度變化,圖片的tintColor,邊框線的顏色,我們就針對(duì)這幾個(gè)點(diǎn)進(jìn)行修改。
下面粘貼幾塊代碼段大概展示一下:
highlighted邏輯-?(void)setHighlighted:(BOOL)highlighted?{
[super?setHighlighted:highlighted];
if?(highlighted?&&?!self.originBorderColor)?{
//?手指按在按鈕上會(huì)不斷觸發(fā)setHighlighted:,所以這里做了保護(hù),設(shè)置過(guò)一次就不用再設(shè)置了
self.originBorderColor?=?[UIColor?colorWithCGColor:self.layer.borderColor];
}
//?渲染背景色
if?(self.highlightedBackgroundColor?||?self.highlightedBorderColor)?{
[self?adjustsButtonHighlighted];
}
//?如果此時(shí)是disabled,則disabled的樣式優(yōu)先
if?(!self.enabled)?{
return;
}
//?自定義highlighted樣式
if?(self.adjustsButtonWhenHighlighted)?{
if?(highlighted)?{
self.alpha?=?0.5f;
}?else?{
[UIView?animateWithDuration:0.25f?animations:^{
self.alpha?=?1;
}];
}
}
}
enabled邏輯-?(void)setEnabled:(BOOL)enabled?{
[super?setEnabled:enabled];
if?(!enabled?&&?self.adjustsButtonWhenDisabled)?{
self.alpha?=?0.5f;
}?else?{
[UIView?animateWithDuration:0.25f?animations:^{
self.alpha?=?1;
}];
}
}
移除系統(tǒng)layer,添加自定義layer-?(void)adjustsButtonHighlighted?{
if?(self.highlightedBackgroundColor)?{
if?(!self.highlightedBackgroundLayer)?{
self.highlightedBackgroundLayer?=?[CALayer?layer];
[self.highlightedBackgroundLayer?FS_removeDefaultAnimations];
[self.layer?insertSublayer:self.highlightedBackgroundLayer?atIndex:0];
}
self.highlightedBackgroundLayer.frame?=?self.bounds;
self.highlightedBackgroundLayer.cornerRadius?=?self.layer.cornerRadius;
self.highlightedBackgroundLayer.backgroundColor?=?self.highlighted???self.highlightedBackgroundColor.CGColor?:?[UIColor?colorWithRed:1?green:1?blue:1?alpha:0].CGColor;
}
if?(self.highlightedBorderColor)?{
self.layer.borderColor?=?self.highlighted???self.highlightedBorderColor.CGColor?:?self.originBorderColor.CGColor;
}
}
因?yàn)樾枰罅康淖远x屬性來(lái)代替系統(tǒng)默認(rèn)屬性,雖然我很想在這里解釋每個(gè)屬性的用處,但是太麻煩了,所以還是建議直接下載demo,配合代碼看文章,代碼有詳細(xì)的注釋
這里就直接展示一下demo的效果圖:
FSCustomButtonDemo.gif
以前項(xiàng)目用到的時(shí)候,我也是直接網(wǎng)上找的一個(gè)庫(kù),不過(guò)那個(gè)庫(kù)包含內(nèi)容太多,很多都沒(méi)用,所以我將其中的部分代碼抽離了出來(lái)直接在項(xiàng)目中運(yùn)用,效果還可以很穩(wěn)定,所以最近抽時(shí)間將代碼從項(xiàng)目中抽離封裝了一下,寫(xiě)了一個(gè)demo上傳在github,需要的可以直接前往下載:
文章和demo中涉及到的知識(shí)點(diǎn):
如果對(duì)你有所幫助,就點(diǎn)個(gè)贊吧作者:PURE藍(lán)胖子
鏈接:http://www.jianshu.com/p/4603e9bbba56
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的ios开发 自定义btn_iOS一步步实现一个高度自定义UIButton控件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 485不用双绞线可以吗_加装迎宾踏板可以
- 下一篇: 点击定位到指定位置_以三菱PLC来举例说