Label under image in UIButton

后端 未结 30 1976
佛祖请我去吃肉
佛祖请我去吃肉 2020-11-29 15:53

I\'m trying to create a button which has some text beneath the icon (sorta like the app buttons) however it seems to be quite difficult to achieve. Any ideas how can I go ab

相关标签:
30条回答
  • 2020-11-29 16:39

    Top image and bottom title button with subclassing UIButton

    class VerticalButton: UIButton {
      override func layoutSubviews() {
        super.layoutSubviews()
        let padding: CGFloat = 8
        let iH = imageView?.frame.height ?? 0
        let tH = titleLabel?.frame.height ?? 0
        let v: CGFloat = (frame.height - iH - tH - padding) / 2
        if let iv = imageView {
          let x = (frame.width - iv.frame.width) / 2
          iv.frame.origin.y = v
          iv.frame.origin.x = x
        }
    
        if let tl = titleLabel {
          let x = (frame.width - tl.frame.width) / 2
          tl.frame.origin.y = frame.height - tl.frame.height - v
          tl.frame.origin.x = x
        }
      }
    }
    
    0 讨论(0)
  • 2020-11-29 16:40

    Instead of going through hell trying to position the icon and the text with edge insets, you could create a NSAttributedString with your image as an attachment and set it to your button's attributed title instead:

    let titleText = NSAttributedString(string: yourTitle, attributes: attributes)
    let imageAttachment = NSTextAttachment()
    imageAttachment.image = yourImage
    
    let title = NSMutableAttributedString(string: "")
    title.append(NSAttributedString(attachment: imageAttachment))
    title.append(titleText)
    
    button.setAttributedTitle(title, for: .normal)
    
    0 讨论(0)
  • 2020-11-29 16:42

    Localization Friendly Solution:

    So many great solutions guys, but I'd like to add a note here for those who use localization.

    You need to reverse the left and right EdgeInstets values to get the button laid out correctly in case of a change of language direction from LtR to RtL.

    Using a similar solution I'd implement it as follows:

    extension UIButton {
    
        func alignVertical(spacing: CGFloat, lang: String) {
            guard let imageSize = self.imageView?.image?.size,
                let text = self.titleLabel?.text,
                let font = self.titleLabel?.font
            else { return }
    
            let labelString = NSString(string: text)
            let titleSize = labelString.size(
                withAttributes: [NSAttributedString.Key.font: font]
            )
    
            var titleLeftInset: CGFloat = -imageSize.width
            var titleRigtInset: CGFloat = 0.0
    
            var imageLeftInset: CGFloat = 0.0
            var imageRightInset: CGFloat = -titleSize.width
    
            if Locale.current.languageCode! != "en" { // If not Left to Right language
                titleLeftInset = 0.0
                titleRigtInset = -imageSize.width
    
                imageLeftInset = -titleSize.width
                imageRightInset = 0.0
            }
    
            self.titleEdgeInsets = UIEdgeInsets(
                top: 0.0,
                left: titleLeftInset,
                bottom: -(imageSize.height + spacing),
                right: titleRigtInset
            )
            self.imageEdgeInsets = UIEdgeInsets(
                top: -(titleSize.height + spacing),
                left: imageLeftInset,
                bottom: 0.0,
                right: imageRightInset
            )
            let edgeOffset = abs(titleSize.height - imageSize.height) / 2.0;
            self.contentEdgeInsets = UIEdgeInsets(
                top: edgeOffset,
                left: 0.0,
                bottom: edgeOffset,
                right: 0.0
            )
        }
    }
    
    
    0 讨论(0)
  • 2020-11-29 16:43

    Refactored icecrystal23`s answer.

    Swift 3, works with autolayouts, xib, storyboards, can be animated.

    Button in orginal icecrystal23`s answer had a badly calculated frame. I think I fixed that.

    Edit: Updated to Swift 5 and made work inside Interface Builder / Storyboards

    import UIKit
    
    @IBDesignable
    class VerticalButton: UIButton {
    
        @IBInspectable public var padding: CGFloat = 20.0 {
            didSet {
                setNeedsLayout()
            }
        }
    
        override var intrinsicContentSize: CGSize {
            let maxSize = CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)
    
            if let titleSize = titleLabel?.sizeThatFits(maxSize), let imageSize = imageView?.sizeThatFits(maxSize) {
                let width = ceil(max(imageSize.width, titleSize.width))
                let height = ceil(imageSize.height + titleSize.height + padding)
    
                return CGSize(width: width, height: height)
            }
    
            return super.intrinsicContentSize
        }
    
        override func layoutSubviews() {
            if let image = imageView?.image, let title = titleLabel?.attributedText {
                let imageSize = image.size
                let titleSize = title.size()
    
                titleEdgeInsets = UIEdgeInsets(top: 0.0, left: -imageSize.width, bottom: -(imageSize.height + padding), right: 0.0)
                imageEdgeInsets = UIEdgeInsets(top: -(titleSize.height + padding), left: 0.0, bottom: 0.0, right: -titleSize.width)
            }
    
            super.layoutSubviews()
        }
    
    }
    
    0 讨论(0)
  • 2020-11-29 16:43

    If you are using custom fonts the calculation for the titleLabel size won't work properly, you should replace it with

    let titleLabelSize = self.titleLabel?.text?.size(withAttributes: [NSAttributedStringKey.font: self.titleLabel!.font!])

    0 讨论(0)
  • 2020-11-29 16:43

    Something like this inside UIButton subclass

    public override func layoutSubviews() {
        super.layoutSubviews()
    
        imageEdgeInsets = UIEdgeInsetsMake(-10, 0, 0, 0)
        titleEdgeInsets = UIEdgeInsetsMake(0, -bounds.size.width/2 - 10, -30, 0)
    }
    
    0 讨论(0)
提交回复
热议问题