效果图如下:
分析所需的ui元素
元素 | 样式 | 控件 |
---|---|---|
弹窗标题 | 黑色加粗 | UILabel |
弹窗内容 | 灰色正常 | UILabel |
关闭按钮 | 红底白字圆角 | UIButton |
弹窗白底 | 白底圆角 | UIView |
弹窗半透明背景 | 黑色半透明 | UIController>UIView |
弹窗标题ui实现
class MyTitleLabel: UILabel {
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
init(textAlignment: NSTextAlignment, fontSize: CGFloat) {
super.init(frame: .zero)
self.textAlignment = textAlignment
self.font = UIFont.systemFont(ofSize: fontSize, weight: .bold)
configure()
}
private func configure() {
textColor = .label
adjustsFontSizeToFitWidth = true
minimumScaleFactor = 0.9
lineBreakMode = .byTruncatingTail
translatesAutoresizingMaskIntoConstraints = false
}
}
弹窗内容ui实现
class MyBodyLabel: UILabel {
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
init(textAlignment: NSTextAlignment) {
super.init(frame: .zero)
self.textAlignment = textAlignment
configure()
}
private func configure() {
textColor = .secondaryLabel
font = UIFont.preferredFont(forTextStyle: .body)
adjustsFontSizeToFitWidth = true
minimumScaleFactor = 0.75
lineBreakMode = .byWordWrapping
translatesAutoresizingMaskIntoConstraints = false
}
}
关闭按钮ui实现
class MyButton: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
init(backgroundColor: UIColor, title: String) {
super.init(frame: .zero)
self.backgroundColor = backgroundColor
self.setTitle(title, for: .normal)
configure()
}
private func configure() {
layer.cornerRadius = 10
setTitleColor(.white, for: .normal)
titleLabel?.font = UIFont.preferredFont(forTextStyle: .headline)
translatesAutoresizingMaskIntoConstraints = false
}
func set(backgroundColor: UIColor, title: String) {
self.backgroundColor = backgroundColor
setTitle(title, for: .normal)
}
}
半透明背景controller,内置一个圆角UIView盛放标题、内容、关闭按钮ui空间和用auto layout布局按钮位置
关闭按钮被点击后需要关闭这个controller
关闭当前controller:dismiss(animated: true)
class MyAlertVC: UIViewController {
let containerView = UIView()
let titleLabel = MyTitleLabel(textAlignment: .center, fontSize: 20)
let messageLabel = MyBodyLabel(textAlignment: .center)
let actionButton = MyButton(backgroundColor: .systemPink, title: "Ok")
var alertTitle: String?
var message: String?
var buttonTitle: String?
let padding: CGFloat = 20
init(title: String, message: String, buttonTitle: String) {
super.init(nibName: nil, bundle: nil)
self.alertTitle = title
self.message = message
self.buttonTitle = buttonTitle
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.75)
configureContainerView()
configureTitleLabel()
configureActionButton()
configureMessageLabel()
}
func configureContainerView() {
view.addSubview(containerView)
containerView.backgroundColor = .systemBackground
containerView.layer.cornerRadius = 16
containerView.layer.borderWidth = 2
containerView.layer.borderColor = UIColor.white.cgColor
containerView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
containerView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
containerView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
containerView.widthAnchor.constraint(equalToConstant: 280),
containerView.heightAnchor.constraint(equalToConstant: 220)
])
}
func configureTitleLabel() {
containerView.addSubview(titleLabel)
titleLabel.text = alertTitle ?? "Something went wrong"
NSLayoutConstraint.activate([
titleLabel.topAnchor.constraint(equalTo: containerView.topAnchor, constant: padding),
titleLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: padding),
titleLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -padding),
titleLabel.heightAnchor.constraint(equalToConstant: 28)
])
}
func configureActionButton() {
containerView.addSubview(actionButton)
actionButton.setTitle(buttonTitle ?? "Ok", for: .normal)
actionButton.addTarget(self, action: #selector(dismissVC), for: .touchUpInside)
NSLayoutConstraint.activate([
actionButton.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -padding),
actionButton.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: padding),
actionButton.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -padding),
actionButton.heightAnchor.constraint(equalToConstant: 44)
])
}
func configureMessageLabel() {
containerView.addSubview(messageLabel)
messageLabel.text = message ?? "Unable to complete request"
messageLabel.numberOfLines = 4
NSLayoutConstraint.activate([
messageLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 8),
messageLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: padding),
messageLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -padding),
messageLabel.bottomAnchor.constraint(equalTo: actionButton.topAnchor, constant: -12)
])
}
@objc func dismissVC() {
dismiss(animated: true)
}
}
创建controller实例使用这个弹窗
let alertVC = MyAlertVC(title: title, message: message, buttonTitle: buttonTitle)
alertVC.modalPresentationStyle = .overFullScreen
alertVC.modalTransitionStyle = .crossDissolve
self.present(alertVC, animated: true)
一些注意的点
- 在异步请求中使用这个弹窗需要DispatchQueue.main.async确保在主线程中