导航栏在更改为内联之前短暂闪烁为大标题
Navigation bar briefly flickering as large title before changing to inline
我在我的 SwiftUI 应用程序中使用 UITabController,它运行良好,除了一个问题。
当我有一个使用大标题的 NavigationView 时,它会在我滚动时变为内联,正如预期的那样。到目前为止一切顺利。
当我切换选项卡然后再次切换回来时,它应该会记住滚动位置,因此是内联的。相反,在移动到内联之前,它会非常短暂地闪烁为一个大标题。
这似乎只发生在设备上。
有人能帮我解决问题吗?
struct ContentView: View {
var body: some View {
CustomTabView([
Tab(view: FirstView(),
barItem: UITabBarItem(title: "First", image: UIImage(systemName: "1.circle"), selectedImage: nil)),
Tab(view: SecondView(),
barItem: UITabBarItem(title: "Second", image: UIImage(systemName: "2.circle"), selectedImage: nil))
])
}
}
struct FirstView: View {
var body: some View {
NavigationView {
List {
ForEach( 0...40, id: \.self ) {
Text("\([=10=])")
.padding()
}
}
.navigationTitle("First View")
}
}
}
struct SecondView: View {
var body: some View {
NavigationView {
List {
ForEach( 41...80, id: \.self ) {
Text("\([=10=])")
.padding()
}
}
.navigationTitle("Second View")
}
}
}
struct TabBarController: UIViewControllerRepresentable {
var controllers: [UIViewController]
func makeUIViewController(context: Context) -> UITabBarController {
let tabBarController = UITabBarController()
tabBarController.viewControllers = controllers
tabBarController.delegate = context.coordinator
return tabBarController
}
func updateUIViewController(_ uiViewController: UITabBarController, context: Context) {}
func makeCoordinator() -> Coordinator {
Coordinator()
}
class Coordinator: NSObject, UITabBarControllerDelegate {
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
guard let fromView = tabBarController.selectedViewController?.view, let toView = viewController.view else {
return false
}
if fromView != toView {
fromView.superview!.addSubview(toView)
}
return true
}
}
}
struct CustomTabView: View {
var viewControllers: [UIHostingController<AnyView>]
init(_ tabs: [Tab]) {
self.viewControllers = tabs.map {
let host = UIHostingController(rootView: [=10=].view)
host.tabBarItem = [=10=].barItem
return host
}
}
var body: some View {
TabBarController(controllers: viewControllers)
.edgesIgnoringSafeArea(.all)
}
}
struct Tab {
var view: AnyView
var barItem: UITabBarItem
init<V: View>(view: V, barItem: UITabBarItem) {
self.view = AnyView(view)
self.barItem = barItem
}
}
我找到了解决方法/修复。
我需要使用自定义 UIHostingController,找到导航控制器,并在 viewWillAppear 函数中添加一行:
public class MyHostingController: UIHostingController<AnyView> {
override open func viewWillAppear(_ animated: Bool) {
if let navigationController = navigationController() {
navigationController.view.setNeedsUpdateConstraints()
}
super.viewWillAppear(animated)
}
}
private extension UIViewController {
func navigationController() -> UINavigationController? {
var controller: UINavigationController?
if let navigationController = self as? UINavigationController {
return navigationController
}
children.forEach {
if let navigationController = [=10=] as? UINavigationController {
controller = navigationController
} else {
controller = [=10=].navigationController()
}
}
return controller
}
}
然后显然用 MyHostingController 替换了我原始代码中 UIHostingController 的两个用法。
不过最重要的一行是:
navigationController.view.setNeedsUpdateConstraints()
希望这对发现类似问题的其他人有所帮助。
我在我的 SwiftUI 应用程序中使用 UITabController,它运行良好,除了一个问题。
当我有一个使用大标题的 NavigationView 时,它会在我滚动时变为内联,正如预期的那样。到目前为止一切顺利。
当我切换选项卡然后再次切换回来时,它应该会记住滚动位置,因此是内联的。相反,在移动到内联之前,它会非常短暂地闪烁为一个大标题。
这似乎只发生在设备上。
有人能帮我解决问题吗?
struct ContentView: View {
var body: some View {
CustomTabView([
Tab(view: FirstView(),
barItem: UITabBarItem(title: "First", image: UIImage(systemName: "1.circle"), selectedImage: nil)),
Tab(view: SecondView(),
barItem: UITabBarItem(title: "Second", image: UIImage(systemName: "2.circle"), selectedImage: nil))
])
}
}
struct FirstView: View {
var body: some View {
NavigationView {
List {
ForEach( 0...40, id: \.self ) {
Text("\([=10=])")
.padding()
}
}
.navigationTitle("First View")
}
}
}
struct SecondView: View {
var body: some View {
NavigationView {
List {
ForEach( 41...80, id: \.self ) {
Text("\([=10=])")
.padding()
}
}
.navigationTitle("Second View")
}
}
}
struct TabBarController: UIViewControllerRepresentable {
var controllers: [UIViewController]
func makeUIViewController(context: Context) -> UITabBarController {
let tabBarController = UITabBarController()
tabBarController.viewControllers = controllers
tabBarController.delegate = context.coordinator
return tabBarController
}
func updateUIViewController(_ uiViewController: UITabBarController, context: Context) {}
func makeCoordinator() -> Coordinator {
Coordinator()
}
class Coordinator: NSObject, UITabBarControllerDelegate {
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
guard let fromView = tabBarController.selectedViewController?.view, let toView = viewController.view else {
return false
}
if fromView != toView {
fromView.superview!.addSubview(toView)
}
return true
}
}
}
struct CustomTabView: View {
var viewControllers: [UIHostingController<AnyView>]
init(_ tabs: [Tab]) {
self.viewControllers = tabs.map {
let host = UIHostingController(rootView: [=10=].view)
host.tabBarItem = [=10=].barItem
return host
}
}
var body: some View {
TabBarController(controllers: viewControllers)
.edgesIgnoringSafeArea(.all)
}
}
struct Tab {
var view: AnyView
var barItem: UITabBarItem
init<V: View>(view: V, barItem: UITabBarItem) {
self.view = AnyView(view)
self.barItem = barItem
}
}
我找到了解决方法/修复。
我需要使用自定义 UIHostingController,找到导航控制器,并在 viewWillAppear 函数中添加一行:
public class MyHostingController: UIHostingController<AnyView> {
override open func viewWillAppear(_ animated: Bool) {
if let navigationController = navigationController() {
navigationController.view.setNeedsUpdateConstraints()
}
super.viewWillAppear(animated)
}
}
private extension UIViewController {
func navigationController() -> UINavigationController? {
var controller: UINavigationController?
if let navigationController = self as? UINavigationController {
return navigationController
}
children.forEach {
if let navigationController = [=10=] as? UINavigationController {
controller = navigationController
} else {
controller = [=10=].navigationController()
}
}
return controller
}
}
然后显然用 MyHostingController 替换了我原始代码中 UIHostingController 的两个用法。
不过最重要的一行是:
navigationController.view.setNeedsUpdateConstraints()
希望这对发现类似问题的其他人有所帮助。