如果可以避免,我不想使用子视图。我想要一个带有背景图像,文本和图像的UIButton。现在,当我这样做的时候,图像在文本的左边。背景图像、文本和图像都有不同的高亮状态。


当前回答

在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的解决方案!

Erik

其他回答

Xcode 11.4 Swift 5.2

对于任何试图镜像后退按钮样式的人,像这样的雪佛龙:

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
}

最简单的解决方案:

iOS 10及以上版本,Swift:

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

iOS 9及以上版本,Swift:(推荐)

button.semanticContentAttribute = .forceRightToLeft

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

调整按钮semanticContentAttribute可以让我们很好地将图像放到右边,而不必在文本更改时重新布局。因此它是理想溶液。然而,我仍然需要RTL的支持。事实上,一个应用程序不能改变它的布局方向在同一会话解决这个问题很容易。

话虽如此,它还是相当直截了当的。

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

当标题发生变化时,只需更新插图即可。你需要在另一侧用等量的、相反的插页来补偿插页。

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

更新XCODE 9(通过接口生成器)

在Interface Builder中有一个更简单的方法。

选择UIButton并在View Utilities > Semantic中选择这个选项:

就是这样!很好很简单!

可选-第二步:

如果你想调整图像和标题之间的间距,你可以在这里更改图像插入: