在我的 iOS 项目中,我正在使用包含多个子视图的 UIStackView。我想根据条件动态翻转或上下移动堆栈视图中的特定视图。具体来说,
我正在尝试操纵名为“FIRST”和“SECOND”的两个文本字段的位置。但是,我遇到了一个问题,即翻转仅在每秒点击或单击时才能正确工作。
这是我的代码
import UIKit
import Combine
import SnapKit
class ViewController: UIViewController {
private var toggleSubject = PassthroughSubject<Bool, Never>()
private var toggle = false
private var store = Set<AnyCancellable>()
private lazy var topField: AppTextField = {
let view = AppTextField(title: "First")
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private lazy var bottomField: AppTextField = {
let view = AppTextField(title: "Second")
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private lazy var lineView: UIImageView = {
let view = UIImageView(frame: .zero)
view.backgroundColor = .red
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private lazy var stackView: UIStackView = {
let view = UIStackView(arrangedSubviews: [topField, lineView, bottomField, toggleButton])
view.axis = .vertical
view.spacing = 4.0
view.distribution = .fill
view.alignment = .fill
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private lazy var toggleButton: UIButton = {
let view = UIButton(frame: .zero)
view.setTitle("Toggle", for: .normal)
view.setTitleColor(.white, for: .normal)
view.setTitleColor(.systemYellow, for: .highlighted)
view.backgroundColor = .darkGray
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private lazy var selectedTopFieldLabel: UILabel = {
let view = UILabel(frame: .zero)
view.textAlignment = .center
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(stackView)
self.view.addSubview(selectedTopFieldLabel)
toggleSubject.send(toggle)
stackView.snp.makeConstraints { make in
make.leading.trailing.centerY.equalToSuperview().inset(16)
}
lineView.snp.makeConstraints { make in
make.height.equalTo(0.5)
}
selectedTopFieldLabel.snp.makeConstraints { make in
make.top.equalToSuperview().offset(200)
}
toggleButton.addTarget(self, action: #selector(toggleButtonAction), for: .touchUpInside)
toggleSubject.sink { toggle in
print("---> Changed Toggle",toggle)
self.updateUI(toggle: toggle)
UIView.animate(withDuration: 0.25) {
self.stackView.layoutIfNeeded()
}
}.store(in: &store)
self.updateUI(toggle: toggle)
}
@objc func toggleButtonAction() {
toggle.toggle()
toggleSubject.send(toggle)
}
private func updateUI(toggle: Bool) {
let arrangedSubviews = self.stackView.arrangedSubviews
guard var first = arrangedSubviews[0] as? AppTextField,
var second = arrangedSubviews[2] as? AppTextField else {return}
stackView.arrangedSubviews.forEach({$0.removeFromSuperview()})
let changedViews = toggle ? [first, lineView, second, toggleButton] : [second, lineView, first , toggleButton]
guard let firstTextField = changedViews.first as? AppTextField,
let firstfieldPlaceholder = firstTextField.placeholder else {return}
self.selectedTopFieldLabel.text = "Selected On Top " + " -> " + firstfieldPlaceholder
changedViews.forEach { view in
self.stackView.addArrangedSubview(view)
}
// Update constraints
UIView.animate(withDuration: 0.25) {
self.stackView.setNeedsLayout()
self.stackView.layoutIfNeeded()
}
}
}
class AppTextField: UIView {
private lazy var inputField: UITextField = {
let textField = UITextField(frame: .zero)
textField.backgroundColor = .lightGray.withAlphaComponent(0.15)
textField.translatesAutoresizingMaskIntoConstraints = false
return textField
}()
var title: String? {
get { return inputField.placeholder }
set { inputField.placeholder = newValue }
}
var placeholder: String? {
get { return inputField.placeholder }
set { inputField.placeholder = newValue }
}
var text: String? {
get { return inputField.text }
set { inputField.text = newValue }
}
init(title: String) {
super.init(frame: .zero)
self.title = title
setupViews()
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupViews() {
addSubview(inputField)
inputField.snp.makeConstraints { make in
make.edges.equalToSuperview()
make.height.equalTo(48)
}
}
}
提前致谢。
我可以将上面的代码更改为
CurrentValueSubject<Bool, Never>(false)
来避免额外的 Bool
变量addArrangedSubview
无需删除子视图然后重新添加切换动作应该是:
private var toggleSubject = CurrentValueSubject<Bool, Never>(false)
@objc func toggleButtonAction() {
toggleSubject.value.toggle()
}
...
//Keep toggleSubject sink as it was
toggleSubject
.sink { [weak self] toggle in
self?.updateUI(toggle: toggle)
}
.store(in: &store)
然后删除
updateUI
中的其他内容:
private func updateUI(toggle: Bool) {
if toggle {
self.stackView.addArrangedSubview(topField)
self.stackView.addArrangedSubview(lineView)
self.stackView.addArrangedSubview(bottomField)
self.stackView.addArrangedSubview(toggleButton)
} else {
self.stackView.addArrangedSubview(bottomField)
self.stackView.addArrangedSubview(lineView)
self.stackView.addArrangedSubview(topField)
self.stackView.addArrangedSubview(toggleButton)
}
UIView.animate(withDuration: 0.25) {
self.stackView.setNeedsLayout()
self.stackView.layoutIfNeeded()
}
}