iOS 13:导航控制器内的滚动视图不会进入状态栏

问题描述 投票:0回答:1

我想让SwiftUI可以使用自定义滚动视图,这将允许我设置滚动位置。我走了一半,滚动时滚动视图无法在状态栏下正确显示。

问题看起来像这样:

enter image description here

[进行测试以查看出什么问题时,我制作了一个基于情节提要的比较项目,该项目完全没有代码,只是一个结构与我的代码完全相同。然后结果看起来像这样,这就是我想要实现的:

enter image description here

似乎根视图控制器视图没有完全到达顶部,但是我不知道为什么。所有其他自动滚动插入魔术均应正常工作。

这是我的代码,您只需在Xcode 11中使用SwiftUI创建一个新项目,然后将其粘贴到ContentView.swift中。

import SwiftUI
import UIKit

class UIScrollableViewController: UIViewController {
    let scrollView = UIScrollView()
    let contentController: UIViewController

    init(contentController: UIViewController) {
        self.contentController = contentController

        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(scrollView)

        // Add child controller
        scrollView.addSubview(contentController.view)
        addChild(contentController)

        let contentView = contentController.view!

        // Constrain scroll view
        scrollView.translatesAutoresizingMaskIntoConstraints = false;
        scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true
        scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
        scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0).isActive = true
        scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true

        // Constrain child view to scroll view
        contentView.translatesAutoresizingMaskIntoConstraints = false
        contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
        contentView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
        contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
        contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true

        // Constrain width of child view to width of self.view, NOT scroll view
        contentView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
    }
}

class ScrollableNavigationController: UINavigationController, UINavigationBarDelegate {
}

struct ScrollableNavigationViewController<Content: View>: UIViewControllerRepresentable {
    typealias UIViewControllerType = ScrollableNavigationController

    let hostingController: UIHostingController<Content>
    let scrollableContainer: UIScrollableViewController!

    init(@ViewBuilder content: () -> Content) {
        hostingController = UIHostingController(rootView: content())
        scrollableContainer = UIScrollableViewController(contentController: hostingController)

        scrollableContainer.title = "Scrollable"
    }

    func makeUIViewController(context: UIViewControllerRepresentableContext<ScrollableNavigationViewController>) -> ScrollableNavigationController {
        let navigationController = ScrollableNavigationController(rootViewController: scrollableContainer)

        navigationController.navigationBar.prefersLargeTitles = true

        return navigationController
    }

    func updateUIViewController(_ navigationController: ScrollableNavigationController, context: UIViewControllerRepresentableContext<ScrollableNavigationViewController>) {
    }
}

struct ScrollableNavigationView<Content: View>: View {
    var content: Content

    init(@ViewBuilder content: () -> Content) {
        self.content = content()
    }

    var body: some View {
        ScrollableNavigationViewController {
            content
        }
    }
}

// MARK: Test

struct BoxView: View {
    var colors: [Color] = [.red, .blue, .orange, .pink, .yellow]

    var body: some View {
        ForEach(0 ..< 20) { i in
            ZStack {
                Rectangle()
                    .fill(self.colors[i % 5])
                    .padding()
                    .frame(height: 130)
                Text("\(i)")
                    .font(.title)
            }
        }
    }
}

struct ContentView: View {
    var body: some View {
        ScrollableNavigationView {
            BoxView()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
ios swift uinavigationcontroller
1个回答
0
投票

问题似乎是场景委托,它导致整个视图层次结构包裹在UIHostingController内,这是嵌套SwiftUI控制器似乎能够避免的自身插入魔术。为了证明这一点,我想出了一个有点棘手的解决方案。

替换为:

window.rootViewController = UIHostingController(rootView: ContentView())

with:

window.rootViewController = MyHostingController(rootView: ContentView())

MyHostingController看起来像这样:

class MyHostingController<Content: View>: UIHostingController<Content> {
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        view.subviews[0].frame = UIScreen.main.bounds
    }
}

从iOS 13.1开始,看来您真的应该只尝试在两层UIKit之间集成SwiftUI,而不是相反。 SwiftUI的内部包含太多未记录的魔术。

© www.soinside.com 2019 - 2024. All rights reserved.