iPhone UIButton - 图像位置

问题描述 投票:0回答:17

我有一个

UIButton
,其中包含“探索应用程序”和
UIImage
(>) 在
Interface Builder
中,它看起来像:

[ (>) Explore the app ]

但是我需要将其

UIImage
放在文本之后:

[ Explore the app (>) ]

如何将

UIImage
移至右侧?

ios iphone cocoa-touch uibutton imageedgeinsets
17个回答
164
投票

我的解决方案非常简单

[button sizeToFit];
button.titleEdgeInsets = UIEdgeInsetsMake(0, -button.imageView.frame.size.width, 0, button.imageView.frame.size.width);
button.imageEdgeInsets = UIEdgeInsetsMake(0, button.titleLabel.frame.size.width, 0, -button.titleLabel.frame.size.width);

138
投票

iOS 9 开始,似乎实现此目的的一个简单方法是强制视图的语义。

enter image description here

或者以编程方式使用:

button.semanticContentAttribute = .ForceRightToLeft

86
投票

设置

imageEdgeInset
titleEdgeInset
以在图像内移动组件。您还可以使用这些全尺寸图形创建一个按钮,并将其用作按钮的背景图像(然后使用
titleEdgeInsets
移动标题)。


54
投票

Raymond W 的答案在这里是最好的。使用自定义布局子视图子类化 UIButton。做起来非常简单,这是一个对我有用的layoutSubviews实现:

- (void)layoutSubviews
{
    // Allow default layout, then adjust image and label positions
    [super layoutSubviews];

    UIImageView *imageView = [self imageView];
    UILabel *label = [self titleLabel];

    CGRect imageFrame = imageView.frame;
    CGRect labelFrame = label.frame;

    labelFrame.origin.x = imageFrame.origin.x;
    imageFrame.origin.x = labelFrame.origin.x + CGRectGetWidth(labelFrame);

    imageView.frame = imageFrame;
    label.frame = labelFrame;
}

30
投票

子类化

UIButton
和重写
layoutSubviews
怎么样?

然后对

self.imageView
self.titleLabel

的位置进行后处理

14
投票

另一种简单的方法(不仅仅适用于 iOS 9)是子类化 UIButton 来重写这两个方法

override func titleRectForContentRect(contentRect: CGRect) -> CGRect {
    var rect = super.titleRectForContentRect(contentRect)
    rect.origin.x = 0
    return rect
}

override func imageRectForContentRect(contentRect: CGRect) -> CGRect {
    var rect = super.imageRectForContentRect(contentRect)
    rect.origin.x = CGRectGetMaxX(contentRect) - CGRectGetWidth(rect)
    return rect
}
使用 super 已经考虑到了

contentEdgeInsets


10
投票

如果您的应用同时支持“从左到右”和“从右到左”,则不能选择强制按钮“从右到左”。

对我有用的解决方案是一个子类,可以添加到情节提要中的按钮,并且可以很好地处理约束(在 iOS 11 中测试):

class ButtonWithImageAtEnd: UIButton {

    override func layoutSubviews() {
        super.layoutSubviews()

        if let imageView = imageView, let titleLabel = titleLabel {
            let padding: CGFloat = 15
            imageEdgeInsets = UIEdgeInsets(top: 5, left: titleLabel.frame.size.width+padding, bottom: 5, right: -titleLabel.frame.size.width-padding)
            titleEdgeInsets = UIEdgeInsets(top: 0, left: -imageView.frame.width, bottom: 0, right: imageView.frame.width)
        }

    }

}

“padding”是标题和图像之间的空格。


5
投票

在斯威夫特:

override func layoutSubviews(){
    super.layoutSubviews()

    let inset: CGFloat = 5

    if var imageFrame = self.imageView?.frame,
       var labelFrame = self.titleLabel?.frame {

       let cumulativeWidth = imageFrame.width + labelFrame.width + inset
       let excessiveWidth = self.bounds.width - cumulativeWidth
       labelFrame.origin.x = excessiveWidth / 2
       imageFrame.origin.x = labelFrame.origin.x + labelFrame.width + inset

       self.imageView?.frame = imageFrame
       self.titleLabel?.frame = labelFrame  
    }
}

4
投票

通过@split构建答案...

