Reputation: 1
I have a UIButton with both a title and an image. The button's size changes dynamically, but the title text and image inside the button do not resize proportionally to match the button's size. I want to make sure that both the title and the image adjust their sizes automatically based on the button's frame to maintain a balanced appearance.
Storyboard button configuration:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var myBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
}
}
Button on the simulator:
I set the title and image for the UIButton, hoping they would resize automatically when the button's frame changes. However, the title and image remained the same size, not scaling proportionally with the button. I expected both to adjust dynamically to fit the button's new size, but this didn’t happen.
Upvotes: -1
Views: 85
Reputation: 77423
UI components - including controls such as UIButton
- are rarely a "one size fits all" solution.
Buttons do not auto-adjust the font size.
Options are to:
UIButton
and add customization codeHere is a sample custom button control that you may find helpful:
@IBDesignable
class MyCustomButton: UIControl {
@IBInspectable
public var image: UIImage? {
didSet {
imageView.image = image
setNeedsLayout()
}
}
@IBInspectable
public var title: String = "Button" {
didSet {
titleLabel.text = title
setNeedsLayout()
}
}
private let imageView = UIImageView()
private let titleLabel = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
override func prepareForInterfaceBuilder() {
self.backgroundColor = .systemBlue
}
private func commonInit() {
backgroundColor = .systemBlue
layer.cornerRadius = 8
// Configure internal UI elements
imageView.tintColor = .white
imageView.contentMode = .scaleAspectFill
titleLabel.textColor = .white
titleLabel.textAlignment = .center
titleLabel.text = title
// let's put the imageView and titleLabel in a stack view
let stackView = UIStackView(arrangedSubviews: [imageView, titleLabel])
// adjust spacing as desired
stackView.spacing = 0.0
stackView.translatesAutoresizingMaskIntoConstraints = false
addSubview(stackView)
// Set up layout constraints
NSLayoutConstraint.activate([
stackView.centerXAnchor.constraint(equalTo: centerXAnchor),
stackView.centerYAnchor.constraint(equalTo: centerYAnchor),
// default imageView is ~75% of the button height
// based on your screen shots, you want it to be ~60%
// adjust as desired
imageView.heightAnchor.constraint(equalTo: self.heightAnchor, multiplier: 0.60),
// use 1:1 ratio for the image view
imageView.widthAnchor.constraint(equalTo: imageView.heightAnchor),
])
// make sure all subviews are not interactive
// so they don't consume touches
for v in [imageView, titleLabel, stackView] {
v.isUserInteractionEnabled = false
}
}
override func layoutSubviews() {
super.layoutSubviews()
// update font size based on button height
// we want 17-pt font relative to a button height of 45.0
let fSize: CGFloat = 17.0 * (bounds.height / 45.0)
titleLabel.font = .systemFont(ofSize: fSize, weight: .regular)
// hide image view if image is not set
imageView.isHidden = imageView.image == nil
}
// MARK: - Touch Handling
override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
// Highlight the button on touch down
alpha = 0.7
return true
}
override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
// Reset appearance on touch up
alpha = 1.0
}
override func cancelTracking(with event: UIEvent?) {
// Reset appearance if the touch is canceled
alpha = 1.0
}
}
First, we add a UIImageView
and a UILabel
in a horizontal UIStackView
.
Next, we constrain the size of the image view to 60% of the height of the control view (based on your screen-shots).
On layoutSubviews()
we calculate the font size for the label. Again, based on you screen-shots, it looks like you want 17-pt font size (the default font size for a button) when its height is 45, so we set the new font size to 17.0 * (bounds.height / 45.0)
.
We also define this class as @IBDesignable
with @IBInspectable
title and image so we can lay it out and configure it in Storyboard.
Add a UIView
and set its Custom Class:
Set the Image and Title properties:
and we get this at run-time:
This is an example to get you started. See the inline // comments
for ways you can customize it as desired.
Upvotes: 0