imageEdgeInsets && titleEdgeInsets

原文鏈接

前言

平常開發(fā)中玷禽,UIButton是使用頻率非常高的控件。除了可點擊之外呀打,還因為其能夠同時顯示文案和圖片矢赁。默認(rèn)的UIButton,圖片在左贬丛,文字在右撩银,且文字是緊緊挨著圖片的。大多數(shù)情況下豺憔,UIButton已經(jīng)可以滿足需求了额获,然而够庙,總有一些意外……比如,設(shè)計讓文字和圖片不要離得很近抄邀;比如首启,設(shè)計讓文字在左,圖片在右撤摸;比如毅桃,設(shè)計讓圖片在上,文字在下……

這時候就會用到本文的主角:imageEdgeInsets和titleEdgeInsets了准夷。使用imageEdgeInsets和titleEdgeInsets時钥飞,可能或多或少的都會有一種感覺,就是難以捉摸衫嵌,每次都是嘗試多次才能達(dá)到一個良好的效果读宙。再徹底會使用imageEdgeInsets和titleEdgeInsets之前,我們先來分析下面對的問題楔绞。

圖片和文字保持間距

首先面臨的第一個問題就是圖片和文字之間保持一個距離结闸。其實碰到這樣的需求解決方法有很多,如果對imageEdgeInsets和titleEdgeInsets不熟悉酒朵,完全沒必要使用這兩個屬性桦锄。

圖片右側(cè)透明

UIButton 默認(rèn)圖片在左,文字在右蔫耽,且文字和圖片緊鄰结耀,現(xiàn)在的需求是圖片和文字之間留有一定的間距。一種方法是匙铡,如果設(shè)計提供的圖片右側(cè)有一些透明的地方图甜,那么整體給用戶的感覺就是圖片和文字之間有一定的間距。只不過這種方法需要讓設(shè)計切圖鳖眼。

文案加空格

其實如果只是想讓圖片和文字之間有一定間距黑毅,不用設(shè)計切圖,代碼完全可以控制钦讳,而且特別簡單矿瘦。方法就是在文案的前面加空格,比如說本來要顯示的文案是"聯(lián)系我們",程序中可以設(shè)置為"????? 聯(lián)系我們",這樣最終展示給用戶的效果圖片和文件之間也有一定的間距蜂厅。這種方法完全是開發(fā)人員可控的匪凡。

圖片和文字位置調(diào)整

圖片和文字的位置調(diào)整膊畴,主要是指圖片在右掘猿,文字在左,或者圖片在上唇跨,文字在下這兩種情況稠通,目前還沒有碰到過文字在上衬衬,圖片在下的需求。如果設(shè)計的圖是圖片和文字的位置有了調(diào)整改橘,那么僅僅靠增加圖片透明度滋尉、文案加空格等類似的方法是滿足不了需求的。

解決方法有兩種飞主,一種是使用UIView狮惜,另外就是使用imageEdgeInsets和titleEdgeInsets。

使用UIView解決

使用UIView的思路非常簡單碌识。就是使用三個控件碾篡,一個UIView作為父控件,一個UILabel用來顯示內(nèi)容筏餐,一個UIImageView用來顯示圖片开泽。由于UILabel和UIImageView都是我們自己寫的,其frame我們可以隨意控制魁瞪,圖片是在左穆律、在右,還是在上导俘,都是可以控制的峦耘。

至于UIButton的點擊事件,因為UIView不具備點擊事件旅薄,我們可以給UIView增加手勢UITapGestureRecognizer,用來模擬點擊行為贡歧。看上去完美解決了這個問題赋秀,但是這種方案是有缺點的利朵,看一下:

  1. 首先這種方法是使用了3個控件,而如果使用UIButton猎莲,只需要使用1個控件绍弟。雖然UIButton內(nèi)部也包含了一個UIImageView和一個UILabel,性能上可能沒有太大的差距著洼,但是這種寫法麻煩啊樟遣。本來使用UIButton5行代碼就可以搞定了,結(jié)果使用UIView的形式身笤,寫了20行代碼豹悬,實現(xiàn)比較繁瑣。

  2. 雖然可以給UIView添加手勢模擬點擊行為液荸,但是瞻佛,UIView是沒有高亮狀態(tài)的。UIButton默認(rèn)是有普通狀態(tài)和高亮狀態(tài),點擊時會顯示默認(rèn)的高亮狀態(tài)伤柄,這個效果UIView是實現(xiàn)不了的绊困。如果想實現(xiàn),需要再增加更多的代碼适刀。

