如何将图像放在UIButton中文本的右侧?

时间:2011-08-18 00:06:29

标签: ios user-interface layout uibutton

如果可以避免,我不想使用子视图。我希望UIButton带有背景图片,文字和图片。现在,当我这样做时,图像位于文本的左侧。背景图像,文本和图像都具有不同的高光状态。

33 个答案:

答案 0 :(得分:519)

最简单的解决方案:

iOS 10&斯威夫特:

button.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
button.titleLabel?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
button.imageView?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)

在iOS 10之前,Swift / Obj-C:

button.transform = CGAffineTransformMakeScale(-1.0, 1.0);
button.titleLabel.transform = CGAffineTransformMakeScale(-1.0, 1.0);
button.imageView.transform = CGAffineTransformMakeScale(-1.0, 1.0);

答案 1 :(得分:198)

尽管一些建议的答案非常有创意且极其聪明,但最简单的解决方案如下:

update a_oracle_table
    set test_n = sqrt(a) / acos(-1);  -- acos(-1) = pi

就这么简单。作为奖励,图像将位于从右到左区域的左侧。

编辑:问题已被问过几次,这是 iOS 9 +

答案 2 :(得分:195)

  

更新XCODE 9(通过Interface Builder)

界面生成器开始,这是一种更简单的方法。选择UIButton并在查看实用程序

中选择此选项

enter image description here

那就是它!好又简单!

  

可选 - 第二步:

如果您想调整图片和标题之间的间距,可以在此处更改图片插入

enter image description here

希望有所帮助!

答案 3 :(得分:166)

完全不需要对UIButton进行子类化。相反,您可以简单地为图像插入设置一个高左插入值,并为标题设置一个小的右插入。像这样:

button.imageEdgeInsets = UIEdgeInsetsMake(0., button.frame.size.width - (image.size.width + 15.), 0., 0.);
button.titleEdgeInsets = UIEdgeInsetsMake(0., 0., 0., image.size.width);

答案 4 :(得分:88)

我正在给予Inspire48这个奖励。根据他的建议并查看另一个问题,我提出了这个问题。子类UIButton并覆盖这些方法。

@implementation UIButtonSubclass

- (CGRect)imageRectForContentRect:(CGRect)contentRect
{
    CGRect frame = [super imageRectForContentRect:contentRect];
    frame.origin.x = CGRectGetMaxX(contentRect) - CGRectGetWidth(frame) -  self.imageEdgeInsets.right + self.imageEdgeInsets.left;
    return frame;
}

- (CGRect)titleRectForContentRect:(CGRect)contentRect
{
    CGRect frame = [super titleRectForContentRect:contentRect];
    frame.origin.x = CGRectGetMinX(frame) - CGRectGetWidth([self imageRectForContentRect:contentRect]);
    return frame;
}

@end

答案 5 :(得分:75)

更改标题时更新插图。您需要在另一侧使用相等且相反的插入来补偿插入。

[thebutton setTitle:title forState:UIControlStateNormal];
thebutton.titleEdgeInsets = UIEdgeInsetsMake(0, -thebutton.imageView.frame.size.width, 0, thebutton.imageView.frame.size.width);
thebutton.imageEdgeInsets = UIEdgeInsetsMake(0, thebutton.titleLabel.frame.size.width, 0, -thebutton.titleLabel.frame.size.width);

答案 6 :(得分:59)

截至2016年1月,所有这些答案都是不必要的。在Interface Builder中,将View Semantic设置为Force Right-to-Left,或者如果您更喜欢编程方式,semanticContentAttribute = .forceRightToLeft这将导致图像显示在文本的右侧。

答案 7 :(得分:51)

在界面构建器中,您可以为UIButton配置选项Edge Insets,分别为三个部分:内容,图像,标题

enter image description here enter image description here

Xcode 8:

enter image description here

答案 8 :(得分:23)

更新:Swift 3

