UIButton:如何使用imageEdgeInsets和titleEdgeInsets将图像和文本居中?

如果我只在按钮中放置图像,并将imageEdgeInsets设置得更靠近顶部,则图像保持居中状态,并且按预期工作:

[button setImage:image forState:UIControlStateNormal];
[button setImageEdgeInsets:UIEdgeInsetsMake(-15.0, 0.0, 0.0, 0.0)];

如果我只在按钮中放置一个文本,并将titleEdgeInsets设置得更靠近底部,则文本保持居中,并且所有工作都按预期工作:

[button setTitle:title forState:UIControlStateNormal];
[button setTitleEdgeInsets:UIEdgeInsetsMake(0.0, 0.0, -30, 0.0)];

但是,如果我将4条线放在一起,则文字会干扰图像,并且都会丢失中心对齐。

我所有的图像都有30像素的宽度,如果我在UIEdgeInsetMake的左边参数中为setTitleEdgeInsets放置了30,则文本再次居中。 问题是图像永远不会居中,因为它看起来取决于button.titleLabel大小。 我已经尝试了许多按钮大小,图像大小,titleLabel大小的计算,并且永远都不会完全居中。

有人已经有同样的问题?


对于它的价值,这里有一个通用的解决方案,将图像定位在文本上方而不使用任何幻数。 请注意,以下代码已过时,您应该使用以下更新版本之一

// the space between the image and text
CGFloat spacing = 6.0;

// lower the text and push it left so it appears centered 
//  below the image
CGSize imageSize = button.imageView.frame.size;
button.titleEdgeInsets = UIEdgeInsetsMake(
  0.0, - imageSize.width, - (imageSize.height + spacing), 0.0);

// raise the image and push it right so it appears centered
//  above the text
CGSize titleSize = button.titleLabel.frame.size;
button.imageEdgeInsets = UIEdgeInsetsMake(
  - (titleSize.height + spacing), 0.0, 0.0, - titleSize.width);

以下版本包含对以下评论中推荐的支持iOS 7+的更改。 我还没有自己测试过这个代码,所以我不确定它的工作原理,或者如果在以前版本的iOS下使用,它是否会中断。

// the space between the image and text
CGFloat spacing = 6.0;

// lower the text and push it left so it appears centered 
//  below the image
CGSize imageSize = button.imageView.image.size;
button.titleEdgeInsets = UIEdgeInsetsMake(
  0.0, - imageSize.width, - (imageSize.height + spacing), 0.0);

// raise the image and push it right so it appears centered
//  above the text
CGSize titleSize = [button.titleLabel.text sizeWithAttributes:@{NSFontAttributeName: button.titleLabel.font}];
button.imageEdgeInsets = UIEdgeInsetsMake(
  - (titleSize.height + spacing), 0.0, 0.0, - titleSize.width);

// increase the content height to avoid clipping
CGFloat edgeOffset = fabsf(titleSize.height - imageSize.height) / 2.0;
button.contentEdgeInsets = UIEdgeInsetsMake(edgeOffset, 0.0, edgeOffset, 0.0);

Swift版本

extension UIButton {
  func alignVertical(spacing: CGFloat = 6.0) {
    guard let imageSize = self.imageView?.image?.size,
      let text = self.titleLabel?.text,
      let font = self.titleLabel?.font
      else { return }
    self.titleEdgeInsets = UIEdgeInsets(top: 0.0, left: -imageSize.width, bottom: -(imageSize.height + spacing), right: 0.0)
    let labelString = NSString(string: text)
    let titleSize = labelString.size(attributes: [NSFontAttributeName: font])
    self.imageEdgeInsets = UIEdgeInsets(top: -(titleSize.height + spacing), left: 0.0, bottom: 0.0, right: -titleSize.width)
    let edgeOffset = abs(titleSize.height - imageSize.height) / 2.0;
    self.contentEdgeInsets = UIEdgeInsets(top: edgeOffset, left: 0.0, bottom: edgeOffset, right: 0.0)
  }
}

发现如何。

首先,配置titleLabel的文本(因为样式,即粗体,斜体等)。 然后,使用setTitleEdgeInsets考虑图像的宽度:

[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button setTitle:title forState:UIControlStateNormal];
[button.titleLabel setFont:[UIFont boldSystemFontOfSize:10.0]];

// Left inset is the negative of image width.
[button setTitleEdgeInsets:UIEdgeInsetsMake(0.0, -image.size.width, -25.0, 0.0)]; 

之后,使用setTitleEdgeInsets考虑文本边界的宽度:

[button setImage:image forState:UIControlStateNormal];

// Right inset is the negative of text bounds width.
[button setImageEdgeInsets:UIEdgeInsetsMake(-15.0, 0.0, 0.0, -button.titleLabel.bounds.size.width)];

现在图像和文字将居中(在这个例子中,图像出现在文字上方)。

干杯。


你可以用这个Swift扩展来完成,部分基于Jesse Crossen的回答:

extension UIButton {
  func centerLabelVerticallyWithPadding(spacing:CGFloat) {
    // update positioning of image and title
    let imageSize = self.imageView.frame.size
    self.titleEdgeInsets = UIEdgeInsets(top:0,
                                        left:-imageSize.width,
                                        bottom:-(imageSize.height + spacing),
                                        right:0)
    let titleSize = self.titleLabel.frame.size
    self.imageEdgeInsets = UIEdgeInsets(top:-(titleSize.height + spacing),
                                        left:0,
                                        bottom: 0,
                                        right:-titleSize.width)

    // reset contentInset, so intrinsicContentSize() is still accurate
    let trueContentSize = CGRectUnion(self.titleLabel.frame, self.imageView.frame).size
    let oldContentSize = self.intrinsicContentSize()
    let heightDelta = trueContentSize.height - oldContentSize.height
    let widthDelta = trueContentSize.width - oldContentSize.width
    self.contentEdgeInsets = UIEdgeInsets(top:heightDelta/2.0,
                                          left:widthDelta/2.0,
                                          bottom:heightDelta/2.0,
                                          right:widthDelta/2.0)
  }
}

这定义了一个函数centerLabelVerticallyWithPadding ,适当地设置标题和图像插入。

它还设置了contentEdgeInsets,我认为这对于确保intrinsicContentSize仍然正常工作是必需的,这将需要使用自动布局。

我相信UIButton的所有解决方案在技术上都是非法的,因为你不应该继承UIKit控件。 也就是说,理论上他们可能会在未来的版本中打破。

链接地址: http://www.djcxy.com/p/28243.html

上一篇: UIButton: how to center an image and a text using imageEdgeInsets and titleEdgeInsets?

下一篇: layout to move other views when a view is hidden?