iPhone UIButton - 图片位置

124

我有一个文本为“Explore the app”的UIButton和一个UIImage图像。

Interface Builder中,它看起来像:

[ (>) Explore the app ]

但我需要把这个UIImage放在文本之后:

[ Explore the app (>) ]

我该如何将 UIImage 向右移动?


你也可以使用Interface Builder。请查看我的答案:https://dev59.com/gXE85IYBdhLWcg3wdDSz#22725345 - n8tr
1
只需使用几行代码即可使用此子类:https://github.com/k06a/RTLButton - k06a
16个回答

164

我的解决方案非常简单

[button sizeToFit];
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);

4
这个很好用!但很难理解边缘插入的概念。你有什么想法,为什么我们需要同时设置左和右的边缘插入?理论上,如果我将标题移到左边,将图像移到右边,那就足够了。为什么我还需要同时设置左和右边缘插入呢? - PokerIncome.com
3
我找到的最佳解决方案。 - Bimawa
2
这个答案完美地解决了问题。被采纳的答案是正确的,并且指向了正确的API文档,但这是复制粘贴的解决方案,可以满足OP的要求。 - mclaughj
当您开始更改按钮文本时,情况会变得有些复杂。在这种情况下,我更喜欢使用子类化的解决方案。 - Brad G
谢谢你向我展示如何将等宽应用于左右两侧,虽然我并不完全理解它的工作原理(因为有时它会影响大小和起点),但我已经能够使用这种方法解决类似的问题。 - Toby

138

在iOS 9及以上版本中,似乎强制视图的语义是实现这一点的简单方法。

输入图片描述

或者可以通过编程来实现:

button.semanticContentAttribute = .ForceRightToLeft

4
虽然我很喜欢你的回答(+1),但不得不说这可能不是“正确”的方法,但它是其中最简单的之一。 - farzadshbfn
@farzadshbfn 为什么这不是“正确”的做法? - Samman Bikram Thapa
3
@SammanBikramThapa 在我看来,正确的方法应该是子类化UIButton并重写layoutSubviews,并在我们的布局逻辑中尊重“semanticContentAttribute”,而不是改变“semanticContentAttribute”本身。(改变语义方法,在国际化方面效果不佳) - farzadshbfn
“right-to-left”是用于像阿拉伯语这样的“从右到左”的语言。因此,将其用于其他用途是不好的方法。 - Vyachaslav Gerchicov
@Alvivi 它也有顶部按钮吗? - kiran
显示剩余2条评论

86

设置imageEdgeInsettitleEdgeInset来移动图像中的组件。您也可以使用这些图形创建一个全尺寸的按钮,并将其用作按钮的背景图像(然后使用titleEdgeInsets来移动标题位置)。


8
仅仅设置插图比实现子类要少得多。这就是插图的全部意义。操纵子视图(您未创建的)的框架感觉更像一个hack。 - Kim
6
@kimsnarf,真的吗?每当您对图像大小或标题长度进行微小更改时,调整插图比起修改代码要简单得多(而且“不那么”矫揉造作)? - Kirk Woll

54

Raymond W的回答最好。使用自定义的layoutSubviews子类化UIButton。这样做非常简单,以下是对我有效的一个layoutSubviews实现:

- (void)layoutSubviews
{
    // Allow default layout, then adjust image and label positions
    [super layoutSubviews];

    UIImageView *imageView = [self imageView];
    UILabel *label = [self titleLabel];

    CGRect imageFrame = imageView.frame;
    CGRect labelFrame = label.frame;

    labelFrame.origin.x = imageFrame.origin.x;
    imageFrame.origin.x = labelFrame.origin.x + CGRectGetWidth(labelFrame);

    imageView.frame = imageFrame;
    label.frame = labelFrame;
}

2
如果你需要管理很多按钮,这种方式会更好,但我只需要改变一个按钮 :) - Pavel Yakimenko
2
如果按钮图像为nil,则标签会错位,可能是因为UIImageView未插入(在iOS6.0上测试)。仅当imageView.image不为nil时,您应考虑编辑框架。 - Scakko
2
我建议对这个答案进行以下改进,以使两个视图保持居中:'CGFloat cumulativeWidth = CGRectGetWidth(imageFrame) + CGRectGetWidth(labelFrame) + 10; CGFloat excessiveWidth = CGRectGetWidth(self.bounds) - cumulativeWidth;labelFrame.origin.x = excessiveWidth / 2; imageFrame.origin.x = CGRectGetMaxX(labelFrame) + 10;' - i-konov
这在我的iOS 7上出问题了。其他人呢?在iOS 8上运行良好。 - rounak
1
完全不支持iOS7,你的问题就会消失。无论如何,你都不应该支持它。 - Gil Sand