class ButtonIconRight: UIButton {
    override func imageRect(forContentRect contentRect:CGRect) -> CGRect {
        var imageFrame = super.imageRect(forContentRect: contentRect)
        imageFrame.origin.x = super.titleRect(forContentRect: contentRect).maxX - imageFrame.width
        return imageFrame
    }

    override func titleRect(forContentRect contentRect:CGRect) -> CGRect {
        var titleFrame = super.titleRect(forContentRect: contentRect)
        if (self.currentImage != nil) {
            titleFrame.origin.x = super.imageRect(forContentRect: contentRect).minX
        }
        return titleFrame
    }
}

Swift 2的原始答案:

使用Swift实现示例处理所有水平对齐的解决方案。如果需要,只需转换为Objective-C.

class ButtonIconRight: UIButton {
    override func imageRectForContentRect(contentRect:CGRect) -> CGRect {
        var imageFrame = super.imageRectForContentRect(contentRect)
        imageFrame.origin.x = CGRectGetMaxX(super.titleRectForContentRect(contentRect)) - CGRectGetWidth(imageFrame)
        return imageFrame
    }

    override func titleRectForContentRect(contentRect:CGRect) -> CGRect {
        var titleFrame = super.titleRectForContentRect(contentRect)
        if (self.currentImage != nil) {
            titleFrame.origin.x = CGRectGetMinX(super.imageRectForContentRect(contentRect))
        }
        return titleFrame
    }
}

另外值得注意的是,它处理得非常好。标题插入。

受到jasongregori回答的启发;)

答案 9 :(得分:7)

以下是具有中心对齐内容的UIButton解决方案。 此代码使图像右对齐,并允许使用imageEdgeInsetstitleEdgeInsets进行宝贵的定位。

enter image description here

使用您的自定义类子级UIButton并添加:

- (CGRect)imageRectForContentRect:(CGRect)contentRect {
    CGRect frame = [super imageRectForContentRect:contentRect];
    CGFloat imageWidth = frame.size.width;
    CGRect titleRect = CGRectZero;
    titleRect.size = [[self titleForState:self.state] sizeWithAttributes:@{NSFontAttributeName: self.titleLabel.font}];
    titleRect.origin.x = (self.frame.size.width - (titleRect.size.width + imageWidth)) / 2.0 + self.titleEdgeInsets.left - self.titleEdgeInsets.right;
    frame.origin.x = titleRect.origin.x + titleRect.size.width - self.imageEdgeInsets.right + self.imageEdgeInsets.left;
    return frame;
}

- (CGRect)titleRectForContentRect:(CGRect)contentRect {
    CGFloat imageWidth = [self imageForState:self.state].size.width;
    CGRect frame = [super titleRectForContentRect:contentRect];
    frame.origin.x = (self.frame.size.width - (frame.size.width + imageWidth)) / 2.0 + self.titleEdgeInsets.left - self.titleEdgeInsets.right;
    return frame;
}

答案 10 :(得分:7)

如果需要在 UIBarButtonItem 中完成此操作,则应使用视图中的其他包装 这将有效

let view = UIView()
let button = UIButton()
button.setTitle("Skip", for: .normal)
button.setImage(#imageLiteral(resourceName:"forward_button"), for: .normal)
button.semanticContentAttribute = .forceRightToLeft
button.sizeToFit()
view.addSubview(button)
view.frame = button.bounds
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: view)

这项工作

let button = UIButton()
button.setTitle("Skip", for: .normal)
button.setImage(#imageLiteral(resourceName:"forward_button"), for: .normal)
button.semanticContentAttribute = .forceRightToLeft
button.sizeToFit()
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: button)

答案 11 :(得分:6)

我决定不使用标准的按钮图像视图,因为所提出的解决方案使该按钮看起来有些黑。这给了我理想的美感,并且通过更改约束来重新定位按钮很直观:

