如何在Uikit中使用堆栈视图创建可重复使用的按钮类?
我正在使用类来构建可重复使用的按钮(下图),该按钮使用堆栈视图垂直定位两个标签,并允许我在调用时配置两个标签的文本。
我尝试在下面的初始方法中将“标签”和“ sublabel”添加到uistackView中,但是堆栈并未添加到按钮的视图中。
将堆栈视图集成到此自定义按钮类中的最佳方法是什么?
struct ActivityButtonVM {
let labelText: String
let subLabelText: String
let action: Selector
}
final class ActivityButton: UIButton {
private let label: UILabel = {
let label = UILabel()
label.textAlignment = .center
label.textColor = .black
return label
}()
private let subLabel: UILabel = {
let label = UILabel()
label.textAlignment = .center
label.textColor = .gray
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
setBackgroundImage(Image.setButtonBg, for: .normal)
let stack = UIStackView(arrangedSubviews: [label, subLabel])
stack.axis = .vertical
stack.alignment = .center
addSubview(stack)
clipsToBounds = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configure(with viewModel: ActivityButtonVM) {
label.text = viewModel.labelText
subLabel.text = viewModel.subLabelText
self.addTarget(SetActivityVC(), action: viewModel.action,
for: .touchUpInside)
}
}
这就是我使用此自定义按钮类的方式:
class SetActivityVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
}
lazy var firstButton: UIButton = {
let button = ActivityButton()
button.configure(with: ActivityButtonVM(labelText: "No Exercise", subLabelText: "no exercise or very infrequent", action: #selector(didTapFirst))
return button
}()
lazy var secondButton: UIButton = {
let button = ActivityButton()
button.configure(with: ActivityButtonVM(labelText: "Light Exercise", subLabelText: "some light cardio/weights a few times per week", action: #selector(didTapSecond))
return button
}()
@objc func didTapFirst() {
print("Tapped 1")
}
@objc func didTapSecond() {
print("Tapped 2")
}
}
extension SetActivityVC {
fileprivate func setupViews() {
addViews()
constrainViews()
}
fileprivate func addViews() {
view.addSubview(firstButton)
view.addSubview(secondButton)
}
fileprivate func constrainViews() {
firstButton.centerXToSuperview()
secondButton.centerXToSuperview()
secondButton.topToBottom(of: firstButton, offset: screenHeight * 0.03)
}
}
I'm using a class to build a reusable button (image below) that uses a stack view to position two labels vertically, and allows me to configure both labels' text when called.
I tried to add "label" and "subLabel" into a UIStackView in the init method below, but the stack isn't being added onto the button's view.
What would be the best way to integrate a stack view into this custom button class?
struct ActivityButtonVM {
let labelText: String
let subLabelText: String
let action: Selector
}
final class ActivityButton: UIButton {
private let label: UILabel = {
let label = UILabel()
label.textAlignment = .center
label.textColor = .black
return label
}()
private let subLabel: UILabel = {
let label = UILabel()
label.textAlignment = .center
label.textColor = .gray
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
setBackgroundImage(Image.setButtonBg, for: .normal)
let stack = UIStackView(arrangedSubviews: [label, subLabel])
stack.axis = .vertical
stack.alignment = .center
addSubview(stack)
clipsToBounds = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configure(with viewModel: ActivityButtonVM) {
label.text = viewModel.labelText
subLabel.text = viewModel.subLabelText
self.addTarget(SetActivityVC(), action: viewModel.action,
for: .touchUpInside)
}
}
This is how I'm using this custom button class:
class SetActivityVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
}
lazy var firstButton: UIButton = {
let button = ActivityButton()
button.configure(with: ActivityButtonVM(labelText: "No Exercise", subLabelText: "no exercise or very infrequent", action: #selector(didTapFirst))
return button
}()
lazy var secondButton: UIButton = {
let button = ActivityButton()
button.configure(with: ActivityButtonVM(labelText: "Light Exercise", subLabelText: "some light cardio/weights a few times per week", action: #selector(didTapSecond))
return button
}()
@objc func didTapFirst() {
print("Tapped 1")
}
@objc func didTapSecond() {
print("Tapped 2")
}
}
extension SetActivityVC {
fileprivate func setupViews() {
addViews()
constrainViews()
}
fileprivate func addViews() {
view.addSubview(firstButton)
view.addSubview(secondButton)
}
fileprivate func constrainViews() {
firstButton.centerXToSuperview()
secondButton.centerXToSuperview()
secondButton.topToBottom(of: firstButton, offset: screenHeight * 0.03)
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先,您没有调用您的
init(frame:)
在初始化按钮时:您只是调用您从
nsobject
>>额外。您可以自己添加一个无参数便利性初始评估器,该初始评估器调用
self.init(frame:)
:然后将添加堆栈视图。
我认为您还需要添加:
停止自动化蒙版约束,从而导致堆栈视图具有
.zero
框架。此外,您应该在堆栈视图中添加约束,以使其相对于按钮正确定位。 (可能将4个侧面固定在按钮的4个侧面?)
最后但并非最不重要的一点是,添加目标的方式是不正确的。您将
setActivityvc
的新实例作为此处的目标,而不是具有按钮的VC的实例。相反,如果您想使用目标行动对执行此操作,则应在视图模型中包含
target
:提示:而不是使用诸如
.black
之类的颜色。和.gray
,使用.label
和.secondarylabel
,以便在黑暗模式下看起来也不错。First, you are not calling your
init(frame:)
when initialising your buttons:You are just calling the initialiser you inherited from
NSObject
, so of course the stack views are not added.You can add a parameterless convenience initialiser yourself, that calls
self.init(frame:)
:and then the stack views will be added.
I think you would also need to add:
to stop the autoresizing mask constraints from causing the stack view to have a
.zero
frame.Additionally, you should add constraints to the stack view so that it is positioned correctly with respect to the button. (probably pin the 4 sides to the button's 4 sides?)
Last but not least, the way that you are adding the target is incorrect. You are adding a new instance of
SetActivityVC
as the target here, rather than the instance of the VC that has the button.Instead, if you want to do this with target-action pairs, you should include the
target
in the view model as well:Tip: rather than using colours such as
.black
and.gray
, use.label
and.secondaryLabel
so that it also looks good in dark mode.您可以使用替代方式:新的uibutton.configuration,声明您的按钮:
现在添加此扩展名以进行按钮配置:
如何使用,在viewDidload中设置按钮和相对目标:
设置stackView和“约束”和“约束”:
添加按钮功能:
这就是结果:结果:
You can use alternative way: new UIButton.configuration, declare your buttons:
now add this extension for button configuration:
how to use, in viewDidLoad set your buttons and relative targets:
set your stackView and constraints:
add buttons functions:
This is the result: