Я немного новичок в Xcode и пытаюсь делать что-то программно. У меня есть View Controller A, B, C и D. У меня есть кнопка «Назад» на C и D. При переходе от D к C с использованием self.dismiss
все работает нормально, однако при переходе от C к BI происходит сбой похоже, это проблема с ограничениями, и я понятия не имею, почему.
Опять же, сбой происходит при переходе от C к B. Ошибка говорит об отсутствии общего предка для DropDownButton, но на ViewController B нет DropDownButton, он существует на C, который я пытаюсь отклонить.
Я хотел бы узнать больше о том, как работают контроллеры вида и Auto Layout, может кто-нибудь указать мне правильное направление, пожалуйста?
"oneonone.DropDownButton:0x7fcfe9d30660'??+1 ⌄'.bottom"> because they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies? That's illegal. userInfo: (null)
2018-11-09 19:56:22.828322-0600 oneonone[62728:4835265] *** Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to activate constraint with anchors <NSLayoutYAxisAnchor
ОБНОВЛЕНИЕ К ВОПРОСАМ:
Вот View Controller C, включен var, добавление его в subview, и как я отклоняю этот контроллер view
lazy var countryCodes: DropDownButton = {
let button = DropDownButton(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
let us = flag(country: "US")
let br = flag(country: "BR")
let lightGray = UIColor(red: 240/255, green: 240/255, blue: 240/255, alpha: 1)
button.backgroundColor = lightGray
button.setTitle(us + "+1 \u{2304}", for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 20)
button.setTitleColor(UIColor.darkGray, for: .normal)
button.uiView.dropDownOptions = [us + "+1", br + "+55", "+33", "+17", "+19"]
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
[countryCodes].forEach{ view.addSubview($0) }
setupLayout()
}
func setupLayout(){
countryCodes.translatesAutoresizingMaskIntoConstraints = false
countryCodes.topAnchor.constraint(equalTo: instructionLabel.bottomAnchor, constant: 30).isActive = true
countryCodes.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: -77.5).isActive = true
countryCodes.widthAnchor.constraint(equalToConstant: 85).isActive = true // guarantees this width for stack
countryCodes.heightAnchor.constraint(equalToConstant: 40).isActive = true
}
@objc func buttonPressed(){
self.dismiss(animated: true, completion: nil)
}
Вот код в контроллере вида B, который (создает или представляет?) Контроллер вида C
@objc func phoneAuthButtonPressed(){
let vc = phoneAuthViewController()
self.present(vc, animated: true, completion: nil)
}
ОБНОВЛЕНИЕ 2: ДОБАВЛЕНИЕ ТАМОЖЕННОГО КЛАССА
Вот код кнопки, который я использовал в качестве пользовательского класса после урока, я думаю, что проблема заключается в этом
protocol dropDownProtocol {
func dropDownPressed(string: String)
}
class DropDownButton: UIButton, dropDownProtocol {
var uiView = DropDownView()
var height = NSLayoutConstraint()
var isOpen = false
func dropDownPressed(string: String) {
self.setTitle(string + " \u{2304}", for: .normal)
self.titleLabel?.font = UIFont.systemFont(ofSize: 18)
self.dismissDropDown()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.gray
uiView = DropDownView.init(frame: CGRect.init(x: 0, y: 0, width: 0, height: 0))
uiView.delegate = self
uiView.layer.zPosition = 1 // show in front of other labels
uiView.translatesAutoresizingMaskIntoConstraints = false
}
override func didMoveToSuperview() {
self.superview?.addSubview(uiView)
self.superview?.bringSubviewToFront(uiView)
uiView.topAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
uiView.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
uiView.widthAnchor.constraint(equalTo: self.widthAnchor).isActive = true
height = uiView.heightAnchor.constraint(equalToConstant: 0)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { // animates drop down list
NSLayoutConstraint.deactivate([self.height])
if self.uiView.tableView.contentSize.height > 150 {
self.height.constant = 150
} else {
self.height.constant = self.uiView.tableView.contentSize.height
}
if isOpen == false {
isOpen = true
NSLayoutConstraint.activate([self.height])
UIView.animate(withDuration: 0.25, delay: 0, options: .curveEaseInOut, animations: {
self.uiView.layoutIfNeeded()
self.uiView.center.y += self.uiView.frame.height / 2
}, completion: nil)
} else {
dismissDropDown()
}
}
func dismissDropDown(){
isOpen = false
self.height.constant = 0
NSLayoutConstraint.activate([self.height])
UIView.animate(withDuration: 0.25, delay: 0, options: .curveEaseInOut, animations: {
self.uiView.center.y -= self.uiView.frame.height / 2
self.uiView.layoutIfNeeded()
}, completion: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class DropDownView: UIView, UITableViewDelegate, UITableViewDataSource {
var dropDownOptions = [String]()
var tableView = UITableView()
var delegate : dropDownProtocol!
let lightGray = UIColor(red: 240/255, green: 240/255, blue: 240/255, alpha: 1)
override init(frame: CGRect) {
super.init(frame: frame)
tableView.backgroundColor = lightGray
tableView.delegate = self
tableView.dataSource = self
tableView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(tableView) // can not come after constraints
tableView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
tableView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dropDownOptions.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = dropDownOptions[indexPath.row]
cell.textLabel?.font = UIFont.systemFont(ofSize: 14)
cell.textLabel?.textColor = UIColor.darkGray
cell.backgroundColor = lightGray
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.delegate.dropDownPressed(string: dropDownOptions[indexPath.row])
self.tableView.deselectRow(at: indexPath, animated: true)
}
}