UIStackView 中的 .equalSpacing 无法与 CustomView 一起正常工作
.equalSpacing in UIStackView not working properly with CustomView
我创建了一个复选框/单选按钮的自定义视图,在选中和取消选中时会显示动画。问题是当我将自定义视图嵌入到 .equalSpacing 的 stackView 时,按钮无法再被点击,我猜是 borderView(具有点击手势)缩小得太小,所以它不能被点击。
奇怪的是borderView真的缩小了还是能看到
如果是 .fillEqually 和 .fillProportionally 它可以正常工作。
我正在使用 SnapKit 来安排约束。
让我知道我是否应该在此处粘贴整个代码。
自定义视图
public final class CustomView: UIView {
// MARK: - Properties
private let borderedView: UIView = {
let view = UIView()
view.layer.borderWidth = 1
return view
}()
private var errorStackView: UIStackView = {
let sv = UIStackView()
sv.isHidden = true
return sv
}()
private var borderStackView: UIStackView = {
let sv = UIStackView()
return sv
}()
private var parentStackView: UIStackView = {
let sv = UIStackView()
return sv
}()
.
.
.
.
.
// MARK: - Lifecycle
public override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupUI()
}
public init(button: ButtonType) {
super.init(frame: CGRect.zero)
setupUI()
}
public override func draw(_ rect: CGRect) {
setNeedsDisplay()
}
.
.
.
.
.
.
private func setupUI() {
backgroundColor = .clear
borderedView.addSubview(disabledImageView)
borderedView.snp.makeConstraints { make in
make.width.height.equalTo(borderSize)
}
borderStackView = UIStackView(arrangedSubviews: [borderedView, label])
borderStackView.spacing = 12
borderStackView.distribution = .fillProportionally
borderStackView.snp.makeConstraints { make in
make.height.width.equalTo(borderSize)
}
errorStackView = UIStackView(arrangedSubviews: [errorIconImageView, inlineErrorLabel])
errorStackView.spacing = 7
errorStackView.distribution = .fillProportionally
parentStackView = UIStackView(arrangedSubviews: [borderStackView, errorStackView])
parentStackView.axis = .vertical
parentStackView.distribution = .fillProportionally
addSubview(parentStackView)
parentStackView.snp.makeConstraints { make in
make.centerY.equalTo(self.snp.centerY)
make.width.equalToSuperview()
}
disabledImageView.snp.makeConstraints { make in
make
.leading
.trailing
.top
.bottom
.height
.width
.equalToSuperview()
}
parentStackView.sizeToFit()
layoutIfNeeded()
}
.
.
.
.
.
.
// MARK: - Action
public func addAction(action: @escaping ((Bool?) -> Void)) {
borderedView.addGestureRecognizerOnView(target: self, #selector(handleTapGesture(sender:)))
status = action
}
}
视图控制器
class ViewController: UIViewController {
// MARK: - Properties
private lazy var checkboxDefault: CustomView = {
let checkbox = CustomView()
checkbox.addAction { [weak self] checkboxStatus in
self?.handleUnchecked()
}
return checkbox
}()
private lazy var checkboxEnabledAndChecked: CustomView = {
let checkbox = CustomView()
checkbox.addAction { [weak self] checkboxStatus in
self?.handleChecked()
}
return checkbox
}()
private lazy var checkboxDisableAndUnchecked: CustomView = {
let checkbox = CustomView()
checkbox.addAction { [weak self] checkboxStatus in
self?.handleDisabledAndUnchecked()
}
return checkbox
}()
private lazy var checkboxDisableAndChecked: CustomView = {
let checkbox = CustomView()
checkbox.addAction { [weak self] checkboxStatus in
self?.handleDisabledAndChecked()
}
return checkbox
}()
private lazy var checkboxError: CustomView = {
let checkbox = CustomView()
checkbox.addAction { [weak self] checkboxStatus in
self?.handleError()
}
return checkbox
}()
private lazy var checkboxMultilineError: CustomView = {
let checkbox = CustomView()
checkbox.addAction { [weak self] checkboxStatus in
self?.handleMultiError()
}
return checkbox
}()
.
.
.
.
.
.
override func viewDidLoad() {
let stackview = UIStackView(
arrangedSubviews: [
checkboxDefault,
checkboxEnabledAndChecked,
checkboxDisableAndUnchecked,
checkboxDisableAndChecked,
checkboxError,
checkboxMultilineError
])
stackview.distribution = .equalSpacing
stackview.axis = .vertical
view.addSubview(stackview)
stackview.snp.makeConstraints { make in
make.center.equalTo(view.snp.center)
make.width.equalTo(300)
make.height.equalTo(300)
}
}
我通过在自定义视图中添加 intrinsicContentSize 设法解决了这个问题
并在每次应更新视图时添加 invalidateIntrinsicContentSize()。在我的例子中,它在 handleTapGesture
// MARK: - Lifecycle
public override var intrinsicContentSize: CGSize {
return CGSize(width: 300, height: 50)
}
.
.
.
.
.
// MARK: - Action
@objc private func handleTapGesture(sender: UITapGestureRecognizer) {
invalidateIntrinsicContentSize() // Call this when custom view needs to be updated
}
我创建了一个复选框/单选按钮的自定义视图,在选中和取消选中时会显示动画。问题是当我将自定义视图嵌入到 .equalSpacing 的 stackView 时,按钮无法再被点击,我猜是 borderView(具有点击手势)缩小得太小,所以它不能被点击。
奇怪的是borderView真的缩小了还是能看到
如果是 .fillEqually 和 .fillProportionally 它可以正常工作。
我正在使用 SnapKit 来安排约束。
让我知道我是否应该在此处粘贴整个代码。
自定义视图
public final class CustomView: UIView {
// MARK: - Properties
private let borderedView: UIView = {
let view = UIView()
view.layer.borderWidth = 1
return view
}()
private var errorStackView: UIStackView = {
let sv = UIStackView()
sv.isHidden = true
return sv
}()
private var borderStackView: UIStackView = {
let sv = UIStackView()
return sv
}()
private var parentStackView: UIStackView = {
let sv = UIStackView()
return sv
}()
.
.
.
.
.
// MARK: - Lifecycle
public override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupUI()
}
public init(button: ButtonType) {
super.init(frame: CGRect.zero)
setupUI()
}
public override func draw(_ rect: CGRect) {
setNeedsDisplay()
}
.
.
.
.
.
.
private func setupUI() {
backgroundColor = .clear
borderedView.addSubview(disabledImageView)
borderedView.snp.makeConstraints { make in
make.width.height.equalTo(borderSize)
}
borderStackView = UIStackView(arrangedSubviews: [borderedView, label])
borderStackView.spacing = 12
borderStackView.distribution = .fillProportionally
borderStackView.snp.makeConstraints { make in
make.height.width.equalTo(borderSize)
}
errorStackView = UIStackView(arrangedSubviews: [errorIconImageView, inlineErrorLabel])
errorStackView.spacing = 7
errorStackView.distribution = .fillProportionally
parentStackView = UIStackView(arrangedSubviews: [borderStackView, errorStackView])
parentStackView.axis = .vertical
parentStackView.distribution = .fillProportionally
addSubview(parentStackView)
parentStackView.snp.makeConstraints { make in
make.centerY.equalTo(self.snp.centerY)
make.width.equalToSuperview()
}
disabledImageView.snp.makeConstraints { make in
make
.leading
.trailing
.top
.bottom
.height
.width
.equalToSuperview()
}
parentStackView.sizeToFit()
layoutIfNeeded()
}
.
.
.
.
.
.
// MARK: - Action
public func addAction(action: @escaping ((Bool?) -> Void)) {
borderedView.addGestureRecognizerOnView(target: self, #selector(handleTapGesture(sender:)))
status = action
}
}
视图控制器
class ViewController: UIViewController {
// MARK: - Properties
private lazy var checkboxDefault: CustomView = {
let checkbox = CustomView()
checkbox.addAction { [weak self] checkboxStatus in
self?.handleUnchecked()
}
return checkbox
}()
private lazy var checkboxEnabledAndChecked: CustomView = {
let checkbox = CustomView()
checkbox.addAction { [weak self] checkboxStatus in
self?.handleChecked()
}
return checkbox
}()
private lazy var checkboxDisableAndUnchecked: CustomView = {
let checkbox = CustomView()
checkbox.addAction { [weak self] checkboxStatus in
self?.handleDisabledAndUnchecked()
}
return checkbox
}()
private lazy var checkboxDisableAndChecked: CustomView = {
let checkbox = CustomView()
checkbox.addAction { [weak self] checkboxStatus in
self?.handleDisabledAndChecked()
}
return checkbox
}()
private lazy var checkboxError: CustomView = {
let checkbox = CustomView()
checkbox.addAction { [weak self] checkboxStatus in
self?.handleError()
}
return checkbox
}()
private lazy var checkboxMultilineError: CustomView = {
let checkbox = CustomView()
checkbox.addAction { [weak self] checkboxStatus in
self?.handleMultiError()
}
return checkbox
}()
.
.
.
.
.
.
override func viewDidLoad() {
let stackview = UIStackView(
arrangedSubviews: [
checkboxDefault,
checkboxEnabledAndChecked,
checkboxDisableAndUnchecked,
checkboxDisableAndChecked,
checkboxError,
checkboxMultilineError
])
stackview.distribution = .equalSpacing
stackview.axis = .vertical
view.addSubview(stackview)
stackview.snp.makeConstraints { make in
make.center.equalTo(view.snp.center)
make.width.equalTo(300)
make.height.equalTo(300)
}
}
我通过在自定义视图中添加 intrinsicContentSize 设法解决了这个问题
并在每次应更新视图时添加 invalidateIntrinsicContentSize()。在我的例子中,它在 handleTapGesture
// MARK: - Lifecycle
public override var intrinsicContentSize: CGSize {
return CGSize(width: 300, height: 50)
}
.
.
.
.
.
// MARK: - Action
@objc private func handleTapGesture(sender: UITapGestureRecognizer) {
invalidateIntrinsicContentSize() // Call this when custom view needs to be updated
}