3

我正在制作一个应用程序,其中 1 个屏幕具有 3 个分段的分段控件。最初我有 1 个表格视图,当您更改段时,我只需更改数据源/单元格等并重新加载表格。虽然这很好用,但总是存在一个问题,即当您更改段时,它不会记住您的最后滚动位置,因为表格视图会重新加载。

我试图通过存储偏移位置、行等来解决这个问题,但我永远无法让它像我想要的那样工作。当您有不同的单元类型用于段并且它们也可以自行调整大小时,这似乎特别烦人。

我决定拥有一个带有分段控件的主视图控制器和 3 个容器视图,每个段都有自己的 VC 和表视图。我只是在更改段时隐藏/显示正确的容器视图。这也很好用,但我对 iOS 11 风格的大标题有 1 个问题。只有作为子视图添加到 ViewControllers 视图的第一个容器视图在您滚动时操纵标题的折叠/展开。

在此处输入图像描述

因此,当我更改为第二个或第三个容器视图并开始滚动时,我没有得到大标题折叠动画。我怎样才能解决这个问题?

我尝试了以下

1)更改段时更改容器视图zPosition

2)通过调用将容器视图移到前面view.bringSubview(toFront: ...)

3)循环遍历子视图并调用 view.exchangeSubview(at: 0, withSubviewAt: ...)

我相信我可以删除所有容器视图并再次添加我需要的视图并给它们限制,但我想知道是否有更直接的解决方案。

或者,如果有人有一个很好的解决方案可以在重新加载之前记住 tableViews 滚动位置,我也会很感激。

4

2 回答 2

0

因此,感谢这篇精彩的文章,我找到了一个似乎对我有用的答案。https://cocoacasts.com/managing-view-controllers-with-container-view-controllers/

基本上我所做的是

1) 从 MasterViewController Storyboard 中移除 ContainerViews 和 Segues。

2)在MasterViewController中为分段控件的每个VC添加一个惰性属性。它们是懒惰的,因此它们仅在您真正需要它们时才被初始化

 lazy var viewController1: LibraryViewController = {
        let viewController = UIStoryboard.libraryViewController // convenience property to create the VC from Storyboard
        // do other set up if required.
        return viewController
    }()

lazy var viewController2: LibraryViewController = {
            let viewController = UIStoryboard.libraryViewController // convenience property to create the VC from Storyboard
            // do other set up if required.
            return viewController
        }()

3) 使用以下 2 种方法创建 UIViewController 的扩展。我将它们添加到纯粹用于代码组织的扩展中,因为它们可能会在其他 ViewController 上重用。

extension UIViewController {

    func add(asChildViewController viewController: UIViewController) {
        // Add Child View Controller
        addChildViewController(viewController)

        // Add Child View as Subview
        view.addSubview(viewController.view)

        // Configure Child View
        viewController.view.frame = view.bounds
        viewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]

        // Notify Child View Controller
        viewController.didMove(toParentViewController: self)
    }

    func remove(asChildViewController viewController: UIViewController) {
        // Notify Child View Controller
        viewController.willMove(toParentViewController: nil)

        // Remove Child View From Superview
        viewController.view.removeFromSuperview()

        // Notify Child View Controller
        viewController.removeFromParentViewController()
    }
}

4) 现在,在更改段时调用的分段控制方法中,我只需添加正确的 ViewController。好消息是删除/添加它们实际上并没有释放它们。

func didPressSegmentedControl() {

   if segmentedControl.selectedSegmentIndex == 0 {
        remove(asChildViewController: viewController2)
        add(asChildViewController: viewController1)
    } else {
        remove(asChildViewController: viewController1)
        add(asChildViewController: viewController2)
    }
}

5) 确保在第 4 点调用该方法,ViewDidLoad以便在第一次加载 VC 时添加正确的 VC。

func viewDidLoad() {
    super.viewDidLoad()

    didPressSegmentedControl()
}

这样,当我们删除一个 ChildViewController 并添加另一个时,它将始终是 subviews 数组中的顶部 VC,并且我得到了漂亮的标题折叠动画。

这种方法的另一个好处是,如果你从不去特定的段,那么特定的 VC 将永远不会被初始化,因为它们是惰性属性,这应该有助于提高效率。

希望这可以帮助尝试做同样事情的人。

于 2017-10-29T11:23:36.067 回答
0

这是一个可怕的问题,我希望很快就能解决,但还有另一个解决方法——尽管我坦率地承认这是一个令人讨厌的 hack。

基本上,该问题仅适用于层次结构中的第一个容器视图。将另一个容器视图添加到您的层次结构。将它设置为隐藏,然后删除它的 segue 和它的目标视图控制器只是为了整洁。最后,通过将其拖到列表顶部,确保这是层次结构中的第一个容器视图。

于 2018-07-18T11:05:50.570 回答