怪异的iOS11中的可视化行为。 单元格通过导航推animation面向上滚动

我最近将一些代码迁移到新的iOS 11 beta 5 SDK。

我现在从UITableView得到一个非常混乱的行为。 桌面本身并不是那种幻想。 我有自定义的单元格,但大部分只是为了他们的高度。

当我推我的视图控制器与tableview我得到一个额外的animation,单元格“向上滚动”(或可能整个tableview框架被改变),并沿着推/stream行导航animation下来。 请参阅gif:

波浪tableview

我手动在loadView方法中创buildtableview ,并设置自动布局约束等于tableview的superview的前导,尾随,顶部,底部。 超级视图是视图控制器的根视图。

视图控制器推送代码非常标准: self.navigationController?.pushViewController(notifVC, animated: true)

相同的代码提供了iOS 10上的正常行为。

你能指点我什么是错的方向?

编辑:我做了一个非常简单的tableview控制器,我可以在那里重现相同的行为。 码:

 class VerySimpleTableViewController : UITableViewController { override func viewDidLoad() { super.viewDidLoad() self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell") } override func numberOfSections(in tableView: UITableView) -> Int { return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 4 } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) cell.textLabel?.text = String(indexPath.row) cell.accessoryType = .disclosureIndicator return cell } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) let vc = VerySimpleTableViewController.init(style: .grouped) self.navigationController?.pushViewController(vc, animated: true) } } 

编辑2:我能够缩小问题,以我的UINavigationBar的自定义。 我有这样的定制:

rootNavController.navigationBar.setBackgroundImage(createFilledImage(withColor: .white, size: 1), for: .default)

createFilledImage创build具有给定大小和颜色的方形图像。

如果我注释掉这条线,我会恢复正常的行为。

对于这个问题,我将不胜感激。

这是由于UIScrollView's (UITableView是 UIScrollView's 一个子类)新的contentInsetAdjustmentBehavior属性,它默认设置为contentInsetAdjustmentBehavior

您可以在任何受影响的控制器的viewDidLoad中使用以下片段覆盖此行为:

  tableView.contentInsetAdjustmentBehavior = .never 

https://developer.apple.com/documentation/uikit/uiscrollview/2902261-contentinsetadjustmentbehavior

除了maggy的回答

Objective-C的

 if (@available(iOS 11.0, *)) { scrollViewForView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; } 

您可以在整个应用程序中通过在例如didFinishLaunchingWithOptions中使用NSProxy来一次性编辑此行为:

 if (@available(iOS 11.0, *)) { [UIScrollView appearance].contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; } 

另外,如果您使用标签栏,集合视图的底部内容插入将为零。 为此,把下面的代码放在viewDidAppear中:

 if #available(iOS 11, *) { tableView.contentInset = self.collectionView.safeAreaInsets } 

这看起来更像是一个比预期行为更糟的错误。 导航栏不透明或设置背景图像时发生。

如果您只是将contentInsetAdjustmentBehavior设置为“。”,则不会在iPhone X上正确设置内容插入,例如内容将进入滚动条下方的底部区域。

有必要做两件事情:
1.防止scrollViewanimation推/stream行
2.保留自动行为,因为它是iPhone X所需要的。没有这个例如纵向,内容将低于底部滚动条。

注意:如果在横向模式下使用UIScrollView,它仍然不会正确设置水平插入(另一个bug?),所以您必须将scrollView的前导/尾随挂接到IB中的safeAreaInsets。

注2:下面的解决scheme也有问题,如果tableView滚动到底部,并且你推控制器和popup,它不会在底部了。

 override func viewDidLoad() { super.viewDidLoad() // This parts gets rid of animation when pushing if #available(iOS 11, *) { self.tableView.contentInsetAdjustmentBehavior = .never } } override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) // This parts gets rid of animation when popping if #available(iOS 11, *) { self.tableView.contentInsetAdjustmentBehavior = .never } } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // This parts sets correct behaviour(insets are correct on iPhone X) if #available(iOS 11, *) { self.tableView.contentInsetAdjustmentBehavior = .automatic } } 

以下是我如何设法解决这个问题, 同时仍然允许iOS 11自动设置插入 。 我正在使用UITableViewController

  • 在视图控制器的故事板中(或以编程方式 )select“扩展顶部条下方的边”和“在不透明条之下延伸边”。 安全区域插入将阻止您的视图在顶部栏之下。
  • 检查故事板中桌面视图上的“插入到安全区域”button。 (或tableView.insetsContentViewsToSafeArea = true ) – 这可能不是必要的,但这是我做的。
  • 设置内容调整行为为“Scrollable Axes”(或tableView.contentInsetAdjustmentBehavior = .scrollableAxes.always也可以,但是我没有testing。

还有一件事要尝试,如果一切都失败了:

覆盖viewSafeAreaInsetsDidChange UIViewController方法获取表视图强制设置滚动视图插图到安全区域插页。 这与马吉的回答中的“从不”设置相结合。

 - (void)viewSafeAreaInsetsDidChange { [super viewSafeAreaInsetsDidChange]; self.tableView.contentInset = self.view.safeAreaInsets; } 

注意: self.tableViewself.view应该是UITableViewController相同的东西

删除此代码为我工作

 self.edgesForExtendedLayout = UIRectEdgeNone 

在我的情况下,这工作(把它放在viewDidLoad):

 self.navigationController.navigationBar.translucent = YES; 

请确保与上面的代码一起,添加如下代码。 它解决了这个问题

 override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) // print(thisUISBTV.adjustedContentInset) }