可以說秤朗,使用UIView能夠解決問題,但是解決方法不夠優(yōu)雅笔喉。

imageEdgeInsets和titleEdgeInsets

蘋果可能已經(jīng)考慮到了開發(fā)者會有這樣的需求取视,于是提供了imageEdgeInsets和titleEdgeInsets兩個屬性。然而常挚,由于蘋果沒有介紹這兩個屬性的原理贫途,對兩個屬性的描述又不是特別清晰,導(dǎo)致使用起來難度較大待侵,對于經(jīng)驗不足的開發(fā)者丢早,每次使用都要嘗試多次。

先來看下兩者的定義秧倾。

imageEdgeInsets和titleEdgeInsets的定義

imageEdgeInsets和titleEdgeInsets的定義在UIButton.h中怨酝,如下:


@property(nonatomic)          UIEdgeInsets titleEdgeInsets;                // default is UIEdgeInsetsZero

@property(nonatomic)          UIEdgeInsets imageEdgeInsets;                // default is UIEdgeInsetsZero

可以看到,imageEdgeInsets和titleEdgeInsets都是UIEdgeInsets類型那先,且默認(rèn)取值是UIEdgeInsetsZero农猬。看一下UIEdgeInsets的定義:


typedef struct UIEdgeInsets {

    CGFloat top, left, bottom, right;  // specify amount to inset (positive) for each of the edges. values can be negative to 'outset'

} UIEdgeInsets;

UIEdgeInsets是一個結(jié)構(gòu)體售淡,四個值分別是上斤葱、左、下揖闸、右揍堕,值可以為正,也可以為負(fù)汤纸。

在了解imageEdgeInsets和titleEdgeInsets的使用之前衩茸,有三點一定要明白:

  1. 無論是imageEdgeInsets還是titleEdgeInsets,都是和原控件的位置相比較的贮泞。imageEdgeInsets是和原imageView的位置比較楞慈,titleEdgeInsets是和原label的位置比較

  2. imageEdgeInsets和titleEdgeInsets中的值為正啃擦,則是該方向上的擴(kuò)張囊蓝,如果值為負(fù),則是該方向上的縮減令蛉。舉例來說聚霜,對于左側(cè),擴(kuò)張是更向左,即frame的x值減懈┪;對于右側(cè)擴(kuò)張是更向右运杭,frame的width值更大夫啊。

  3. UIEdgeInsets是對稱的,左右對稱辆憔,上下對稱撇眯。因此,在設(shè)置imageEdgeInsets和titleEdgeInsets時盡量也要對稱虱咧,比如[0,-5,0,5],左右對稱熊榛,同理上下也要對稱。之所以要對稱腕巡,是為了不拉伸imageView和titleLabel玄坦。

imageEdgeInsets和titleEdgeInsets的使用

有了上面的了解和介紹,來看一下使用imageEdgeInsets和titleEdgeInsets如何解決文中最開始提到的問題绘沉。

首先是圖片和文字之間保持間距煎楣。圖片和文字保持間距有兩種處理方式,一種是圖片左移车伞,一種是文字右移择懂。實際上,最開始提到的給圖片右側(cè)增加透明度以及文案加空格正是分別對應(yīng)了圖片左移和文字右移另玖。如果使用imageEdgeInsets和titleEdgeInsets困曙,對應(yīng)的也是這兩種處理方式。我們可以調(diào)整imageEdgeInsets來使圖片左移谦去,同理也可以調(diào)整titleEdgeInsets來使圖片右移慷丽,可以達(dá)到相同的效果。

寫代碼驗證一下鳄哭。首先看一下普通狀態(tài)的UIButton:

為了后續(xù)方便盈魁,先定義一些宏:


#define    DefaultFont    [UIFont systemFontOfSize:20.0f]