答案很棒,但它忽略了这样一个事实:按钮可能具有预先设置的自定义图像和标题边缘插图(例如在故事板中)。

例如,您可能希望图像在容器的顶部和底部有一些填充,但仍将图像移动到按钮的右侧。

我用这个方法扩展了这个概念:-

- (void) moveImageToRightSide {
    [self sizeToFit];

    CGFloat titleWidth = self.titleLabel.frame.size.width;
    CGFloat imageWidth = self.imageView.frame.size.width;
    CGFloat gapWidth = self.frame.size.width - titleWidth - imageWidth;
    self.titleEdgeInsets = UIEdgeInsetsMake(self.titleEdgeInsets.top,
                                            -imageWidth + self.titleEdgeInsets.left,
                                            self.titleEdgeInsets.bottom,
                                            imageWidth - self.titleEdgeInsets.right);

    self.imageEdgeInsets = UIEdgeInsetsMake(self.imageEdgeInsets.top,
                                            titleWidth + self.imageEdgeInsets.left + gapWidth,
                                            self.imageEdgeInsets.bottom,
                                            -titleWidth + self.imageEdgeInsets.right - gapWidth);
}

2
投票
// Get the size of the text and image
CGSize buttonLabelSize = [[self.button titleForState:UIControlStateNormal] sizeWithFont:self.button.titleLabel.font];
CGSize buttonImageSize = [[self.button imageForState:UIControlStateNormal] size];

// You can do this line in the xib too:
self.button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;

// Adjust Edge Insets according to the above measurement. The +2 adds a little space 
self.button.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, -(buttonLabelSize.width+2));
self.button.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, buttonImageSize.width+2);

这将创建一个右对齐按钮,如下所示:

[           button label (>)]

按钮不会根据上下文调整其宽度,因此标签左侧会出现空格。您可以通过从buttonLabelSize.width和buttonImageSize.width计算按钮的框架宽度来解决这个问题。


1
投票
button.semanticContentAttribute = UISemanticContentAttributeForceRightToLeft;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;

1
投票

基于之前的答案。如果您希望图标和按钮标题之间有一个边距,则必须对代码进行一些更改,以防止标签和图标浮动到固有尺寸按钮的边界上方。

let margin = CGFloat(4.0)
button.titleEdgeInsets = UIEdgeInsetsMake(0, -button.imageView.frame.size.width, 0, button.imageView.frame.size.width);
button.imageEdgeInsets = UIEdgeInsetsMake(0, button.titleLabel.frame.size.width, 0, -button.titleLabel.frame.size.width)
button.contentEdgeInsets = UIEdgeInsetsMake(0, margin, 0, margin)

最后一行代码对于自动布局的本质内容大小计算很重要。


1
投票

Swift 中的单行解决方案:

// iOS 9 and Onwards
button.semanticContentAttribute = .forceRightToLeft

0
投票

此解决方案适用于 iOS 7 及更高版本

只是 UIButton 的子类

@interface UIButton (Image)

- (void)swapTextWithImage;

@end

@implementation UIButton (Image)

- (void)swapTextWithImage {
   const CGFloat kDefaultPadding = 6.0f;
   CGSize buttonSize = [self.titleLabel.text sizeWithAttributes:@{
                                                               NSFontAttributeName:self.titleLabel.font
                                                               }];

   self.titleEdgeInsets = UIEdgeInsetsMake(0, -self.imageView.frame.size.width, 0, self.imageView.frame.size.width);
   self.imageEdgeInsets = UIEdgeInsetsMake(0, buttonSize.width + kDefaultPadding, 0, -buttonSize.width); 
}

@end

用法(课堂上的某个地方):

[self.myButton setTitle:@"Any text" forState:UIControlStateNormal];
[self.myButton swapTextWithImage];

0
投票

这是我自己的做法,(大约10年后)

  1. UIButton 的子类(Button,因为我们生活在 Swift 时代)
  2. 将图像和标签放入堆栈视图中。
class CustomButton: Button {

    var didLayout: Bool = false // The code must be called only once

    override func layoutSubviews() {
        super.layoutSubviews()
        if !didLayout, let imageView = imageView, let titleLabel = titleLabel {
            didLayout = true
            let stack = UIStackView(arrangedSubviews: [titleLabel, imageView])
            addSubview(stack)
            stack.edgesToSuperview() // I use TinyConstraints library. You could handle the constraints directly
            stack.axis = .horizontal
        }
    }
}

