HiDungLing
HiDungLing

Reputation: 247

Button and Image Alignment issues in UIButton

So I have a UIBarbuttonItem that I am currently designing based off of a layout that I have done.

import Foundation
import UIKit

class LocationManager: UIBarButtonItem {
    var viewController: MainViewController?

    lazy var customButton : UIButton = {
        let customButton = UIButton(type: .system)
        customButton.setImage(UIImage(named: "downArrow"), for: .normal)
        customButton.imageEdgeInsets = UIEdgeInsetsMake(0, 20, 0, -10)
        guard let customFont = UIFont(name: "NoirPro-SemiBold", size: 20) else {
            fatalError("""
        Failed to load the "CustomFont-Light" font.
        Make sure the font file is included in the project and the font name is spelled correctly.
        """
            )
        }
        customButton.semanticContentAttribute = UIApplication.shared
            .userInterfaceLayoutDirection == .rightToLeft ? .forceLeftToRight : .forceRightToLeft
        customButton.titleLabel?.font = customFont
        customButton.setTitleColor(UIColor.black, for: .normal)
        return customButton
    }()



    override init() {
        super.init()
        setupViews()
    }

    @objc func setupViews(){
        customView = customButton

    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

I correctly do the job of using both an image and title and setting the image insets for the button and on load the appearance is great. However, when I leave the screen and come back it seems as though everything is thrown out of wack the image gets moved back and sometimes there will be two images and one will have a distorted size.

Is there anything wrong with my custom button implementation that I am missing.

I have included images for before and afterenter image description here

enter image description here

enter image description here

Upvotes: 0

Views: 75

Answers (1)

Alex Kolovatov
Alex Kolovatov

Reputation: 879

I suggest you to make your custom button class, then make title and image by adding subviews. In this case UIImageView and UILabel. Because UIButton inherits from UIView you can easy do this. I've never had problems using this way.

Here is the code I've written for you:

import UIKit

class ViewController: UIViewController {

lazy var customButton: CustomButton = {
    let button = CustomButton(frame: CGRect(x: 50,
                                            y: 200,
                                            width: view.frame.width - 100,
                                            height: 50))
    // This mask for rotation
    button.autoresizingMask = [.flexibleLeftMargin,
                             .flexibleRightMargin,
                             .flexibleTopMargin,
                             .flexibleBottomMargin]
    button.attrTitleLabel.text = "San Francisco, CA"
    button.addTarget(self, action: #selector(chooseCity), for: .touchUpInside)
    return button
}()

override func viewDidLoad() {
    super.viewDidLoad()

    view.backgroundColor = .blue
    view.addSubview(customButton)
}

@objc func chooseCity() {
    print("Choose city button has pressed")
}

}

class CustomButton: UIButton {

private let arrowImageSize: CGSize = CGSize(width: 20, height: 20)
private let sideOffset: CGFloat = 10

override init(frame: CGRect) {
    super.init(frame: frame)

    backgroundColor = .white

    addSubview(attrTitleLabel)
    addSubview(arrowImageView)
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

lazy var attrTitleLabel: UILabel = {
    let label = UILabel()
    label.font = UIFont(name: "NoirPro-SemiBold", size: 20)
    label.textColor = .black
    return label
}()

lazy var arrowImageView: UIImageView = {
    let iv = UIImageView()
    iv.image = UIImage(named: "arrow_down")
    iv.contentMode = .scaleAspectFit
    return iv
}()

override func layoutSubviews() {
    super.layoutSubviews()

    arrowImageView.frame = CGRect(x: self.frame.width - arrowImageSize.width - sideOffset,
                                  y: self.frame.height/2 - arrowImageSize.height/2,
                                  width: arrowImageSize.width,
                                  height: arrowImageSize.height)

    attrTitleLabel.frame = CGRect(x: sideOffset, y: 0, width: self.frame.width - sideOffset*2 - arrowImageSize.width, height: self.frame.height)
}

}

How it looks:

enter image description here

Upvotes: 0

Related Questions