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

use*_*721 57 uibutton uiimage ios

我见过有关正确对齐的帖子,但我无法让左对齐工作.我希望按钮占据屏幕的宽度,左侧是图像,中间是标题/文字.

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

    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);
Run Code Online (Sandbox Code Playgroud)

red*_*t84 54

此解决方案适用于Swift 3并尊重原始内容和图像边缘插入,同时保持标题标签始终位于可用空间的中心,这样可以更轻松地调整边距.

它会覆盖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)
    }
}
Run Code Online (Sandbox Code Playgroud)

以下内容:

在此输入图像描述

会导致这个:

在此输入图像描述


不推荐使用先前的答案

这适用于大多数情况,但是某些布局会导致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)
    }
}
Run Code Online (Sandbox Code Playgroud)

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

@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)
    }
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

正确的allignment版本使用semanticContentAttribute它需要iOS 9+.

  • 您必须设置`contentHorizo​​ntalAlignment = .left`使其起作用。 (2认同)

toy*_*toy 46

在我的最后,我使用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];
Run Code Online (Sandbox Code Playgroud)

输出看起来像,

带图像的居中文本http://i43.tinypic.com/33mbxxi.png

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)
Run Code Online (Sandbox Code Playgroud)

  • 对我来说,最重要的是将内容水平对齐设置为Left,而不是默认中心.文本本身仍然在文本区域中居中.这里你的幻数"42"是图像的宽度,很容易计算出来. (8认同)

Ann*_*awn 12

对于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
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

myButton.rightImage(image: UIImage(named: "image_name")!, renderMode: .alwaysOriginal)
myButton.leftImage(image: UIImage(named: "image_name")!, renderMode: .alwaysOriginal)
Run Code Online (Sandbox Code Playgroud)

renderMode可以是.alwaysTemplate.alwaysOriginal.另外,myButton应该是一种custom类型UIButton.

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


更新:在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
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 不起作用。标题对齐不是在按钮中居中,这正是OP想要的。 (4认同)

Ale*_*lex 9

我已经尝试了上面几乎所有的解决方案,但没有一个像我预期的那样工作(我有两个按钮,每个按钮都有不同的标题和不同的图像宽度)。所以我为 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

用法: myButton.moveImageLeftTextCenter()


Dan*_*ilo 7

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

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];
Run Code Online (Sandbox Code Playgroud)


Den*_*hov 7

我认为,好的解决方案必须对任何文本都有用,没有用于插入的硬编码值(这是关于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)];
Run Code Online (Sandbox Code Playgroud)

在使用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]];
}
Run Code Online (Sandbox Code Playgroud)

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

[buttonView.titleLabel setAdjustsFontSizeToFitWidth:YES];
Run Code Online (Sandbox Code Playgroud)

效果不是很好,看起来它的字体大小一步缩小3-4个点,所以有些不那么长的线条变得比它必须要小.

此代码允许我们将按钮标题空间中的任何文本正好放在中心.


Dee*_*ahu 6

[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];
Run Code Online (Sandbox Code Playgroud)

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

我的输出 在此输入图像描述


Mat*_*ell 6

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

斯威夫特 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

希望对一些人有所帮助!


Rém*_*rin 5

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

子类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)
    }

}
Run Code Online (Sandbox Code Playgroud)


Max*_*elc 5

我写了一个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)
  }
}
Run Code Online (Sandbox Code Playgroud)

你可以像这样使用:

yourButton.leftImage(image: yourImage)
Run Code Online (Sandbox Code Playgroud)

瞧!


Chr*_*ian -2

最好创建一个自定义 UIButton 子类来以更好的方式解决此问题。Apple 可能会“重置”您的设置。