iOS适配UIButton图文布局(上下左右):AlignButton

很少写技术博客,以前都是利用印象笔记和自己做Demo进行技术积累的。这篇文章算是首次写技术博客吧,不足之处,还望指正,以后也会渐渐利用简书和Github写一些技术心得和体会,也希望和大家多多交流,共同进步。

言归正传,iOS开发中,UIButton是很常用的控件,经常会碰到图片和文字结合的情况,系统默认的是图片在左,文字在右,并且中间间距很小,并不能满足我们的需要,于是封装了一个AlignButton控件,只需要指定alignTypepadding就能控制图片和文字的位置和间距,关键代码如下:

// left、right、top、bottom指的是title的位置
typedef NS_ENUM(NSInteger,AlignType)
{
    AlignType_TextRight  = 1,   //title在右边
    AlignType_TextLeft,         //title在左边
    AlignType_TextTop,          //title在上面
    AlignType_TextBottom,       //title在下面
};

@interface AlignButton : UIButton

@property (nonatomic,assign) AlignType alignType;   //文字title所在位置
@property (assign, nonatomic) CGFloat padding;      //图片和文字间距

@end

.m文件
- (void)layoutSubviews
{
    [super layoutSubviews];
    
    CGRect titleRect= [self titleRectForContentRect:self.bounds];
    CGRect imgRect = [self imageRectForContentRect:self.bounds];
    
    switch (self.alignType) {
        case AlignType_TextRight: //字体居右,图片居左
        {
            [self setImageEdgeInsets:UIEdgeInsetsMake(0, -self.padding, 0, 0)];
            [self setTitleEdgeInsets:UIEdgeInsetsMake(0, self.padding, 0, 0)];
            
            //针对RTL的情况,当然也可以判断isRTL,重新计算frame
        }
            break;
        case AlignType_TextLeft:    //文字居左,图片居右边
        {
            [self setImageEdgeInsets:UIEdgeInsetsMake(0, titleRect.size.width + self.padding, 0, -titleRect.size.width)];
            [self setTitleEdgeInsets:UIEdgeInsetsMake(0, -imgRect.size.width - self.padding, 0, imgRect.size.width)];
        }
            break;
        case AlignType_TextTop:    //文字居上,图片居下
        {
            self.titleLabel.textAlignment = NSTextAlignmentCenter;
            
            CGFloat height = imgRect.size.height + self.padding + titleRect.size.height;
            
            self.titleLabel.frame = CGRectMake(0, (CGRectGetHeight(self.frame) - height) / 2, CGRectGetWidth(self.frame), CGRectGetHeight(self.titleLabel.frame));
            
            self.imageView.frame = CGRectMake((CGRectGetWidth(self.frame) - imgRect.size.width) / 2, CGRectGetMaxY(self.titleLabel.frame) + self.padding, imgRect.size.width, imgRect.size.height);
        }
            break;
        case AlignType_TextBottom:  //文字居下,图片居上
        {
            self.titleLabel.textAlignment = NSTextAlignmentCenter;
            
            CGFloat height = imgRect.size.height + self.padding + titleRect.size.height;
            
            self.imageView.frame = CGRectMake((CGRectGetWidth(self.frame) - imgRect.size.width) / 2, (CGRectGetHeight(self.frame) - height) / 2, imgRect.size.width, imgRect.size.height);
            
            self.titleLabel.frame = CGRectMake(0, CGRectGetMaxY(self.imageView.frame) + self.padding, CGRectGetWidth(self.frame), CGRectGetHeight(self.titleLabel.frame));
        }
            break;
        default:
            break;
    }
    
    /* <#注释#>
     Note: that doesn’t actually flip the UIImage, but instead configures the image to be drawn flipped when it’s placed inside a UIImageView.
     注意:图片并没有翻转,当放置到imageView的时候image才会被翻转
     */
    if (isRTL()) {
        if (@available(iOS 9.0,*)) {
            self.imageView.image = [self.imageView.image imageFlippedForRightToLeftLayoutDirection];
        }
    }
}

void RTLMethodSwizzling (id obj,SEL oriMethod,SEL newMethod){
    Method ori = class_getInstanceMethod([obj class], oriMethod);
    Method new = class_getInstanceMethod([obj class], newMethod);
    method_exchangeImplementations(ori, new);
}