#define    DefaultImage    [UIImage imageNamed:@"mail"]

#define    DefaultText    @"技術(shù)支持"

生成一個普通的UIButton:


- (UIButton *)createBtn

{

    UIButton *btn = [[UIButton alloc] init];

    [btn setTitle:DefaultText forState:UIControlStateNormal];

    btn.titleLabel.font = DefaultFont;

    [btn setImage:DefaultImage forState:UIControlStateNormal];

    [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];

    btn.titleLabel.backgroundColor = [UIColor redColor];

    return btn;

}

將普通button顯示到屏幕上:


UIButton *btn0 = [self createBtn];

[btn0 sizeToFit];

btn0.frame = CGRectMake(100,100,btn0.frame.size.width,btn0.frame.size.height);

[self.view addSubview:btn0];

看一下效果:

image

可以看到圖片和文字是緊緊貼在一起的。

調(diào)整imageEdgeInsets的值窃诉,使兩者保持一定間距杨耙。像上文說的,讓圖片左移飘痛,既然是左移珊膜,相當(dāng)于是左側(cè)擴(kuò)張,為了不拉伸圖片,對應(yīng)的右側(cè)就要縮減。也就是說左側(cè)的值為負(fù)描沟,右側(cè)的值為正饭寺,且兩者的絕對值要相等崔兴。


UIButton *btn1 = [self createBtn];

btn1.imageEdgeInsets = UIEdgeInsetsMake(0, -5, 0, 5);

[btn1 sizeToFit];

btn1.frame = CGRectMake(100,200,btn1.frame.size.width,btn1.frame.size.height);

[self.view addSubview:btn1];

看一下效果:

[圖片上傳失敗...(image-af7662-1545731919275)]

可以看到圖片和文字之間有了一定的間距厚脉。

接下來再來看一下蜕猫,使用imageEdgeInsets和titleEdgeInsets箫踩,讓文字在左塑陵,圖片在右感憾,為達(dá)到這種效果,imageEdgeInsets和titleEdgeInsets的值都需要調(diào)整令花。先看下圖:

[圖片上傳失敗...(image-7c71bb-1545731919275)]

默認(rèn)圖片在左阻桅,文字在右,現(xiàn)在要將文字放到左側(cè)兼都,圖片放到右側(cè)嫂沉。從上圖可以看出,最終文字是向左移了扮碧,圖片是向右移了趟章。根據(jù)前面的介紹,文字向左側(cè)移動慎王,那么titleEdgeInsets中的left字段應(yīng)該為負(fù)尤揣,right字段應(yīng)該為正,那么應(yīng)該移動多少呢柬祠?從上面的圖也很清晰的看到北戏,移動的距離就是圖片的寬度。再看圖片漫蛔,圖片整體右移嗜愈,因此imageEdgeInsets中的left字段應(yīng)該為正,right字段應(yīng)該為負(fù)莽龟,右移的距離是多少呢蠕嫁?正好是文字的寬度。

看一下實現(xiàn)代碼:


UIButton *btn2 = [self createBtn];

UILabel *label = [[UILabel alloc] init];

label.font = DefaultFont;

label.text = DefaultText;

[label sizeToFit];

btn2.imageEdgeInsets = UIEdgeInsetsMake(0, label.frame.size.width, 0, label.frame.size.width * -1);

btn2.titleEdgeInsets = UIEdgeInsetsMake(0, DefaultImage.size.width * -1, 0, DefaultImage.size.width);

[btn2 sizeToFit];

btn2.frame = CGRectMake(100,300,btn2.frame.size.width,btn2.frame.size.height);

[self.view addSubview:btn2];

效果如下:

image

如果想讓兩者之間有間距毯盈,也很簡單剃毒,移動時只需要把值調(diào)大一些即可:


UIButton *btn3 = [self createBtn];

btn3.imageEdgeInsets = UIEdgeInsetsMake(0, label.frame.size.width, 0, label.frame.size.width * -1);

btn3.titleEdgeInsets = UIEdgeInsetsMake(0, DefaultImage.size.width * -1 - 5, 0, DefaultImage.size.width + 5);

[btn3 sizeToFit];

