ios 在 UIButton 上左对齐图像和居中文本

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10954880/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 18:41:31  来源:igfitidea点击:

Left-align image and center text on UIButton

iosuiimageuibutton

提问by user1007721

I've seen posts regarding right alignment but I can't get left-alignment to work. I want the button to take up the width of the screen, with the image on the left and the title/text in the center.

我看过有关右对齐的帖子,但我无法使用左对齐。我希望按钮占据屏幕的宽度,图像在左侧,标题/文本在中心。

This does not work (at least reliably):

这不起作用(至少可靠):

    button.titleLabel.textAlignment = UITextAlignmentCenter;
    [button setImageEdgeInsets:UIEdgeInsetsMake(0, -60.0, 0, 0)];
    button.frame = CGRectMake((self.view.frame.size.width - w ) / 2, self.view.frame.size.height - 140.0,  self.view.frame.size.width - 10.0, 40.0);

回答by redent84

This solution works with Swift 3 and respects original content and image edge insets while keeping the title label always centered in the available space, which makes much easier adjusting margins.

此解决方案适用于 Swift 3 并尊重原始内容和图像边缘插入,同时保持标题标签始终位于可用空间的中心,这使得调整边距变得更加容易。

It overrides titleRect(forContentRect:)method and returns the correct frame:

它覆盖titleRect(forContentRect:)方法并返回正确的框架:

@IBDesignable
class LeftAlignedIconButton: UIButton {
    override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
        let titleRect = super.titleRect(forContentRect: contentRect)
        let imageSize = currentImage?.size ?? .zero
        let availableWidth = contentRect.width - imageEdgeInsets.right - imageSize.width - titleRect.width
        return titleRect.offsetBy(dx: round(availableWidth / 2), dy: 0)
    }
}

The following insets:

以下插图:

enter image description here

在此处输入图片说明

Would result in this:

会导致这个:

enter image description here

在此处输入图片说明



Deprecated previous answer

已弃用的先前答案

This works in most scenarios, but some layouts cause layoutSubviewsto recursively call itself in an endless loop, so use with caution.

这在大多数情况下都有效,但某些布局会导致layoutSubviews在无限循环中递归调用自身,因此请谨慎使用

@IBDesignable
class LeftAlignedIconButton: UIButton {
    override func layoutSubviews() {
        super.layoutSubviews()
        contentHorizontalAlignment = .left
        let availableSpace = UIEdgeInsetsInsetRect(bounds, contentEdgeInsets)
        let availableWidth = availableSpace.width - imageEdgeInsets.right - (imageView?.frame.width ?? 0) - (titleLabel?.frame.width ?? 0)
        titleEdgeInsets = UIEdgeInsets(top: 0, left: availableWidth / 2, bottom: 0, right: 0)
    }
}

This code would do the same but aligning the icon to the right edge:

此代码将执行相同的操作,但将图标与右边缘对齐:

@IBDesignable
class RightAlignedIconButton: UIButton {
    override func layoutSubviews() {
        super.layoutSubviews()
        semanticContentAttribute = .forceRightToLeft
        contentHorizontalAlignment = .right
        let availableSpace = UIEdgeInsetsInsetRect(bounds, contentEdgeInsets)
        let availableWidth = availableSpace.width - imageEdgeInsets.left - (imageView?.frame.width ?? 0) - (titleLabel?.frame.width ?? 0)
        titleEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: availableWidth / 2)
    }
}

enter image description here

在此处输入图片说明

The right allignment version uses semanticContentAttributeso it requires iOS 9+.

使用正确的对齐版本,semanticContentAttribute因此它需要 iOS 9+。

回答by toytoy

In my end, I did this using UIEdgeInsetsMake which the left corner is calculated to make it to the center. I am not sure if there's something really you can make the text at aligned at the center but this works for me. Make sure that you set your left corner to your desired position by calculating the width. e.g. UIEdgeInsetsMake(0.0f, 42.0f, 0.0f, 0.0f)

最后,我使用 UIEdgeInsetsMake 做到了这一点,计算左角使其居中。我不确定是否真的有什么东西可以让文本在中心对齐,但这对我有用。确保通过计算宽度将左角设置到所需位置。例如 UIEdgeInsetsMake(0.0f, 42.0f, 0.0f, 0.0f)

