UIButton 标题和图片对齐问题查询

28

我有一个UIButton,我正在尝试设置标题和图像。

我想让UIButton的标题靠左对齐,并放置一个右对齐的图像。我试图获得时钟应用程序中计时器按钮的外观和感觉(显示“计时器结束”)。

我尝试使用contentHorizontalAlignmentcontentEdgeInsetstitleEdgeInsetsimageEdgeInsets进行调整,但没有成功。相关文档也相当稀少。

如何实现相同的效果?

另外还有一个问题,时钟应用程序中的计时器按钮有两个文本集,一个靠左对齐,另一个靠右并带有图像?如何在UIButton中实现?(目前我不需要这个功能。)

9个回答

49

这是我用来做那件事的代码:

//Right-align the button image
CGSize size = [[myButton titleForState:UIControlStateNormal] sizeWithFont:myButton.titleLabel.font];
[myButton setImageEdgeInsets:UIEdgeInsetsMake(0, 0, 0, -size.width)];
[myButton setTitleEdgeInsets:UIEdgeInsetsMake(0, 0, 0, myButton.imageView.image.size.width + 5)];

这是我个人认为更好的答案,使用代码相对于@Bill的最高票答案,后者告诉你要使用这些API调用,但没有展示如何调用setImage:forState:。如果它展示了如何调用setImage:forState:会更好。此外,我发现在某些情况下,例如操作表(actionSheets),一旦你有了setImageEdgeInsets,你就不需要调整titleEdgeInsets——它们已经考虑了你的图像宽度。结果可能因人而异。 - natbro
3
如果你将 contentHorizontalAlignment 设置为 UIControlContentHorizontalAlignmentRight,你还需要在 titleEdgeInsets 中向左添加一个插入量。即: [myButton setTitleEdgeInsets:UIEdgeInsetsMake(0, -imageSize.width, 0, imageSize.width)]; - vilanovi

35

更改UIButton上的imageEdgeInsets属性,然后只需使用setImage:forState:


1
这是使用UIButton的正确方法,如果您正在使用UIButton。表视图则是另一种不同的东西。 - Aleksandar Vacić
5
同意,但是这位发帖者没有提到表格视图 :) - Bill

14

以下代码可用:

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = buttonRect;
[button setTitle:@"A title" forState:UIControlStateNormal];
[button setImage:buttonImage forState:UIControlStateNormal];
button.imageEdgeInsets = UIEdgeInsetsMake(0.0, WIDTH(button.titleLabel) + 10.0, 0.0, 0.0);
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;

9

请记住UIButton是从UIView继承而来的,因此您可以像其他视图一样向其添加子视图。在您的情况下,您将创建一个按钮,然后在左侧添加一个UILabel,在右侧添加一个UIImage:

// Create the button
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];

// Now load the image and create the image view
UIImage *image = [UIImage imageNamed:@"yourImage.png"];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(/*frame*/)];
[imageView setImage:image];

// Create the label and set its text
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(/*frame*/)];
[label setText:@"Your title"];

// Put it all together
[button addSubview:label];
[button addSubview:imageView];

2
通常这种行为会在将背景图像作为UIButton的子视图添加到自定义视图之上时出现。不要设置按钮的backgroundImage属性,而是考虑自己添加一个UIImageView来作为背景图像,然后在该图像视图上方添加其他自定义内容。 - Tim
这个答案建议在已经拥有 UIImageView 的按钮内创建一个新的 UIImageView。这肯定能够工作,但推荐的解决方案将涉及到 imageRectForContentRect:titleRectForContentRect: 这两个专为此目的而提供的方法。 - cleverbit
@Tim 感谢您的代码,请告诉我如何在按钮单击事件中通过编程方式更改 imageView 的图像? - Varun Naharia
@VarunNaharia:关于那个问题,最好的建议是提出一个新问题,而不是使用这篇评论(这篇评论已经有近六年了!)。 - Tim
看起来你已经在那个问题上接受了一个答案。请不要再重复使用这个旧问题上的评论来讨论其他主题! - Tim
显示剩余5条评论