btn3.frame = CGRectMake(100,400,btn3.frame.size.width,btn3.frame.size.height);

[self.view addSubview:btn3];

讓兩者之間保持間距為5,效果如下:

image

再來看最后一種效果搂赋,即圖片在上赘阀,文字在下。為達(dá)到這樣的效果脑奠,我們可以將圖片向上移基公,文字的y值保持不變;也可以圖片保持不變宋欺,文字的位置下移轰豆;可以達(dá)到相同的效果胰伍。如下圖:

image

當(dāng)然,也可以圖片上移一部分酸休,文字下移一部分骂租,只是沒有這個必要。

我們以圖片上移為例斑司。圖片上移渗饮,說明imageView的edgeInsets的top值擴(kuò)張,即top為負(fù)陡厘,那么bottom值為正抽米。移動的距離正好是圖片的高度特占。


btn4.imageEdgeInsets = UIEdgeInsetsMake(-DefaultImage.size.height, 0, DefaultImage.size.height, 0);

為了保持美觀糙置,我們還需要讓titleLabel和imageView的中心點對齊,即titleLabel左移。titleLabel左移是目,說明titleLabel的edgeInsets的left擴(kuò)張谤饭,值為負(fù),right值為正懊纳。titleLabel左移的距離需要計算揉抵。從上圖可以看出,titleLabel原來的x值正好是imageView.width嗤疯,現(xiàn)在的x值是(imageView.width - titleLabel.width) * 0.5,因此冤今,titleLabel需要左移的距離是:


CGFloat diff5X = DefaultImage.size.width - (DefaultImage.size.width - label.frame.size.width) * 0.5;

通常情況下,titleLabel的高度和imageView的高度是不同的茂缚,如下圖:

[圖片上傳失敗...(image-6c05b6-1545731919276)]

titleLabel和imageView豎直方向的中心點一致戏罢,但是兩者的高度是不同的。如果titleLabel的y值不調(diào)整脚囊,那么圖片和文字之間會有一定的間距龟糕,這個間距對于開發(fā)者來說不好控制。因此悔耘,最好的辦法是將titleLabel向上調(diào)整讲岁,和imageView緊鄰。調(diào)整的距離是多少呢衬以?根據(jù)上圖也很容易看出來


CGFloat diffY = (DefaultImage.size.height - label.frame.size.height) * 0.5;

完整代碼如下:


UIButton *btn4 = [self createBtn];

btn4.imageEdgeInsets = UIEdgeInsetsMake(-DefaultImage.size.height, 0, DefaultImage.size.height, 0);

CGFloat diff = DefaultImage.size.width - (DefaultImage.size.width - label.frame.size.width) * 0.5;

CGFloat diffY = (DefaultImage.size.height - label.frame.size.height) * 0.5;

btn4.titleEdgeInsets = UIEdgeInsetsMake(-diffY, diff * -1, diffY, diff);

[btn4 sizeToFit];

btn4.frame = CGRectMake(20,550,btn4.frame.size.width,btn4.frame.size.height);

[self.view addSubview:btn4];

效果圖如下:

image

如果想讓文字和圖片之間保持間距缓艳,只需要把文字向下移動一些即可,代碼如下:


UIButton *btn5 = [self createBtn];

btn5.imageEdgeInsets = UIEdgeInsetsMake(-DefaultImage.size.height, 0, DefaultImage.size.height, 0);

CGFloat diff5X = DefaultImage.size.width - (DefaultImage.size.width - label.frame.size.width) * 0.5;

CGFloat diff5Y = (DefaultImage.size.height - label.frame.size.height) * 0.5;

btn5.titleEdgeInsets = UIEdgeInsetsMake(-diffY + 5, diff * -1, diffY - 5, diff);

[btn5 sizeToFit];

btn5.frame = CGRectMake(200,550,btn5.frame.size.width,btn5.frame.size.height);

[self.view addSubview:btn5];

效果圖如下:

image

封裝

了解了imageEdgeInsets和titleEdgeInsets如何使用后看峻,之后再碰到文中開頭提到打需求郎任,相信大家已經(jīng)可以從容應(yīng)對了。然而备籽,imageEdgeInsets和titleEdgeInsets實在難以理解舶治,一段時間不用分井,可能就忘了應(yīng)該如何調(diào)整偏移量……每次使用之前都研究一下其偏移量的原理,好像又有點浪費時間霉猛。