extension UIButton {
    func addRightIcon(image: UIImage) {
        let imageView = UIImageView(image: image)
        imageView.translatesAutoresizingMaskIntoConstraints = false

        addSubview(imageView)

        let length = CGFloat(15)
        titleEdgeInsets.right += length

        NSLayoutConstraint.activate([
            imageView.leadingAnchor.constraint(equalTo: self.titleLabel!.trailingAnchor, constant: 10),
            imageView.centerYAnchor.constraint(equalTo: self.titleLabel!.centerYAnchor, constant: 0),
            imageView.widthAnchor.constraint(equalToConstant: length),
            imageView.heightAnchor.constraint(equalToConstant: length)
        ])
    }
}

button with right arrow

答案 12 :(得分:4)

由于转换解决方案在iOS 11中不起作用,我决定编写一种新方法。

调整按钮semanticContentAttribute可以很好地向右显示图像,而不必在文本发生变化时重新布局。因此,它是理想的解决方案。但是我仍然需要RTL支持。应用无法在同一会话中更改其布局方向这一事实可以轻松解决此问题。

据说,这很直接。

extension UIButton {
    func alignImageRight() {
        if UIApplication.shared.userInterfaceLayoutDirection == .leftToRight {
            semanticContentAttribute = .forceRightToLeft
        }
        else {
            semanticContentAttribute = .forceLeftToRight
        }
    }
}

答案 13 :(得分:3)

以Piotr Tomasik优雅的解决方案为基础:如果你想在按钮标签和图像之间有一点 间距 ,那么在你的边缘插入包括如下(复制我的代码,这对我来说很完美):

    CGFloat spacing          = 3;
    CGFloat insetAmount      = 0.5 * spacing;

    // First set overall size of the button:
    button.contentEdgeInsets = UIEdgeInsetsMake(0, insetAmount, 0, insetAmount);
    [button sizeToFit];

    // Then adjust title and image insets so image is flipped to the right and there is spacing between title and image:
    button.titleEdgeInsets   = UIEdgeInsetsMake(0, -button.imageView.frame.size.width - insetAmount, 0,  button.imageView.frame.size.width  + insetAmount);
    button.imageEdgeInsets   = UIEdgeInsetsMake(0, button.titleLabel.frame.size.width + insetAmount, 0, -button.titleLabel.frame.size.width - insetAmount);

感谢Piotr的解决方案!

埃里克

答案 14 :(得分:2)

动手做。 Xcode10,swift4,

用于以编程方式进行UI设计

enter image description here

 lazy var buttonFilter : ButtonRightImageLeftTitle = {
    var button = ButtonRightImageLeftTitle()
    button.setTitle("Playfir", for: UIControl.State.normal)
    button.setImage(UIImage(named: "filter"), for: UIControl.State.normal)
    button.backgroundColor = UIColor.red
    button.contentHorizontalAlignment = .left
    button.titleLabel?.font = UIFont.systemFont(ofSize: 16)
    return button
}()
  

边缘插入值应用于矩形以缩小或扩展   该矩形代表的区域。通常,使用边缘插图   在视图布局期间修改视图的框架。正值导致   要插入(或缩小)指定数量的帧。负   值导致框架以指定的位置开始(或扩展)   数量。

class ButtonRightImageLeftTitle: UIButton {

    override func layoutSubviews() {
        super.layoutSubviews()

        guard imageView != nil else { return }

        imageEdgeInsets = UIEdgeInsets(top: 5, left: (bounds.width - 35), bottom: 5, right: 5)
        titleEdgeInsets = UIEdgeInsets(top: 0, left: -((imageView?.bounds.width)! + 10), bottom: 0, right: 0 )

    }
}

用于StoryBoard UI设计

enter image description here enter image description here

答案 15 :(得分:2)

取了@Piotr的答案,并将其变成了Swift扩展。确保在调用之前设置图像和标题,以便按钮大小正确。