30

如何通过继承 UIButton 并覆盖 layoutSubviews 方法来实现布局?

接着可以处理 self.imageViewself.titleLabel 的位置。


4
这比其他所有建议都容易得多(如上面的建议),那些建议要求使用手调整插图来正确放置所有内容。 - Steven Kramer

14

另一个简单的方法(不仅限于iOS 9)是子类化UIButton并重写这两个方法。

override func titleRectForContentRect(contentRect: CGRect) -> CGRect {
    var rect = super.titleRectForContentRect(contentRect)
    rect.origin.x = 0
    return rect
}

override func imageRectForContentRect(contentRect: CGRect) -> CGRect {
    var rect = super.imageRectForContentRect(contentRect)
    rect.origin.x = CGRectGetMaxX(contentRect) - CGRectGetWidth(rect)
    return rect
}

contentEdgeInsets 已经通过使用 super 而被考虑在内。


谢谢!我喜欢这种方法,比起子类化并重写layoutSubviews()函数更好。 - Joe Susnick
1
在我看来,这是最好的方法 :) - DrPatience

10

如果您的应用程序同时支持“从左到右”和“从右到左”,则强制按钮使用“从右到左”并不是一个选项。

对我有效的解决方案是在Storyboard中为按钮添加一个可添加的子类,并与约束很好地配合使用(在iOS 11中进行了测试):

class ButtonWithImageAtEnd: UIButton {

    override func layoutSubviews() {
        super.layoutSubviews()

        if let imageView = imageView, let titleLabel = titleLabel {
            let padding: CGFloat = 15
            imageEdgeInsets = UIEdgeInsets(top: 5, left: titleLabel.frame.size.width+padding, bottom: 5, right: -titleLabel.frame.size.width-padding)
            titleEdgeInsets = UIEdgeInsets(top: 0, left: -imageView.frame.width, bottom: 0, right: imageView.frame.width)
        }

    }

}

“padding”指的是标题和图像之间的空白区域。


2
当然,.forceRightToLeft 是一个选项!如果 UIApplication.shared.userInterfaceLayoutDirection == .rightToLeft,只需使用相反的值(.forceLeftToRight)即可。 - manmal

5

使用Swift:

override func layoutSubviews(){
    super.layoutSubviews()

    let inset: CGFloat = 5

    if var imageFrame = self.imageView?.frame,
       var labelFrame = self.titleLabel?.frame {

       let cumulativeWidth = imageFrame.width + labelFrame.width + inset
       let excessiveWidth = self.bounds.width - cumulativeWidth
       labelFrame.origin.x = excessiveWidth / 2
       imageFrame.origin.x = labelFrame.origin.x + labelFrame.width + inset

       self.imageView?.frame = imageFrame
       self.titleLabel?.frame = labelFrame  
    }
}

4

在@split的答案基础上进行扩展...

这个答案非常好,但它忽略了一个事实:按钮可能具有预先设置的自定义图像和标题边缘插图(例如,在storyboard中)。

例如,您可能希望图像与容器的顶部和底部有一些填充,但仍将图像移动到按钮的右侧。

我使用以下方法扩展了这个概念:

- (void) moveImageToRightSide {
    [self sizeToFit];

    CGFloat titleWidth = self.titleLabel.frame.size.width;
    CGFloat imageWidth = self.imageView.frame.size.width;
    CGFloat gapWidth = self.frame.size.width - titleWidth - imageWidth;
    self.titleEdgeInsets = UIEdgeInsetsMake(self.titleEdgeInsets.top,
                                            -imageWidth + self.titleEdgeInsets.left,
                                            self.titleEdgeInsets.bottom,
                                            imageWidth - self.titleEdgeInsets.right);

    self.imageEdgeInsets = UIEdgeInsetsMake(self.imageEdgeInsets.top,
                                            titleWidth + self.imageEdgeInsets.left + gapWidth,
                                            self.imageEdgeInsets.bottom,
                                            -titleWidth + self.imageEdgeInsets.right - gapWidth);
}

2
// Get the size of the text and image
CGSize buttonLabelSize = [[self.button titleForState:UIControlStateNormal] sizeWithFont:self.button.titleLabel.font];
CGSize buttonImageSize = [[self.button imageForState:UIControlStateNormal] size];

// You can do this line in the xib too:
self.button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;

// Adjust Edge Insets according to the above measurement. The +2 adds a little space 
self.button.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, -(buttonLabelSize.width+2));
self.button.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, buttonImageSize.width+2);

这将创建一个向右对齐的按钮,如下所示:

[           button label (>)]
的宽度不会根据上下文自动调整,因此标签左侧会出现空白。您可以通过从和计算的框架宽度来解决这个问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接