美文网首页iOS学习专题
iOS 左文右图的按钮

iOS 左文右图的按钮

作者: sergeant | 来源:发表于2019-04-19 14:42 被阅读1次

    iOS 按钮默认布局方式是左图右文,但是有时候我们需要左文右图的布局。

    下面总结了几种方案。要结论的同学直接看方案五。

    方案一

    直接使用UIButton,设置其semanticContentAttribute为UISemanticContentAttributeForceRightToLeft。即布局改为从右至左。这个属性原本用于阿拉伯文这种从右向左写的语言。

    button.semanticContentAttribute = UISemanticContentAttributeForceRightToLeft;
    

    优点:

    • 方便快捷。

    缺点:

    • 需要iOS 9.0及以上。
    • 需要纯代码,我在xib测试无效。

    方案二

    直接使用UIButton,设置其titleEdgeInsets或imageEdgeInsets。也就是让图片右移文本的宽度,文本左移图片的宽度。

    button.titleEdgeInsets = UIEdgeInsetsMake(0, -button.imageView.frame.size.width, 0, button.imageView.frame.size.width);
    button.imageEdgeInsets = UIEdgeInsetsMake(0, button.titleLabel.frame.size.width, 0, -button.titleLabel.frame.size.width);
    

    优点:

    • 代码与xib均可以使用。

    缺点:

    • 文本改变后需要重新计算。
    • 如果使用自动布局,需要frame确定后才能计算,或者自己用 boundingRectWithSize:options:attributes:context: 计算出title的size。

    方案三

    方案三是方案二的变种,即派生一个UIButton的子类,来实现titleEdgeInsets与imageEdgeInsets的自动更新。

    - (void)layoutSubviews {
        [super layoutSubviews];
        
        [self updateEdgeInsets];
    }
    
    - (void)updateEdgeInsets {
        self.titleEdgeInsets = UIEdgeInsetsMake(0, -self.imageView.frame.size.width, 0, self.imageView.frame.size.width);
        self.imageEdgeInsets = UIEdgeInsetsMake(0, self.titleLabel.frame.size.width, 0, -self.titleLabel.frame.size.width);
    }
    

    之所以在layoutSubviews中调用更新方法,是因为无论是自动布局还是更改内容都会触发这个方法,并且子视图的frame都已经确定。

    优点:

    • 代码与xib均可以使用,且不像方案二那样需要手动重新计算。

    缺点:

    • 碰到那种需要调整文本与图片间距的需求,就不能使用titleEdgeInsets与imageEdgeInsets属性了,需要额外添加属性来处理。

    方案四

    派生一个UIButton的子类,通过重载 titleRectForContentRect:imageRectForContentRect: 来分别指定文本和图片的显示区域。

    @interface FCReverseButton ()
    
    @property (nonatomic, assign) CGRect originalImageRect; // 原图片区域
    @property (nonatomic, assign) CGRect originalTitleRect; // 原文本区域
    
    @end
    
    @implementation FCReverseButton
    
    - (CGRect)titleRectForContentRect:(CGRect)contentRect {
        if (CGRectIsEmpty(self.originalTitleRect)) {
            self.originalTitleRect = [super titleRectForContentRect:contentRect];
        }
    
        if (CGRectIsEmpty(self.originalTitleRect) || CGRectIsEmpty(self.originalImageRect)) {
            return self.originalTitleRect;
        } else {
            CGFloat height = MAX(CGRectGetHeight(self.originalTitleRect), CGRectGetHeight(self.originalImageRect));
            return CGRectMake(contentRect.origin.x + self.titleEdgeInsets.right, contentRect.origin.y + (height - CGRectGetHeight(self.originalTitleRect)) / 2, CGRectGetWidth(self.originalTitleRect), CGRectGetHeight(self.originalTitleRect));
        }
    }
    
    - (CGRect)imageRectForContentRect:(CGRect)contentRect {
        if (CGRectIsEmpty(self.originalImageRect)) {
            self.originalImageRect = [super imageRectForContentRect:contentRect];
        }
    
        if (CGRectIsEmpty(self.originalTitleRect) || CGRectIsEmpty(self.originalImageRect)) {
            return self.originalImageRect;
        } else {
            CGFloat height = MAX(CGRectGetHeight(self.originalTitleRect), CGRectGetHeight(self.originalImageRect));
            return CGRectMake(contentRect.origin.x + CGRectGetWidth(self.originalTitleRect) + self.imageEdgeInsets.right, contentRect.origin.y + (height - CGRectGetHeight(self.originalImageRect)) / 2, CGRectGetWidth(self.originalImageRect), CGRectGetHeight(self.originalImageRect));
        }
    }
    
    @end
    

    优点:

    • 可以兼容titleEdgeInsets与imageEdgeInsets属性,内容变化时会自动重新计算。

    缺点

    • 不能在xib中使用。(在xib中使用时 [super titleRectForContentRect:contentRect] 返回的rect的size是zero,很奇怪。)

    方案五

    在坐标系的层面翻转按钮的X轴,再分别将titleLabel和imageView的X轴翻转回来。可以直接对UIButton进行操作,也可以派生一个子类。建议派生一个子类。

    - (instancetype)initWithFrame:(CGRect)frame {
        self = [super initWithFrame:frame];
        if (self) {
            [self horizontalReverse];
        }
        return self;
    }
    
    - (instancetype)initWithCoder:(NSCoder *)aDecoder {
        self = [super initWithCoder:aDecoder];
        if (self) {
            [self horizontalReverse];
        }
        return self;
    }
    
    // 水平翻转
    - (void)horizontalReverse {
        self.transform = CGAffineTransformMakeScale(-1, 1);
        self.imageView.transform = CGAffineTransformMakeScale(-1, 1);
        self.titleLabel.transform = CGAffineTransformMakeScale(-1, 1);
    }
    

    优点

    • 不多说了,悄悄告诉你我用的这个方案。

    缺点

    • 在通过titleEdgeInsets与imageEdgeInsets来调整间距的时候,需要反着来,即左移的结果是右移,右移的结果是左移。

    参考:
    How do I put the image on the right side of the text in a UIButton?

    相关文章

      网友评论

        本文标题:iOS 左文右图的按钮

        本文链接:https://www.haomeiwen.com/subject/pzhqgqtx.html