extension UIButton {

/// Makes the ``imageView`` appear just to the right of the ``titleLabel``.
func alignImageRight() {
    if let titleLabel = self.titleLabel, imageView = self.imageView {
        // Force the label and image to resize.
        titleLabel.sizeToFit()
        imageView.sizeToFit()
        imageView.contentMode = .ScaleAspectFit

        // Set the insets so that the title appears to the left and the image appears to the right. 
        // Make the image appear slightly off the top/bottom edges of the button.
        self.titleEdgeInsets = UIEdgeInsets(top: 0, left: -1 * imageView.frame.size.width,
            bottom: 0, right: imageView.frame.size.width)
        self.imageEdgeInsets = UIEdgeInsets(top: 4, left: titleLabel.frame.size.width,
            bottom: 4, right: -1 * titleLabel.frame.size.width)
    }
}

}

答案 16 :(得分:2)

扩展方式

使用扩展程序在右侧使用自定义偏移设置图像

public class CustomContext: DbContext
{
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        foreach (var type in modelBuilder.Model.GetEntityTypes().Select(c => c.ClrType))
        {
            modelBuilder.Entity(type, b =>
            {              
                b.Property("Id").HasValueGenerator<IntValueGenerator>();
            });
        }
        base.OnModelCreating(modelBuilder);
    }
}

答案 17 :(得分:2)

Swift - 扩展UiButton并放置这些行

    if let imageWidth = self.imageView?.frame.width {
        self.titleEdgeInsets = UIEdgeInsetsMake(0, -imageWidth, 0, imageWidth);
    }

    if let titleWidth = self.titleLabel?.frame.width {
        let spacing = titleWidth + 20
        self.imageEdgeInsets = UIEdgeInsetsMake(0, spacing, 0, -spacing);
    }

答案 18 :(得分:2)

一个快速选项,可以在不玩任何插入的情况下执行您想要的操作:

class RightImageButton: UIButton {

    override func layoutSubviews() {
        super.layoutSubviews()

        if let  textSize = titleLabel?.intrinsicContentSize(),
                imageSize = imageView?.intrinsicContentSize() {
            let wholeWidth = textSize.width + K.textImageGap + imageSize.width
            titleLabel?.frame = CGRect(
                x: round(bounds.width/2 - wholeWidth/2),
                y: 0,
                width: ceil(textSize.width),
                height: bounds.height)
            imageView?.frame = CGRect(
                x: round(bounds.width/2 + wholeWidth/2 - imageSize.width),
                y: RoundRetina(bounds.height/2 - imageSize.height/2),
                width: imageSize.width,
                height: imageSize.height)
        }
    }

    struct K {
        static let textImageGap: CGFloat = 5
    }

}

答案 19 :(得分:1)

子类化和覆盖布局子视图可能是您的最佳选择。

参考:iPhone UIButton - image position

答案 20 :(得分:1)

Xcode 11.4 Swift 5.2

对于任何试图将人字形镜像后退按钮样式的人:

enter image description here

import UIKit

class NextBarButton: UIBarButtonItem {

    convenience init(target: Any, selector: Selector) {

        // Create UIButton
        let button = UIButton(frame: .zero)

        // Set Title
        button.setTitle("Next", for: .normal)
        button.setTitleColor(.systemBlue, for: .normal)
        button.titleLabel?.font = UIFont.systemFont(ofSize: 17)

        // Configure Symbol
        let config = UIImage.SymbolConfiguration(pointSize: 19.0, weight: .semibold, scale: .large)
        let image = UIImage(systemName: "chevron.right", withConfiguration: config)
        button.setImage(image, for: .normal)

        // Add Target
        button.addTarget(target, action: selector, for: .touchUpInside)

        // Put the Image on the right hand side of the button
        // Credit to liau-jian-jie for this part
        button.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
        button.titleLabel?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
        button.imageView?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)

        // Customise spacing to match system Back button
        button.imageEdgeInsets = UIEdgeInsets(top: 0.0, left: -18.0, bottom: 0.0, right: 0.0)
        button.titleEdgeInsets = UIEdgeInsets(top: 0.0, left: -12.0, bottom: 0.0, right: 0.0)

        self.init(customView: button)
    }
}

实施:

