Label under image in UIButton

后端 未结 30 1973
佛祖请我去吃肉
佛祖请我去吃肉 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:19

    corrected one of the answers here:

    Swift 3:

    class CenteredButton: UIButton
    {
        override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
            let rect = super.titleRect(forContentRect: contentRect)
            let imageRect = super.imageRect(forContentRect: contentRect)
    
            return CGRect(x: 0, y: imageRect.maxY + 10,
                          width: contentRect.width, height: rect.height)
        }
    
        override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
            let rect = super.imageRect(forContentRect: contentRect)
            let titleRect = self.titleRect(forContentRect: contentRect)
    
            return CGRect(x: contentRect.width/2.0 - rect.width/2.0,
                          y: (contentRect.height - titleRect.height)/2.0 - rect.height/2.0,
                          width: rect.width, height: rect.height)
        }
    
        override init(frame: CGRect) {
            super.init(frame: frame)
            centerTitleLabel()
        }
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            centerTitleLabel()
        }
    
        private func centerTitleLabel() {
            self.titleLabel?.textAlignment = .center
        }
    }
    
    0 讨论(0)
  • 2020-11-29 16:20

    Or you can just use this category:

    ObjC

    @interface UIButton (VerticalLayout)
    
    - (void)centerVerticallyWithPadding:(float)padding;
    - (void)centerVertically;
    
    @end
    
    @implementation UIButton (VerticalLayout)
    
    - (void)centerVerticallyWithPadding:(float)padding {
        CGSize imageSize = self.imageView.frame.size;
        CGSize titleSize = self.titleLabel.frame.size;
        CGFloat totalHeight = (imageSize.height + titleSize.height + padding);
        
        self.imageEdgeInsets = UIEdgeInsetsMake(- (totalHeight - imageSize.height),
                                                0.0f,
                                                0.0f,
                                                - titleSize.width);
        
        self.titleEdgeInsets = UIEdgeInsetsMake(0.0f,
                                                - imageSize.width,
                                                - (totalHeight - titleSize.height),
                                                0.0f);
        
        self.contentEdgeInsets = UIEdgeInsetsMake(0.0f,
                                                  0.0f,
                                                  titleSize.height,
                                                  0.0f);
    }
    
    - (void)centerVertically {
        const CGFloat kDefaultPadding = 6.0f;
        [self centerVerticallyWithPadding:kDefaultPadding];
    }
    
    @end
    

    Swift extension

    extension UIButton {
        
        func centerVertically(padding: CGFloat = 6.0) {
            guard
                let imageViewSize = self.imageView?.frame.size,
                let titleLabelSize = self.titleLabel?.frame.size else {
                return
            }
            
            let totalHeight = imageViewSize.height + titleLabelSize.height + padding
            
            self.imageEdgeInsets = UIEdgeInsets(
                top: -(totalHeight - imageViewSize.height),
                left: 0.0,
                bottom: 0.0,
                right: -titleLabelSize.width
            )
            
            self.titleEdgeInsets = UIEdgeInsets(
                top: 0.0,
                left: -imageViewSize.width,
                bottom: -(totalHeight - titleLabelSize.height),
                right: 0.0
            )
            
            self.contentEdgeInsets = UIEdgeInsets(
                top: 0.0,
                left: 0.0,
                bottom: titleLabelSize.height,
                right: 0.0
            )
        }
        
    }
    

    Suggestion: If button height is less than totalHeight, then image will draw outside borders.

    imageEdgeInset.top should be:

    max(0, -(totalHeight - imageViewSize.height))
    
    0 讨论(0)
  • 2020-11-29 16:20

    I think one of the best ways to do that is by subclassing UIButton and override some rendering methods:

    - (void)awakeFromNib
    {
        [super awakeFromNib];
        [self setupSubViews];
    }
    
    - (instancetype)init
    {
        if (self = [super init])
        {
            [self setupSubViews];
        }
        return self;
    }
    
    - (void)setupSubViews
    {
        [self.imageView setTranslatesAutoresizingMaskIntoConstraints:NO];
        [self addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.imageView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
        [self.titleLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[imageView][titleLabel]|" options:NSLayoutFormatAlignAllCenterX metrics:nil views:@{@"imageView": self.imageView, @"titleLabel": self.titleLabel}]];
    }
    
    - (CGSize)intrinsicContentSize
    {
        CGSize imageSize = self.imageView.image.size;
        CGSize titleSize = [self.titleLabel.text sizeWithAttributes:@{NSFontAttributeName: self.titleLabel.font}];
        return CGSizeMake(MAX(imageSize.width, titleSize.width), imageSize.height + titleSize.height);
    }
    
    0 讨论(0)
  • 2020-11-29 16:22

    Using the code of Kenny Winker's and simeon i make this swift code that works for me.

    import UIKit
    
    @IBDesignable
    class TopIconButton: UIButton {
        override func layoutSubviews() {
            super.layoutSubviews()
    
            let kTextTopPadding:CGFloat = 3.0;
    
            var titleLabelFrame = self.titleLabel!.frame;
    
    
            let labelSize = titleLabel!.sizeThatFits(CGSizeMake(CGRectGetWidth(self.contentRectForBounds(self.bounds)), CGFloat.max))
    
            var imageFrame = self.imageView!.frame;
    
            let fitBoxSize = CGSizeMake(max(imageFrame.size.width, labelSize.width), labelSize.height + kTextTopPadding + imageFrame.size.    height)
    
            let fitBoxRect = CGRectInset(self.bounds, (self.bounds.size.width - fitBoxSize.width)/2, (self.bounds.size.height - fitBoxSize.    height)/2);
    
            imageFrame.origin.y = fitBoxRect.origin.y;
            imageFrame.origin.x = CGRectGetMidX(fitBoxRect) - (imageFrame.size.width/2);
            self.imageView!.frame = imageFrame;
    
            // Adjust the label size to fit the text, and move it below the image
    
            titleLabelFrame.size.width = labelSize.width;
            titleLabelFrame.size.height = labelSize.height;
            titleLabelFrame.origin.x = (self.frame.size.width / 2) - (labelSize.width / 2);
            titleLabelFrame.origin.y = fitBoxRect.origin.y + imageFrame.size.height + kTextTopPadding;
            self.titleLabel!.frame = titleLabelFrame;
            self.titleLabel!.textAlignment = .Center
        }
    
    }
    
    0 讨论(0)
  • You just have to adjust all three edge insets based on the size of your image and title label:

    button.contentEdgeInsets = UIEdgeInsetsMake(0, 0, titleLabelBounds.height + 4, 0)
    button.titleEdgeInsets = UIEdgeInsetsMake(image.size.height + 8, -image.size.width, 0, 0)
    button.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, -titleLabelBounds.width)
    

    You can get the title label bounds by calling sizeToFit after setting its text. The horizontal spacing should work regardless of the size of the text, font and image but I don't know of a single solution to get the vertical spacing and bottom content edge inset consistent.

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

    If you subclass UIButton and override layoutSubviews, you can use the below to center the image and place the title centered below it:

    kTextTopPadding is a constant you'll have to introduce that determines the space between the image and the text below it.

    -(void)layoutSubviews {
        [super layoutSubviews];
    
        // Move the image to the top and center it horizontally
        CGRect imageFrame = self.imageView.frame;
        imageFrame.origin.y = 0;
        imageFrame.origin.x = (self.frame.size.width / 2) - (imageFrame.size.width / 2);
        self.imageView.frame = imageFrame;
    
        // Adjust the label size to fit the text, and move it below the image
        CGRect titleLabelFrame = self.titleLabel.frame;
        CGSize labelSize = [self.titleLabel.text sizeWithFont:self.titleLabel.font
                                            constrainedToSize:CGSizeMake(self.frame.size.width, CGFLOAT_MAX)
                                            lineBreakMode:NSLineBreakByWordWrapping];
        titleLabelFrame.size.width = labelSize.width;
        titleLabelFrame.size.height = labelSize.height;
        titleLabelFrame.origin.x = (self.frame.size.width / 2) - (labelSize.width / 2);
        titleLabelFrame.origin.y = self.imageView.frame.origin.y + self.imageView.frame.size.height + kTextTopPadding;
        self.titleLabel.frame = titleLabelFrame;
    
    }
    
    0 讨论(0)
提交回复
热议问题