UIButton *scanBarCodeButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
scanBarCodeButton.frame = CGRectMake(center, 10.0f, fieldWidth, 40.0f);
[scanBarCodeButton setImage:[UIImage imageNamed:@"BarCodeIcon.png"] forState:UIControlStateNormal];
[scanBarCodeButton setTitle:@"Scan the Barcode" forState:UIControlStateNormal];
scanBarCodeButton.titleEdgeInsets = UIEdgeInsetsMake(0.0f, 42.0f, 0.0f, 0.0f);
[scanBarCodeButton setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
[scanBarCodeButton addTarget:self action:@selector(scanBarCode:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:scanBarCodeButton];

The output looks like,

输出看起来像,

centered text with image

带有图像的居中文本

In Swift:

斯威夫特

var scanBarCodeButton: UIButton = UIButton(type: .roundedRect)
scanBarCodeButton.frame = CGRectMake(center, 10.0, fieldWidth, 40.0)
scanBarCodeButton.setImage(UIImage(named: "BarCodeIcon.png"), for: UIControlStateNormal)
scanBarCodeButton.setTitle("Scan the Barcode", for: UIControlStateNormal)
scanBarCodeButton.titleEdgeInsets = UIEdgeInsetsMake(0.0, 42.0, 0.0, 0.0)
scanBarCodeButton.contentHorizontalAlignment = .left
scanBarCodeButton.addTarget(self, action: "scanBarCode:", for: UIControlEventTouchUpInside)
self.view.addSubview(scanBarCodeButton)

回答by AnBisw

For Swift 4.0, here's an extension that works-

对于 Swift 4.0,这是一个有效的扩展 -

extension UIButton {
    func leftImage(image: UIImage, renderMode: UIImageRenderingMode) {
        self.setImage(image.withRenderingMode(renderMode), for: .normal)
        self.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: image.size.width / 2)
        self.contentHorizontalAlignment = .left
        self.imageView?.contentMode = .scaleAspectFit
    }

    func rightImage(image: UIImage, renderMode: UIImageRenderingMode){
        self.setImage(image.withRenderingMode(renderMode), for: .normal)
        self.imageEdgeInsets = UIEdgeInsets(top: 0, left:image.size.width / 2, bottom: 0, right: 0)
        self.contentHorizontalAlignment = .right
        self.imageView?.contentMode = .scaleAspectFit
    }
}

Usage:

用法:

myButton.rightImage(image: UIImage(named: "image_name")!, renderMode: .alwaysOriginal)
myButton.leftImage(image: UIImage(named: "image_name")!, renderMode: .alwaysOriginal)

renderModecan be .alwaysTemplateor .alwaysOriginal. Also, myButtonshould be a customtype UIButton.

renderMode可以.alwaysTemplate.alwaysOriginal。此外,myButton应该是一个custom类型UIButton

This extension's leftImageand rightImagecan also be used in UIButtonin UIBarButtonItemfor UINavigationBar(Note: as of iOS 11, the navigation bar follows autolayout so you will need to add width/height constraints to the UIBarButtonItem). For usage on Navigation Bar, make sure you follow the Apple recommended @2x and @3x image sizes (i.e. 50x50, 75x75) and to have better accessibility on iPhone 6, 7 , 8, 6s, 7s, 8s, the Plus variants and iPhone x the width and height of the UIBarButtoncould be height - 25 and width - 55 (or whatever your app requires, these numbers are some basic numbers that should work for most cases).

这个扩展的leftImage并且rightImage也可以在使用UIButtonUIBarButtonItemUINavigationBar(注:由于iOS的11,导航栏下面自动布局,所以你需要宽度/高度限制添加到UIBarButtonItem)。要在导航栏上使用,请确保遵循 Apple 推荐的 @2x 和 @3x 图像尺寸(即 50x50、75x75),并在 iPhone 6、7、8、6s、7s、8s、Plus 变体和 iPhone 上获得更好的可访问性x 的宽度和高度UIBarButton可以是高度 - 25 和宽度 - 55(或者无论您的应用需要什么,这些数字都是一些基本数字,适用于大多数情况)。



UPDATE: In Swift 4.2, UIImageRenderingModehas been renamed to UIImage.RenderingMode

更新:在 Swift 4.2 中,UIImageRenderingMode已重命名为UIImage.RenderingMode

extension UIButton {
    func leftImage(image: UIImage, renderMode: UIImage.RenderingMode) {
        self.setImage(image.withRenderingMode(renderMode), for: .normal)
        self.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: image.size.width / 2)
        self.contentHorizontalAlignment = .left
        self.imageView?.contentMode = .scaleAspectFit
    }

    func rightImage(image: UIImage, renderMode: UIImage.RenderingMode){
        self.setImage(image.withRenderingMode(renderMode), for: .normal)
        self.imageEdgeInsets = UIEdgeInsets(top: 0, left:image.size.width / 2, bottom: 0, right: 0)
        self.contentHorizontalAlignment = .right
        self.imageView?.contentMode = .scaleAspectFit
    }
}

