我在 iPhone X 的横屏模式下移动子视图控制器时遇到了安全区域的困难。
我的根视图控制器中有一个可移动的视图,其中包含一个嵌入的子视图控制器。实际应用程序是一个侧边栏菜单滑动界面。这里的示例代码是一个简化版本。
如果表格位于屏幕左侧,则安全区域布局规则会将其单元格内容视图缩进到右侧,以适应刘海区域。正确的。但是,如果我将子视图控制器从屏幕左侧移开,子控件的插页不会更新以重新布局内容。
我意识到,实际上,只要子视图控制器在其最终位置上完全显示,就一切正常运行。如果任何部分超出屏幕,则安全区域不会更新。
以下是演示问题的示例代码。这可以使用标准的 Single View App Xcode 模板项目:用所示代码替换 ViewController 文件代码。运行时,向右滑动表格将其从屏幕左侧移动到屏幕右侧。
请查看“constraint(...,multiplier:0.5)”行。这将可移动视图的宽度设置为相对于屏幕。在0.5时,表格完全适合屏幕,安全区域会随着其移动而更新。停靠在左侧时,表格单元格会遵守安全区域插页,而停靠在右侧时,表格单元格没有额外的插页是正确的。
一旦乘数超过0.5,即使在0.51时,向右滑动表格的一部分也会超出屏幕范围。在这种情况下,不会发生安全区域更新,因此表格单元格内容插页太大-即使表格左侧现在与安全区域无关。
更让人费解的是,如果它们不是 UIViewController 的视图,则布局在 UIView 上似乎可以正常工作。但我需要它能够与 UIViewControllers 一起使用。
有谁能解释如何使子视图控制器尊重正确的安全区域吗? 谢谢。
可复制代码:
class ViewController: UIViewController {
var leftEdgeConstraint : NSLayoutConstraint!
var viewThatMoves : UIView!
var myEmbeddedVC : UIViewController!
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.gray
self.viewThatMoves = UIView()
self.viewThatMoves.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(self.viewThatMoves)
// Relayout during animation work with multiplier = 0.5
// With any greater value, like 0.51 (meaning part of the view is offscreen), relayout does not happen
self.viewThatMoves.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 0.5).isActive = true
self.viewThatMoves.heightAnchor.constraint(equalTo: self.view.heightAnchor).isActive = true
self.viewThatMoves.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
self.leftEdgeConstraint = self.viewThatMoves.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 0)
self.leftEdgeConstraint.isActive = true
// Embed child ViewController
self.myEmbeddedVC = MyTableViewController()
self.addChildViewController(self.myEmbeddedVC)
self.myEmbeddedVC.view.translatesAutoresizingMaskIntoConstraints = false
self.viewThatMoves.addSubview(self.myEmbeddedVC.view)
self.myEmbeddedVC.didMove(toParentViewController: self)
// Fill containing view
self.myEmbeddedVC.view.leftAnchor.constraint(equalTo: self.viewThatMoves.leftAnchor).isActive = true
self.myEmbeddedVC.view.rightAnchor.constraint(equalTo: self.viewThatMoves.rightAnchor).isActive = true
self.myEmbeddedVC.view.topAnchor.constraint(equalTo: self.viewThatMoves.topAnchor).isActive = true
self.myEmbeddedVC.view.bottomAnchor.constraint(equalTo: self.viewThatMoves.bottomAnchor).isActive = true
let swipeLeftRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe(recognizer:)))
swipeLeftRecognizer.direction = .left
let swipeRightRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe(recognizer:)))
swipeRightRecognizer.direction = .right
self.viewThatMoves.addGestureRecognizer(swipeLeftRecognizer)
self.viewThatMoves.addGestureRecognizer(swipeRightRecognizer)
}
@objc func handleSwipe(recognizer:UISwipeGestureRecognizer) {
UIView.animate(withDuration: 1) {
if recognizer.direction == .left {
self.leftEdgeConstraint.constant = 0
}
else if recognizer.direction == .right {
self.leftEdgeConstraint.constant = self.viewThatMoves.frame.size.width
}
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
// Tried this: has no effect
// self.myEmbeddedVC.viewSafeAreaInsetsDidChange()
}
}
}
class MyTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.blue
self.title = "Test Table"
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Left", style: .plain, target: nil, action: nil)
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Right", style: .plain, target: nil, action: nil)
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 25
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
cell.contentView.backgroundColor = UIColor.green
cell.backgroundColor = UIColor.yellow
cell.textLabel?.text = "This is row \(indexPath.row)"
cell.textLabel?.backgroundColor = UIColor.clear
return cell
}
}