IPhone UIButton-图像位置

我有一个 UIButton与文本“探索应用程序”和 UIImage(>) 在 Interface Builder中,它看起来像:

[ (>) Explore the app ]

但是我需要把这个 UIImage放在文本后面:

[ Explore the app (>) ]

如何将 UIImage向右移动?

89512 次浏览

设置 imageEdgeInsettitleEdgeInset来移动图像中的组件。您还可以使用这些全尺寸图形创建一个按钮,并使用它作为该按钮的背景图像(然后使用 titleEdgeInsets来移动标题)。

如何子类化 UIButton并覆盖 layoutSubviews

然后对 self.imageViewself.titleLabel的位置进行后期处理

雷蒙德 · W 的答案是最好的。具有自定义 layoutSubviews 的子类 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;
}
// 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 (>)]

The button doesn't adjust it's width according to the context, so space will appear on the left of the label. You could solve this by calculating the button's frame width from the buttonLabelSize.width and the buttonImageSize.width.

我的解决办法很简单

[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);

通过“分裂”构建答案。

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

For instance, you may want the image have some padding from the top and bottom of the container, but still move the image to the right side of the button.

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

- (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);
}

斯威夫特:

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
}
}

IOS9开始,似乎实现这一点的一个简单方法就是强制语义的观点。

enter image description here

或者以编程方式,使用:

button.semanticContentAttribute = .ForceRightToLeft
button.semanticContentAttribute = UISemanticContentAttributeForceRightToLeft;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;

另一个简单的方法(不仅仅是 iOS9)是子类 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

此解决方案适用于 iOS7及以上版本

只是 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];

以前的答案为基础。如果你想在图标和按钮的标题之间有一个边距,代码必须稍微改变一下,以防止标签和图标漂浮在按钮本身大小的边界之上。

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)

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

如果你的应用程序同时支持“从左到右”和“从右到左”,那么强制“从右到左”按钮是不可行的。

The solution that worked for me is a subclass that can be added to the button in the Storyboard and works well with constraints (tested in 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)
}


}


}

其中“填充”是标题和图像之间的空格。

这是我自己的方法,(大约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
}
}
}

Swift 中的单行解决方案:

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

我尝试了解决方案,并工作,但它的中心标题 + 图像。在我的方法 我需要以导航栏为中心的文本和右边的图像。

我实现了这个定制视图:

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