回答by Danilo

Create your button and set the text alignment to center, then add:

创建您的按钮并将文本对齐设置为居中,然后添加:

UIImage *image = [UIImage imageNamed:@"..."];
CGSize imageSize = image.size;
CGFloat offsetY = floor((self.layer.bounds.size.height - imageSize.height) / 2.0);

CALayer *imageLayer = [CALayer layer];
imageLayer.contents = (__bridge id) image.CGImage;
imageLayer.contentsGravity = kCAGravityBottom;
imageLayer.contentsScale = [UIScreen mainScreen].scale;
imageLayer.frame = CGRectMake(offsetY, offsetY, imageSize.width, imageSize.height);
[self.layer addSublayer:imageLayer];

回答by Denis Kozhukhov

As I think, the good solution must be useful for any text, without hardcoded values for insets (it's about the solution provided by toytoy). I use the code similar to this:

我认为,好的解决方案必须对任何文本都有用,没有插入的硬编码值(这是关于 toytoy 提供的解决方案)。我使用类似于此的代码:

NSString *sometitle = @"blabla button title";
NSString *someimage = @"blablaimage";
UIImage *image = [[UIImage imageNamed:someimage];
int buttonWidth = A;
int buttonHeight = B;
int imageWidth =image.size.width;
int imageHeight = image.size.height;
int titleWidth = buttonWidth - imageWidth;

// create button and set image and title
buttonView = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, buttonWidth, buttonHeight)];
[buttonView setImage:image forState:UIControlStateNormal];
[buttonView setTitle:sometitle forState:UIControlStateNormal];

// make button all content to be left aligned
[buttonView setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];

// set title font 
[buttonView.titleLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:14]];

// calculate font text width with selected font
CGSize stringBoundingBox = [number sizeWithFont:[buttonView.titleLabel font]];

// make title inset with some value from left 
// it place the title right on the center of space for the title
int titleLeft = (titleWidth - stringBoundingBox.width) / 2;
[buttonView setTitleEdgeInsets:UIEdgeInsetsMake(0, titleLeft, 0, 0)];

After the string with stringBoundingBox init I also add some strings like this:

在 stringBoundingBox init 字符串之后,我还添加了一些这样的字符串:

if (stringBoundingBox.width > titleWidth)
{
    [_backgroundView.titleLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:13]];
    stringBoundingBox = [number sizeWithFont:[_backgroundView.titleLabel font]];
}
if (stringBoundingBox.width > titleWidth)
{
    [_backgroundView.titleLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:12]];
    stringBoundingBox = [number sizeWithFont:[_backgroundView.titleLabel font]];
}

it allow to me set the titles longer than available space, by selecting some smaller fonts. I make this because of another way for this:

它允许我通过选择一些较小的字体来设置比可用空间更长的标题。我这样做是因为另一种方式:

[buttonView.titleLabel setAdjustsFontSizeToFitWidth:YES];

works not very good, looks like it take the font size for 3-4 points smaller at one step, so some not so long lines become too smaller, than it must to be.

效果不是很好,看起来它的字体大小一步小了 3-4 个点,所以一些不那么长的行变得太小了,比它必须的要小。

This code allow us to place any text in button title space exactly in center.

这段代码允许我们将任何文本放在按钮标题空间的中心位置。

回答by Maximelc

I wrote an UIButton extension.

我写了一个 UIButton 扩展。

extension UIButton {

  /// Add image on left view
  func leftImage(image: UIImage) {
    self.setImage(image, for: .normal)
    self.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: image.size.width)
  }
}

And you could use like this :

你可以这样使用:

yourButton.leftImage(image: yourImage)

