iPhone UIButton-图像位置


116

我有一个UIButton文本“ Explore the app”,并且UIImage(>)Interface Builder看起来像:

[ (>) Explore the app ]

但是我需要UIImage在文本之后放置:

[ Explore the app (>) ]

如何将其UIImage移至右侧?


您也可以使用Interface Builder。点击这里,查看我的回答: stackoverflow.com/questions/2765024/...
n8tr

1
只需将此子类与几行代码一起使用:github.com/k06a/RTLButton
k06a 2015年

Answers:


161

我的解决方法很简单

[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要求的复制和粘贴解决方案。
mclaughlinj 2014年

当您开始更改按钮文本时,变得有点复杂。在这种情况下,子类化解决方案对我来说效果更好。
布拉德·高斯

感谢您向我展示您必须在左右两侧应用相同的宽度,我无法100%理解它的工作原理(因为有时会影响大小和原点),但是我已经能够解决类似的问题使用这种方法。
托比

128

iOS 9开始,实现此目的的一种简单方法似乎是强制视图的语义。

在此处输入图片说明

或以编程方式使用:

button.semanticContentAttribute = .ForceRightToLeft

4
尽管我很喜欢您的答案(+1),但我不想说这可能不是执行此操作的“正确”方法,但这是最简单的方法之一。
farzadshbfn

@farzadshbfn你是对的。我将该词改为“简单”,似乎更加一致。
Alvivi

@farzadshbfn为什么这不是“正确的”方法?
Samman Bikram Thapa,

3
@SammanBikramThapa恕我直言,正确的方法是将UIButton子类化,并semanticContentAttribute在我们的布局逻辑中覆盖layoutSubviews和尊重,而不是更改semanticContentAttribute自身。(更改语义方法,将不适用于国际化)
farzadshbfn

@farzadshbfn完全正确。无论此答案的得分是多少,它都是不正确的-可能会破坏从右到左界面的UX。
帕维尔·亚基缅科

86

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


8
与实现子类相比,简单地设置insets的代码要少得多。这是插图的重点。操纵子视图(尚未创建)的框架感觉更像是黑客。
金·安德烈·桑德

6
@kimsnarf,真的吗?每当您对图像的大小或标题的长度进行较小的更改时,调整插图的工作量就了很多(也没什么大不了的)?
Kirk Woll

54

雷蒙德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 2013年

2
我建议对该答案进行以下改进,以使两个视图均居中:'CGFloatcumulativeWidth = CGRectGetWidth(imageFrame)+ CGRectGetWidth(labelFrame)+ 10; CGFloat extratyWidth = CGRectGetWidth(self.bounds)-累积宽度; labelFrame.origin.x = fullyWidth / 2; imageFrame.origin.x = CGRectGetMaxX(labelFrame)+ 10;'
i-konov

对我而言,这在iOS 7上无法使用。还有谁?8.适用于iOS精
rounak

1
完全不支持iOS7,您的问题将消失。无论如何,您都不应该支持它。
吉尔·桑德

30

那么子类化UIButton和重写layoutSubviews呢?

然后对self.imageView&的位置进行后处理self.titleLabel


4
这比所有其他建议(使用上面的建议)要容易得多,这些建议都是尝试使用手工调整的插图正确放置所有内容。
史蒂文·克雷默

13

另一种简单的方法(不仅限于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

9

如果您的应用程序同时支持“从左到右”和“从右到左”,则不可以将按钮强制为“从右到左”。

对我有用的解决方案是一个子类,可以将其添加到情节提要中的按钮,并且可以很好地与约束一起使用(在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)
        }

    }

}

其中“填充”是标题和图像之间的空间。


当然.forceRightToLeft是一个选择!.forceLeftToRight如果使用相反的值()UIApplication.shared.userInterfaceLayoutDirection == .rightToLeft
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建立答案...

答案是极好的,但它忽略了按钮可能具有预先设置的自定义图像和标题边缘插图(例如在情节提要中)的事实。

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

我用这种方法扩展了概念:

- (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 (>)]

该按钮不会根据上下文调整其宽度,因此空格将出现在标签的左侧。您可以通过从buttonLabelSize.width和buttonImageSize.width计算按钮的框架宽度来解决此问题。


1
button.semanticContentAttribute = UISemanticContentAttributeForceRightToLeft;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;

0

此解决方案适用于iOS 7及更高版本

只是UIButton的子类

@interface UIButton (Image)

- (void)swapTextWithImage;

@end

@implementation UIButton (Image)

- (void)swapTextWithImage {
   const CGFloat kDefaultPadding = 6.0f;
   CGSize buttonSize = [self.titleLabel.text sizeWithAttributes:@{
                                                               NSFontAttributeName:self.titleLabel.font
                                                               }];

   self.titleEdgeInsets = UIEdgeInsetsMake(0, -self.imageView.frame.size.width, 0, self.imageView.frame.size.width);
   self.imageEdgeInsets = UIEdgeInsetsMake(0, buttonSize.width + kDefaultPadding, 0, -buttonSize.width); 
}

@end

用法(在课堂上的某个地方):

[self.myButton setTitle:@"Any text" forState:UIControlStateNormal];
[self.myButton swapTextWithImage];

0

以先前的答案为基础。如果要在图标和按钮标题之间留出一定的空白,则代码必须稍作更改,以防止标签和图标浮动在固有大小的按钮的边界上方。

let margin = CGFloat(4.0)
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)
button.contentEdgeInsets = UIEdgeInsetsMake(0, margin, 0, margin)

最后一行代码对于自动布局的固有内容大小计算很重要。


0

这是我做事的方式(大约10年后)

  1. UIButton的子类(Button,因为我们生活在Swift时代)
  2. 将图像和标签放在堆栈视图中。
class CustomButton: Button {

    var didLayout: Bool = false // The code must be called only once

    override func layoutSubviews() {
        super.layoutSubviews()
        if !didLayout, let imageView = imageView, let titleLabel = titleLabel {
            didLayout = true
            let stack = UIStackView(arrangedSubviews: [titleLabel, imageView])
            addSubview(stack)
            stack.edgesToSuperview() // I use TinyConstraints library. You could handle the constraints directly
            stack.axis = .horizontal
        }
    }
}

0

Swift中的单行解决方案:

// iOS 9 and Onwards
button.semanticContentAttribute = .forceRightToLeft

这不好,因为它将破坏所有RTL用户的布局。您将需要从左向右强制他们。您最好从这里尝试其他解决方案。
帕维尔·亚基缅科
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.