iOS11中奇怪的uitableview行为.单元格向上滚动导航推送动画

iur*_*iur 116 animation uitableview uinavigationcontroller ios

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

我现在从UITableView得到一个非常令人困惑的行为.tableview本身并不那么花哨.我有自定义单元格但在大多数情况下它只是为了它们的高度.

当我用tableview推动我的视图控制器时,我得到一个额外的动画,其中单元格"向上滚动"(或者可能整个桌面框架被更改)并沿着推/弹导航动画向下移动.请看gif:

波浪的tableview

我手动创建tableviewloadView方法和设置自动布局约束等于前置,顶部的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)
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑2:我能够将问题缩小到我对UINavigationBar的定制.我有这样的定制:

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

在哪里createFilledImage创建具有给定大小和颜色的方形图像.

如果我注释掉这一行,我会恢复正常行为.

我很感激有关这件事的任何想法.

Mag*_*len 147

这是由于UIScrollView's (UITableView是UIScrollview的子类)contentInsetAdjustmentBehavior属性,.automatic默认情况下设置为.

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

    tableView.contentInsetAdjustmentBehavior = .never
Run Code Online (Sandbox Code Playgroud)

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

  • 你也可以用故事板做到这一点.大小检查器 - >内容插入 - >设置"从不". (8认同)
  • 此问题是由iOS 11中的错误引起的,其中视图控制器视图的safeAreaInsets在导航过渡期间设置不正确,应在iOS 11.2中修复.将`contentInsetAdjustmentBehavior`设置为`.never`不是一个很好的解决方法,因为它可能会产生其他不良副作用.如果您确实使用了解决方法,则应确保在iOS版本> = 11.2时删除它. (8认同)
  • 如果您的内容延伸到标签栏后面,禁用`tableView.contentInsetAdjustmentBehavior`会破坏插入内容. (4认同)
  • 此外,简单地禁用此功能会将滚动指示器放在iPhone X上的(顶部Gizmo)后面.此行为的重点是调整scrollviews的内容区域,以便它们在非矩形的屏幕上可见.我想我们目前只能在iPhone X Sim上看到这个. (4认同)
  • 上UIScrollViewContentInsetAdjustmentBehavior.automatic的定义此评论说:" ......向后兼容性也将调整顶部和底部contentInset当滚动视图是通过用一个automaticallyAdjustsScrollViewInsets视图控制器导航控制器内部资= YES,无论滚动视图是可滚动的".我的理论是导航栏的contentInset受设置背景图像的影响,然后动态调整. (2认同)

Lal*_*hna 22

除了maggy的答案

Objective-C的

if (@available(iOS 11.0, *)) {
    scrollViewForView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
Run Code Online (Sandbox Code Playgroud)

此问题是由iOS 11中的错误引起的,其中safeAreaInsets视图控制器的视图在导航过渡期间设置不正确,应在iOS 11.2中修复.设置 contentInsetAdjustmentBehavior.never是不是一个伟大的解决方法,因为它很可能有其他不良的副作用.如果您确实使用了解决方法,则应确保在iOS版本> = 11.2时删除它

- 由smileyborg提到(Apple的软件工程师)


小智 6

您可以使用NSProxy在整个应用程序中立即编辑此行为,例如didFinishLaunchingWithOptions:

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


San*_*aus 5

这是我设法解决此问题的方法,同时仍然允许iOS 11自动设置插图。我正在使用UITableViewController

  • 在情节提要中的视图控制器中(或以编程方式)选择“顶部栏下方的延伸边缘”和“不透明栏下方的延伸边缘” 。安全区域插图将阻止您的视图进入顶部栏。
  • 在情节提要的表格视图中,选中“插入到安全区域”按钮。(或tableView.insetsContentViewsToSafeArea = true)-这可能不是必需的,但这就是我所做的。
  • 将内容插图调整行为设置为“可滚动轴”(或tableView.contentInsetAdjustmentBehavior = .scrollableAxes)- .always可能也可以,但是我没有测试。

如果其他所有方法都失败,请尝试另一件事:

viewSafeAreaInsetsDidChange UIViewController获取表视图的重写方法,将滚动视图插图强制设置为安全区域插图。这与Maggy答案中的“从不”设置结合在一起。

- (void)viewSafeAreaInsetsDidChange {
    [super viewSafeAreaInsetsDidChange];
    self.tableView.contentInset = self.view.safeAreaInsets;
}
Run Code Online (Sandbox Code Playgroud)

注意:self.tableViewself.view应该是一样的UITableViewController