override func viewDidLoad() {
    super.viewDidLoad()
    let nextButton = NextBarButton(target: self, selector: #selector(nextTapped))
    navigationItem.rightBarButtonItem = nextButton
}

@objc func nextTapped() {
    // your code
}

答案 21 :(得分:1)

此处提到的解决方案在我启用自动布局后停止工作。我必须拿出自己的:

子类UIButton并覆盖layoutSubviews方法:

//
//  MIThemeButtonImageAtRight.m
//  Created by Lukasz Margielewski on 7/9/13.
//

#import "MIThemeButtonImageAtRight.h"

static CGRect CGRectByApplyingUIEdgeInsets(CGRect frame, UIEdgeInsets insets);

@implementation MIThemeButtonImageAtRight

- (void)layoutSubviews
{
    [super layoutSubviews];

    CGRect contentFrame = CGRectByApplyingUIEdgeInsets(self.bounds, self.contentEdgeInsets);

    CGRect frameIcon = self.imageView.frame;
    CGRect frameText = self.titleLabel.frame;

    frameText.origin.x = CGRectGetMinX(contentFrame) + self.titleEdgeInsets.left;
    frameIcon.origin.x = CGRectGetMaxX(contentFrame) - CGRectGetWidth(frameIcon);

    self.imageView.frame = frameIcon;
    self.titleLabel.frame = frameText;
}

@end

static CGRect CGRectByApplyingUIEdgeInsets(CGRect frame, UIEdgeInsets insets){

    CGRect f = frame;

    f.origin.x += insets.left;
    f.size.width -= (insets.left + insets.right);
    f.origin.y += (insets.top);
    f.size.height -= (insets.top + insets.bottom);

    return f;

}

<强>结果:

enter image description here

答案 22 :(得分:0)

我最终创建了一个自定义按钮,该按钮允许从Inspector设置图像。下面是我的代码:

import UIKit

@IBDesignable
class CustomButton: UIButton {

    @IBInspectable var leftImage: UIImage? = nil
    @IBInspectable var gapPadding: CGFloat = 0

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }
    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        setup()
    }

    func setup() {

        if(leftImage != nil) {
            let imageView = UIImageView(image: leftImage)
            imageView.translatesAutoresizingMaskIntoConstraints = false

            addSubview(imageView)

            let length = CGFloat(16)
            titleEdgeInsets.left += length

            NSLayoutConstraint.activate([
                imageView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: gapPadding),
                imageView.centerYAnchor.constraint(equalTo: self.titleLabel!.centerYAnchor, constant: 0),
                imageView.widthAnchor.constraint(equalToConstant: length),
                imageView.heightAnchor.constraint(equalToConstant: length)
            ])
        }
    }
}

您可以在Inspector中调整“间隙填充”的值,以调整文本和图像之间的间距。

PS:使用了@Mark Hennings答案的一些代码部分

答案 23 :(得分:0)

最后,我得到了想要的完美结果。

这是我的代码。

self.semanticContentAttribute = .forceRightToLeft
self.contentHorizontalAlignment = .left

self.imageView?.translatesAutoresizingMaskIntoConstraints = false
self.imageView?.centerYAnchor.constraint(equalTo: self.centerYAnchor, constant: 0.0).isActive = true
self.imageView?.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 0.0).isActive = true

此代码使文本右/图像左按钮没有任何填充。

答案 24 :(得分:0)

如果你想让字符串在左边,图像在右边,这应该没问题(Swift 5)

/// [ String ------------------ Image ] Style Custom Button
/// For use, just define 'Title Text' and 'Image' on ib / source with setting the class 'DistantTextImageButton'.

class DistantTextImageButton: UIButton {
    override func layoutSubviews() {
        super.layoutSubviews()
        self.semanticContentAttribute = .forceRightToLeft
        self.contentHorizontalAlignment = .left

        guard let imageView = imageView,
              let title = title(for: .normal),
              let font = titleLabel?.font else { return }
       
        imageEdgeInsets = UIEdgeInsets(top: 0, left: bounds.width - imageView.bounds.width - title.textSizeWithFont(font).width, bottom: 0, right: 0)
        titleEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
    }
}