4
在Swift中,对于任何关心的人(使用10pt间距):
let size = (self.titleForState(UIControlState.Normal)! as NSString).sizeWithAttributes([NSFontAttributeName:self.titleLabel!.font])
let offset = (size.width + 10)
self.imageEdgeInsets = UIEdgeInsetsMake(0, offset, 0, -offset)
self.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, self.imageView!.frame.size.width + 10)

4

对于在 iOS 9 上的使用,我尝试了这个帖子中许多答案,但它们都不适合我。我找到了适合自己的答案,如下所示:

class MyButton: UIButton {

  override func layoutSubviews() {
    super.layoutSubviews()

    self.contentHorizontalAlignment = UIControlContentHorizontalAlignment.Left

    if self.imageView?.image != nil {
      // Move icon to right side
      self.imageEdgeInsets = UIEdgeInsets(
        top: 0,
        left: self.bounds.size.width - self.imageView!.image!.size.width,
        bottom: 0,
        right: 0)

      // Move title to left side
      self.titleEdgeInsets = UIEdgeInsetsMake(0, -self.imageView!.frame.size.width + 8, 0, 0)

    }
  }
}

SWIFT 3:

class MyButton: UIButton {

    override func layoutSubviews() {
        super.layoutSubviews()

        self.contentHorizontalAlignment = UIControlContentHorizontalAlignment.left

        if self.imageView?.image != nil {
            // Move icon to right side
            self.imageEdgeInsets = UIEdgeInsets(
                top: 0,
                left: self.bounds.size.width - self.imageView!.image!.size.width,
                bottom: 0,
                right: 0)

            // Move title to left side
            self.titleEdgeInsets = UIEdgeInsetsMake(0, -self.imageView!.frame.size.width + 8, 0, 0)

        }
    }
}

我希望这能对像我一样的人有所帮助!

1
干得好,我会用Swift 3更新你。 - Mikel Sanchez

4

您还可以重写 UIButtontitleRectForContentRect:imageRectForContentRect: 方法,以便将文本和图像定位在任何位置。


1
这是 Swift 中 UIButton 的一个子类,它将图像对齐到左侧,将文本居中。将 imageLeftInset 设置为所需值即可。
class LeftImageAlignedButton : UIButton {

var imageLeftInset : CGFloat = 10.0

override func layoutSubviews() {
    super.layoutSubviews()
    self.contentHorizontalAlignment = .Left
    if let font = titleLabel?.font {
        let textWidth = ((titleForState(state) ?? "") as NSString).sizeWithAttributes([NSFontAttributeName:font]).width
        let imageWidth = imageForState(state)?.size.width ?? 0.0
        imageEdgeInsets = UIEdgeInsets(top: 0, left: imageLeftInset, bottom: 0, right: 0)
        titleEdgeInsets = UIEdgeInsets(top: 0, left: bounds.width/2 - textWidth/2.0 - imageWidth, bottom: 0, right: 0)
    }
}
}

-2

没问题,虽然我不确定使用这种机制是否值得,相对于普通的子类化。 - Steven Kramer
虽然这是一种通用的良好策略,但 -(CGRect) imageRectForContentRect:(CGRect)contentRect-(CGRect) titleRectForContentRect:(CGRect)contentRect 是专门为此目的而设计的。不幸的是,每次视图布局更改时都会调用 layoutSubviews,因此在这种情况下不适用。 - cleverbit
但我敢打赌,imageRectForContentRect:等方法也会在布局时被调用 - 我想知道你为什么认为“这种情况”使它不适合?除此之外,layoutSubviews让您一次性完全控制布局,这也很好。我猜这取决于情况 - 如果我没记错的话,我曾经尝试过使用...forContentRect创建一个具有顶部对齐图标和底部对齐文本的按钮,遇到了一些问题。 - Steven Kramer

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