Skip to content

Instantly share code, notes, and snippets.

@rolandleth
Last active September 15, 2022 18:43
Show Gist options
  • Save rolandleth/f1264fa7032570526ed01d0ab63988d6 to your computer and use it in GitHub Desktop.
Save rolandleth/f1264fa7032570526ed01d0ab63988d6 to your computer and use it in GitHub Desktop.
SwiftUI influences in UIKit
import UIKit
class VStack: UIStackView {
init(alignment: UIStackView.Alignment = .fill, spacing: CGFloat = 10, _ arrangedViews: UIView...) {
super.init(frame: .zero)
axis = .vertical
self.alignment = alignment
self.spacing = spacing
distribution = .fill
arrangedViews.forEach(addArrangedSubview)
}
required init(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class HStack: UIStackView {
init(alignment: UIStackView.Alignment = .fill, spacing: CGFloat = 10, _ arrangedViews: UIView...) {
super.init(frame: .zero)
axis = .horizontal
self.alignment = alignment
self.spacing = spacing
distribution = .fill
arrangedViews.forEach(addArrangedSubview)
}
required init(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
final class Spacer: UIView {
init() {
super.init(frame: .zero)
autoresizingMask = [.flexibleWidth, .flexibleHeight]
// These might not be needed, but in case spacers don't work as expected, give them a try.
// The idea is that a `Spacer` has the lowest priority in hugging, since it doesn't care if it doesn't hug its content (it has none).
// A `Spacer` also should stop being compressed when other views would stop hugging.
// setContentHuggingPriority(.init(rawValue: 1), for: .vertical)
// setContentHuggingPriority(.init(rawValue: 1), for: .horizontal)
//
// setContentCompressionResistancePriority(.init(rawValue: UILayoutPriority.defaultLow.rawValue - 1), for: .vertical)
// setContentCompressionResistancePriority(.init(rawValue: UILayoutPriority.defaultLow.rawValue - 1), for: .horizontal)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
final class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .secondarySystemFill
let image = UIImageView(image: UIImage(named: "pic"))
image.contentMode = .scaleAspectFill
image.clipsToBounds = true
image.translatesAutoresizingMaskIntoConstraints = false
let nameLabel = UILabel()
nameLabel.font = UIFont.preferredFont(forTextStyle: .title1)
nameLabel.text = "Yosemite"
let infoLabel = UILabel()
infoLabel.font = UIFont.italicSystemFont(
ofSize: UIFont.preferredFont(forTextStyle: .caption1).pointSize)
infoLabel.text = "First climbed in: 1907"
let detailsStack = VStack(
spacing: 4,
detailsRow(labelText: "Difficulty:", valueText: "Hard"),
detailsRow(labelText: "Annual attempts:", valueText: "1452"),
detailsRow(labelText: "Monthly successful attempts:", valueText: "12")
)
detailsStack.translatesAutoresizingMaskIntoConstraints = false
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .blue
let content = VStack(
spacing: 16,
image,
HStack(
alignment: .lastBaseline,
nameLabel,
Spacer(),
infoLabel
),
HStack(
detailsStack,
VStack(
Spacer(),
HStack(
v,
Spacer()
)
)
),
HStack(
viewRow(number: 97, icon: "paperplane", text1: "Bird", text2: "species"),
Spacer(),
viewRow(number: 20, icon: "eyes", text1: "Breathtaking", text2: "views"),
Spacer(),
viewRow(number: 12, icon: "arrow.up", text1: "Oak", text2: "species")
),
Spacer()
)
content.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(content)
NSLayoutConstraint.activate([
content.topAnchor.constraint(equalTo: view.topAnchor),
content.bottomAnchor.constraint(equalTo: view.bottomAnchor),
content.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
content.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
image.heightAnchor.constraint(equalToConstant: 100),
detailsStack.widthAnchor.constraint(equalToConstant: 250),
v.heightAnchor.constraint(equalToConstant: 20),
v.widthAnchor.constraint(equalToConstant: 100),
])
}
private func detailsRow(labelText: String, valueText: String) -> UIView {
let label = UILabel()
label.font = UIFont.preferredFont(forTextStyle: .caption1)
label.text = labelText
let value = UILabel()
value.font = label.font
value.text = valueText
return HStack(
label,
Spacer(),
value
)
}
private func viewRow(number: Int, icon: String, text1: String, text2: String) -> UIView {
let numberLabel = UILabel()
numberLabel.font = UIFont.boldSystemFont(ofSize: UIFont.preferredFont(forTextStyle: .title1).pointSize)
numberLabel.text = "\(number)"
let text1Label = UILabel()
text1Label.font = UIFont.preferredFont(forTextStyle: .caption1)
text1Label.text = text1
let text2Label = UILabel()
text2Label.font = text1Label.font
text2Label.text = text2
let image = UIImage(systemName: icon,
withConfiguration: UIImage.SymbolConfiguration(font: text1Label.font))?
.withRenderingMode(.alwaysOriginal)
let imageView = UIImageView(image: image)
imageView.contentMode = .scaleAspectFit
return HStack(
alignment: .lastBaseline,
numberLabel,
VStack(
spacing: 0,
HStack(
spacing: 2,
imageView,
text1Label,
Spacer()
),
text2Label
)
)
}
}
@rolandleth
Copy link
Author

This is the example's output:

Screenshot 2020-08-18 at 20 50 51

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment