UINavigationController 与子视图控制器的奇怪行为
Posted
技术标签:
【中文标题】UINavigationController 与子视图控制器的奇怪行为【英文标题】:Strange behavior of UINavigationController with child view controller 【发布时间】:2018-07-15 16:16:45 【问题描述】:我需要导航控制器堆栈中所有控制器的可拖动视图。为了管理这个视图和手势识别器,我使用了名为 ChildViewController 的自定义 VC。在 navController 的 viewDidLoad 方法中,我添加了子控制器。在 ChildViewController 中,我在 didMoveToParent 方法中创建视图并设置约束。在手势识别器中使用约束的常数来计算平移时的视图位置。及其作品。但是每次当我在 navController 的堆栈中推送或弹出控制器时,navController 都会调用 ChildViewController 的 didMoveToParent 方法并设置约束。之后,手势识别器开始无法正常工作。我通过实现 isConstrainted 变量并在 didMoveToParent 中添加 if 语句来解决这个问题。现在,约束设置一劳永逸。但是,当我在viewDidLoad中添加一次子vc时,为什么navController在推送或弹出时调用子vc的didMoveToParent? GIF https://i.stack.imgur.com/MEeu6.gif gitHub 上的项目https://github.com/ayatsev/ChildNavController
class CustomNavController: UINavigationController
override func viewDidLoad()
super.viewDidLoad()
let childController = ChildViewController()
addChild(childController)
view.addSubview(childController.view)
childController.didMove(toParent: self)
class ChildViewController: UIViewController
var xConstraint: NSLayoutConstraint!
var yConstraint: NSLayoutConstraint!
var isConstrainted = false
lazy var childView: UIView =
let cv = UIView()
cv.translatesAutoresizingMaskIntoConstraints = false
let panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
cv.addGestureRecognizer(panRecognizer)
cv.backgroundColor = .green
return cv
()
override func viewDidLoad()
super.viewDidLoad()
view = childView
override func didMove(toParent parent: UIViewController?)
print("--- CHILD: Did Move To Parent")
guard let parent = parent else return
if !isConstrainted
childView.widthAnchor.constraint(equalToConstant: 50).isActive = true
childView.heightAnchor.constraint(equalToConstant: 50).isActive = true
xConstraint = childView.leadingAnchor.constraint(equalTo: parent.view.leadingAnchor, constant: 40)
xConstraint.isActive = true
yConstraint = childView.topAnchor.constraint(equalTo: parent.view.topAnchor, constant: parent.view.frame.height * 2 / 3)
yConstraint.isActive = true
isConstrainted = true
@objc func handlePan(recognizer: UIPanGestureRecognizer)
guard let parent = parent else return
let translation = recognizer.translation(in: parent.view)
switch recognizer.state
case .changed:
xConstraint.constant += translation.x
yConstraint.constant += translation.y
recognizer.setTranslation(CGPoint.zero, in: parent.view)
default:
break
【问题讨论】:
【参考方案1】:但是为什么navController在push或者pop的时候会调用child vc的didMoveToParent
没有必要问这个“为什么”。这就是系统的工作方式。有时didMove(toParent:)
到达时没有对应的willMove(toParent:)
。有时didMove(toParent:)
会到达,即使此视图控制器以前是此父级的子级并且仍然是此父级的子级。这似乎很疯狂,我知道。但是你不要去解释为什么,你的编码方式应该能够连贯地响应你收到的信息。
【讨论】:
我相信我的回答是错误的。我现在相信你得到didMove(toParent:)
的原因是因为你对didMove(toParent:)
的实现是错误的。它需要首先调用super
,即它应该是super.didMove(toParent:parent)
。以上是关于UINavigationController 与子视图控制器的奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章