extension String {
    func textSizeWithFont(_ font: UIFont) -> CGSize {
        return self.size(withAttributes: [.font: font])
    }
}

答案 25 :(得分:0)

快速4和5

更改UIButton图像的方向(RTL和LTR)

extension UIButton {
    func changeDirection(){
       isArabic ? (self.contentHorizontalAlignment = .right) : (self.contentHorizontalAlignment = .left)
        // left-right margin 
        self.imageEdgeInsets = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
        self.titleEdgeInsets = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
    }
}

答案 26 :(得分:0)

对于此问题,您可以在“带有UIImage视图的标签”内部创建UIView,并将UIView类设置为UIControl,并在侧面创建IBAction

enter image description here

答案 27 :(得分:0)

在尝试了多种互联网解决方案后,我没有达到确切的要求。因此,我最终编写了自定义实用程序代码。发布以帮助将来的某人。 在4.2上测试过

// This function should be called in/after viewDidAppear to let view render
    func addArrowImageToButton(button: UIButton, arrowImage:UIImage = #imageLiteral(resourceName: "my_image_name") ) {
        let btnSize:CGFloat = 32
        let imageView = UIImageView(image: arrowImage)
        let btnFrame = button.frame
        imageView.frame = CGRect(x: btnFrame.width-btnSize-8, y: btnFrame.height/2 - btnSize/2, width: btnSize, height: btnSize)
        button.addSubview(imageView)
        //Imageview on Top of View
        button.bringSubviewToFront(imageView)
    }

答案 28 :(得分:0)

约束怎么样?与semanticContentAttribute不同,它们不会更改语义。也许是这样的事情:

 button.rightAnchorconstraint(equalTo: button.rightAnchor).isActive = true

或在Objective-C中:

[button.imageView.rightAnchor constraintEqualToAnchor:button.rightAnchor].isActive = YES;

警告:未经测试,iOS 9 +

答案 29 :(得分:0)

swift 3.0 迁移   jasongregori

给出的解决方案
class ButtonIconRight: UIButton {
        override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
            var imageFrame = super.imageRect(forContentRect: contentRect)
           imageFrame.origin.x = super.titleRect(forContentRect: contentRect).maxX - imageFrame.width
        return imageFrame
        }

        override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
            var titleFrame = super.titleRect(forContentRect: contentRect)
            if (self.currentImage != nil) {
                titleFrame.origin.x = super.imageRect(forContentRect: contentRect).minX
            }
            return titleFrame
        }

答案 30 :(得分:0)

斯威夫特3:

open override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
    var frame = super.imageRect(forContentRect: contentRect)
    let  imageWidth = frame.size.width
    var titleRect = CGRect.zero
    titleRect.size = self.title(for: self.state)!.size(attributes: [NSFontAttributeName: self.titleLabel!.font])
    titleRect.origin.x = (self.frame.size.width - (titleRect.size.width + imageWidth)) / 2.0 + self.titleEdgeInsets.left - self.titleEdgeInsets.right;
    frame.origin.x = titleRect.origin.x + titleRect.size.width - self.imageEdgeInsets.right + self.imageEdgeInsets.left;
    return frame
}

open override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
    var frame = super.titleRect(forContentRect: contentRect)
    if let imageWidth = self.image(for: self.state)?.size.width {
        frame.origin.x = (self.frame.size.width - (frame.size.width + imageWidth)) / 2.0 + self.titleEdgeInsets.left - self.titleEdgeInsets.right;
    }
    return frame
}

答案 31 :(得分:-1)

要在UIButton中使图像右对齐,请尝试以下代码

%windir%\SysWOW64\odbcad32.exe

答案 32 :(得分:-1)

感谢Vitaliy Gozhenko

我只想补充一点,您可以在按钮@interface之前添加IB_DESIGNABLE,并在storyborad中设置按钮类。然后,您可以实时观看布局,而无需在界面构建阶段启动应用程序

enter image description here