Voila !

瞧!

回答by Alex

I've tried almost every solution above and none of them worked as I expected (I had two buttons each with different tittle and with different image width). So I have written my own extension for UIButton, which works flawlessly with different image widths as well as with different titles.

我已经尝试了上面几乎所有的解决方案,但没有一个像我预期的那样工作(我有两个按钮,每个按钮都有不同的标题和不同的图像宽度)。所以我为 UIButton 编写了我自己的扩展,它可以完美地处理不同的图像宽度和不同的标题。

extension UIButton {
    func moveImageLeftTextCenter(imagePadding: CGFloat = 30.0, titlePadding: CGFloat = 0.0, minImageTitleDistance: CGFloat = 10.0){
    guard let imageViewWidth = imageView?.frame.width else{return}
    guard let titleLabelWidth = titleLabel?.intrinsicContentSize.width else{return}
    contentHorizontalAlignment = .left

    let imageLeftInset = imagePadding - imageViewWidth / 2
    var titleLeftInset = (bounds.width - titleLabelWidth) / 2 - imageViewWidth + titlePadding

    if titleLeftInset - imageLeftInset < minImageTitleDistance{
        titleLeftInset = imageLeftInset + minImageTitleDistance
    }

    imageEdgeInsets = UIEdgeInsets(top: 0.0, left: imageLeftInset, bottom: 0.0, right: 0.0)
    titleEdgeInsets = UIEdgeInsets(top: 0.0, left: titleLeftInset, bottom: 0.0, right: 0.0)
    }
}

Usage: myButton.moveImageLeftTextCenter()

用法: myButton.moveImageLeftTextCenter()

回答by Deepak Kumar Sahu

[self.button setImage:[UIImage imageNamed:@"image.png"] forState:UIControlStateNormal];

[self.button setTitleEdgeInsets:UIEdgeInsetsMake(0.0, self.button.center.x/2 , 0.0, 0.0)];

[self.button setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];

Let me know if it is not working.

如果它不起作用,请告诉我。

My output enter image description here

我的输出 在此处输入图片说明

回答by Rémy Virin

This works well for me, for several buttons, with different image width and different title length :

这对我来说效果很好,对于几个具有不同图像宽度和不同标题长度的按钮:

Subclass UIButton, and add the following method:

子类UIButton,并添加以下方法:

override func layoutSubviews() {
    super.layoutSubviews()

    if let image = imageView?.image {

        let margin = 30 - image.size.width / 2
        let titleRect = titleRectForContentRect(bounds)
        let titleOffset = (bounds.width - titleRect.width - image.size.width - margin) / 2


        contentHorizontalAlignment = UIControlContentHorizontalAlignment.Left
            imageEdgeInsets = UIEdgeInsetsMake(0, margin, 0, 0)
            titleEdgeInsets = UIEdgeInsetsMake(0, (bounds.width - titleRect.width -  image.size.width - margin) / 2, 0, 0)
    }

}

回答by Matthew Mitchell

Tried most of the answers with no luck. I was getting a blue image most of the time, or the title was not center. Used code from a few of the answers and wrote this extension, works like a charm.

在没有运气的情况下尝试了大多数答案。大多数时候我得到的是蓝色图像,或者标题不在中心。使用了一些答案中的代码并编写了这个扩展,就像一个魅力。

Swift 4.2:

斯威夫特 4.2:

import UIKit

extension UIButton {
    func moveImageLeftTextCenter(image : UIImage, imagePadding: CGFloat, renderingMode: UIImage.RenderingMode){
        self.setImage(image.withRenderingMode(renderingMode), for: .normal)
        guard let imageViewWidth = self.imageView?.frame.width else{return}
        guard let titleLabelWidth = self.titleLabel?.intrinsicContentSize.width else{return}
        self.contentHorizontalAlignment = .left
        let imageLeft = imagePadding - imageViewWidth / 2
        let titleLeft = (bounds.width - titleLabelWidth) / 2 - imageViewWidth
        imageEdgeInsets = UIEdgeInsets(top: 0.0, left: imageLeft, bottom: 0.0, right: 0.0)
        titleEdgeInsets = UIEdgeInsets(top: 0.0, left: titleLeft , bottom: 0.0, right: 0.0)
    }
}

Hope it helps for some!

希望对一些人有所帮助!