為了方便日常開發(fā)尺锚,我封裝了ACEdgeInsetsBtn,ACEdgeInsetsBtn是UIButton的子類惜浅,主要目的就是解決UIButton中文字瘫辩、圖片有間隔、或者位置調(diào)整的問題坛悉。使用也很簡單伐厌,只需要傳入image,文案,字體裸影,imageView和titleLabel的間距挣轨,類型即可,如下:


/**

初始化方法

@param image btn所要顯示的image

@param text btn所要顯示的text

@param font btn的字體信息

@param edgeInsetsType 圖片的位置類型

@param space image和文字之間的間距

@return    返回實例button對象

*/

- (instancetype)initWithImage:(UIImage *)image text:(NSString *)text font:(UIFont *)font edgeInsetsType:(ACEdgeInsetsBtnType)edgeInsetsType space:(CGFloat)space;

ACEdgeInsetsBtnType是一個枚舉類型轩猩,目前包含了圖片左文子右卷扮、圖片右文字左、圖片上文字下三種類型均践,如下:


/**

btn類型晤锹,以圖片的位置為標(biāo)準(zhǔn)

*/

typedef NS_ENUM(NSInteger, ACEdgeInsetsBtnType){

    // 普通狀態(tài),即圖片在左彤委,文字在右

    ACEdgeInsetsBtnTypeNormal = 1,

    // 圖片在右鞭铆,文字在左

    ACEdgeInsetsBtnTypeRight ,

    // 圖片在上,文字在下

    ACEdgeInsetsBtnTop

};

傳入對應(yīng)的參數(shù)焦影,直接生成期望的Btn:


ACEdgeInsetsBtn *btn = [[ACEdgeInsetsBtn alloc] initWithImage:DefaultImage text:DefaultText font:DefaultFont edgeInsetsType:ACEdgeInsetsBtnTypeNormal space:5];

[btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];

btn.frame = CGRectMake(50,80,btn.frame.size.width,btn.frame.size.height);

[self.view addSubview:btn];

項目放在了github上车遂,地址

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末偷办,一起剝皮案震驚了整個濱河市艰额,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌椒涯,老刑警劉巖柄沮,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異废岂,居然都是意外死亡祖搓,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進(jìn)店門湖苞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拯欧,“玉大人,你說我怎么就攤上這事财骨「渥鳎” “怎么了藏姐?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長该贾。 經(jīng)常有香客問我羔杨,道長,這世上最難降的妖魔是什么杨蛋? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任兜材,我火速辦了婚禮,結(jié)果婚禮上逞力,老公的妹妹穿的比我還像新娘曙寡。我一直安慰自己,他們只是感情好寇荧,可當(dāng)我...
    茶點故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布举庶。 她就那樣靜靜地躺著,像睡著了一般砚亭。 火紅的嫁衣襯著肌膚如雪灯变。 梳的紋絲不亂的頭發(fā)上殴玛,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天捅膘,我揣著相機與錄音,去河邊找鬼滚粟。 笑死寻仗,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的凡壤。 我是一名探鬼主播署尤,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼亚侠!你這毒婦竟也來了曹体?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤硝烂,失蹤者是張志新(化名)和其女友劉穎箕别,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體滞谢,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡串稀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了狮杨。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片母截。...
    茶點故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖橄教,靈堂內(nèi)的尸體忽然破棺而出清寇,到底是詐尸還是另有隱情喘漏,我是刑警寧澤,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布华烟,位于F島的核電站陷遮,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏垦江。R本人自食惡果不足惜帽馋,卻給世界環(huán)境...
    茶點故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望比吭。 院中可真熱鬧绽族,春花似錦、人聲如沸衩藤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赏表。三九已至检诗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間瓢剿,已是汗流浹背逢慌。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留间狂,地道東北人攻泼。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像鉴象,于是被迫代替她去往敵國和親忙菠。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,665評論 2 354

推薦閱讀更多精彩內(nèi)容