0
投票

我尝试了该解决方案,并且有效,但它使标题+图像居中。按照我的方法,我需要将文本放在导航栏上并将图像放在右侧。

我实现了这个自定义视图:

class CenteredViewWithImage: UIView {
    
    // MARK: - Vars
    private let marginBetweenElements: CGFloat = 10.0
    private let imageViewWidth: CGFloat = 20.0

    private weak var spaceView: UIView?
    private weak var titleLabel: UILabel?
    private weak var imageView: UIImageView?
    
    var title: String? {
        willSet {
            self.titleLabel?.text = newValue
        }
    }
    
    // MARK: - LifeCycle
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.commonSetup()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        self.commonSetup()
    }
    
    // MARK: - Setup
    private func commonSetup() {
        let spaceView = UIView.init()
        self.spaceView = spaceView
        self.addSubview(spaceView)
        
        let titleLabel = UILabel.init()
        self.titleLabel = titleLabel
        self.titleLabel?.text = nil
        self.titleLabel?.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
        self.titleLabel?.lineBreakMode = .byTruncatingTail
        self.titleLabel?.textAlignment = .center
        self.addSubview(titleLabel)
        
        let imageView = UIImageView.init()
        self.imageView = imageView
        self.imageView?.image = UIImage.init(named: "image_name")
        self.imageView?.contentMode = .scaleAspectFit
        self.addSubview(imageView)
        
        self.addConstraints()
    }
    
    // MARK: - Helper
    private func addConstraints() {
        guard let spaceView = self.spaceView,
              let titleLabel = self.titleLabel,
              let imageView = self.imageView else { return }
        
        let guide = self.safeAreaLayoutGuide
        
        self.spaceView?.translatesAutoresizingMaskIntoConstraints = false
        self.spaceView?.topAnchor.constraint(equalTo: guide.topAnchor).isActive = true
        self.spaceView?.leadingAnchor.constraint(equalTo: guide.leadingAnchor).isActive = true
        guide.bottomAnchor.constraint(equalTo: spaceView.bottomAnchor).isActive = true
        self.spaceView?.widthAnchor.constraint(equalTo: imageView.widthAnchor).isActive = true
        
        self.titleLabel?.translatesAutoresizingMaskIntoConstraints = false
        self.titleLabel?.topAnchor.constraint(equalTo: guide.topAnchor).isActive = true
        self.titleLabel?.leadingAnchor.constraint(equalTo: spaceView.trailingAnchor, constant: self.marginBetweenElements).isActive = true
        guide.bottomAnchor.constraint(equalTo: titleLabel.bottomAnchor).isActive = true
        
        self.imageView?.translatesAutoresizingMaskIntoConstraints = false
        self.imageView?.topAnchor.constraint(equalTo: guide.topAnchor).isActive = true
        self.imageView?.leadingAnchor.constraint(equalTo: titleLabel.trailingAnchor, constant: self.marginBetweenElements).isActive = true
        guide.trailingAnchor.constraint(equalTo: imageView.trailingAnchor).isActive = true
        guide.bottomAnchor.constraint(equalTo: imageView.bottomAnchor).isActive = true
        self.imageView?.widthAnchor.constraint(equalToConstant: self.imageViewWidth).isActive = true
        self.imageView?.heightAnchor.constraint(equalTo: imageView.widthAnchor).isActive = true
    }
}

使用方法:

 let centeredView = CenteredViewWithImage.init()
 self.centeredView = centeredView
 self.centeredView?.title = "text centered"
 let tapGesture: UITapGestureRecognizer = UITapGestureRecognizer.init(target: self, action: #selector(self.centeredViewHasBeenPressed))
 self.centeredView?.addGestureRecognizer(tapGesture)
 self.navigationItem.titleView = self.centeredView
    @objc
    private func centeredViewHasBeenPressed() {
        debugPrint("do something")
    }

外观如何:

text centered on navigationbar


0
投票

你可以自定义使用UIView,如果你使用这种方式,可以为你的视图使用最大自定义

© www.soinside.com 2019 - 2024. All rights reserved.