//RTL布局:hook方法setImageEdgeInsets:和setTitleEdgeInsets:
+ (void)load
{
    if (isRTL()) {
        [AlignButton swizzlingOriMethod:@selector(setContentEdgeInsets:) newMethod:@selector(rtl_setContentEdgeInsets:)];

        [AlignButton swizzlingOriMethod:@selector(setImageEdgeInsets:) newMethod:@selector(rtl_setImageEdgeInsets:)];

        [AlignButton swizzlingOriMethod:@selector(setTitleEdgeInsets:) newMethod:@selector(rtl_setTitleEdgeInsets:)];
    }
}

+ (void)swizzlingOriMethod:(SEL)ori newMethod:(SEL)new
{
    Method originalMethod = class_getInstanceMethod([self class], ori);
    Method newMethod = class_getInstanceMethod([self class], new);
    method_exchangeImplementations(originalMethod, newMethod);
}

- (void)rtl_setContentEdgeInsets:(UIEdgeInsets)contentEdgeInsets {
    [self rtl_setContentEdgeInsets:RTLEdgeInsetsWithInsets(contentEdgeInsets)];
}

- (void)rtl_setImageEdgeInsets:(UIEdgeInsets)imageEdgeInsets {
    [self rtl_setImageEdgeInsets:RTLEdgeInsetsWithInsets(imageEdgeInsets)];
}

- (void)rtl_setTitleEdgeInsets:(UIEdgeInsets)titleEdgeInsets {
    [self rtl_setTitleEdgeInsets:RTLEdgeInsetsWithInsets(titleEdgeInsets)];
}

安装:

1、使用Cocoapods安装:

platform :ios
pod 'AlignButton'

2、手动安装:
直接拷贝AlignButton文件夹(包含AlignButton.h、AlignButton.m文件)到工程项目中.

使用: 引用头文件:#import "AlignButton.h"

#import "AlignButton.h"

@interface ViewController ()

@property (weak, nonatomic) IBOutlet AlignButton *rightBtn;
@property (weak, nonatomic) IBOutlet AlignButton *leftBtn;
@property (weak, nonatomic) IBOutlet AlignButton *topBtn;
@property (weak, nonatomic) IBOutlet AlignButton *bottomBtn;
@property (weak, nonatomic) IBOutlet AlignButton *imageBtn;
@property (weak, nonatomic) IBOutlet AlignButton *titleBtn;

@end

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    
    self.rightBtn.alignType = AlignType_TextRight;
    self.rightBtn.padding = 10;
    
    self.rightBtn.imageView.backgroundColor =  [UIColor cyanColor];
    self.rightBtn.titleLabel.backgroundColor =  [UIColor redColor];

    self.leftBtn.imageView.backgroundColor =  [UIColor cyanColor];
    self.leftBtn.titleLabel.backgroundColor =  [UIColor redColor];
    
    self.leftBtn.alignType = AlignType_TextLeft;
    self.leftBtn.padding = 10;
    
    self.topBtn.alignType = AlignType_TextTop;
    self.topBtn.padding = 10;
    
    self.bottomBtn.alignType = AlignType_TextBottom;
    self.bottomBtn.padding = 10;
}

效果如图:

image.png

RTL布局: 做国际化语言适配时,可能会遇到RTL(RightToLeft)布局的情况,大部分国家语言读取都是从左向右LTR(LeftToRight),但有些国家的语言读取是从右向左RTL读取的,如阿拉伯语。
解决思路:判断是否需要RTL布局,hook UIButton的方法setImageEdgeInsets:setTitleEdgeInsets:来达到RTL重新布局的效果:

image.png

Github源码下载

转载请注明出处,谢谢!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,820评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,648评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,324评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,714评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,724评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,328评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,897评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,804评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,345评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,431评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,561评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,238评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,928评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,417评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,528评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,983评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,573评论 2 359

推荐阅读更多精彩内容

  • 好累好累好累 朋友远道而来,周末晚上的大雨着实让人哭笑不得,淋的要死,没有公交车,打不上车,手机没电,哈哈,还觉得...
    小仙女1020阅读 152评论 2 3
  • HBuilderX用户设置,自定义快捷键 编辑 command+c 复制command+v 粘贴command+s...
    大Q本Q阅读 2,186评论 0 0
  • 第三十六章 骷髅神兵(2) 也就是在骸骨的旁边,离得很近的一处墙壁上,靠近底部的位置,出现了一个洞.如果不是仔细看...
    笑君杀手阅读 299评论 0 0
  • 越成长 感动越多 感谢老师的倾心关怀
    丁予阅读 149评论 0 0