【问题标题】:How to animate navigationBarHidden in SwiftUI?如何在 SwiftUI 中为 navigationBarHidden 设置动画?
【发布时间】:2020-09-04 12:18:30
【问题描述】:
struct ContentView: View {
    @State var hideNavigationBar: Bool = false
    
    var body: some View {
        NavigationView {
            ScrollView {
                VStack {
                    Rectangle().fill(Color.red).frame(height: 50)
                        .onTapGesture(count: 1, perform: {
                            withAnimation {
                                self.hideNavigationBar.toggle()
                            }
                        })
                    VStack {
                        ForEach(1..<50) { index in
                            HStack {
                                Text("Sample Text")
                                Spacer()
                            }
                        }
                    }
                }
            }
            .navigationBarTitle("Browse")
            .navigationBarHidden(hideNavigationBar)
        }
    }
}

当您点击红色矩形时,它会捕捉导航栏。我以为withAnimation{} 会解决这个问题,但事实并非如此。在UIKit 中,您会执行类似navigationController?.setNavigationBarHidden(true, animated: true) 的操作。

在 xCode 12 beta 6 和 xCode 11.7 中测试

【问题讨论】:

  • 我仍在学习 SwiftUI 中的动画...目前我知道我们必须为父视图设置动画。您是否尝试将.animate() 视图修饰符应用于ScrollView? (我建议把它放在.navigationBarHidden(hideNavigationBar)

标签: swift swiftui hidden navigationbar


【解决方案1】:

你可以试试

.navigationBarHidden(hideNavigationBar).animation(.linear(duration: 0.5)) 而不是.navigationBarHidden(hideNavigationBar)

并将self.hideNavigationBar.toggle() 移出动画块。如果您使用上述方法隐藏带有动画的导航栏,则不需要这样做。

【讨论】:

  • 嘿,安德鲁,你在 xCode 中尝试过你的代码吗,因为我像你说的那样把这条线改成了动画,但是当按下红色矩形时它仍然显示出活泼的行为。
  • 我确实尝试了代码,它对我来说工作正常。您使用的是什么版本的 Xcode。我检查了 Xcode 12
  • 不知何故我需要重新启动。我会将其标记为答案。
  • 真的还在工作吗?我试过了,它只为 toolbar 项目设置动画,而不是导航栏本身。
  • 它确实有效!重要的是要理解:animation 修饰符必须以某种方式“击中”NavigationView 或它的顶级容器(此处为 ScrollView),否则 hideNavigationBar 的更改不会动画。我想navigationBarHidden 修饰符使用 SwiftUI 首选项系统与NavigationView 对话,因此应用于navigationBarHidden 修饰符的任何动画修饰符都有些无关紧要。应用于NavigationView/顶级容器的修饰符很重要。
【解决方案2】:

我认为,唯一的解决方案是在 SwiftUI 2 中使用位置函数

var body: some View {
    GeometryReader { geometry in
        NavigationView {
            ZStack {
                Color("background")
                    .ignoresSafeArea()
                
                // ContentView
            }
            .navigationBarTitleDisplayMode(.inline)
            .navigationBarItems(leading: logo, trailing: barButtonItems)
            .toolbar {
                ToolbarItem(placement: .principal) {
                    SearchBarButton(placeholder: LocalizedStringKey("home_vc.search_bar.placeholder"))
                        .opacity(isNavigationBarHidden ? 0 : 1)
                        .animation(.easeInOut(duration: data.duration))
                }
                
            }
        }
        .frame(height: geometry.size.height + (isNavigationBarHidden ? 70 : 0))
         // This is the key ⬇
        .position(x: geometry.size.width/2, y: geometry.size.height/2 - (isNavigationBarHidden ? 35 : 0))
        .animation(.easeInOut(duration: 0.38))
        .onTapGesture {
            isNavigationBarHidden.toggle()
        }
    }
}

【讨论】:

    【解决方案3】:

    我仍在学习 SwiftUI 中的动画,但在这个阶段,我知道您必须为父视图设置动画。

    所以你的代码会变成...

    struct ContentView: View {
    
        @State var hideNavigationBar: Bool = false
        
        var body: some View {
            NavigationView {
                ScrollView {
                    VStack {
                        Rectangle().fill(Color.red).frame(height: 50)
                            .onTapGesture(count: 1) {
                                self.hideNavigationBar.toggle()
                            }
                        VStack {
                            ForEach(1..<50) { index in
                                HStack {
                                    Text("Sample Text")
                                    Spacer()
                                }
                            }
                        }
                    }
                }
                .navigationBarTitle("Browse")
                .navigationBarHidden(hideNavigationBar)
                .animation(.spring()) // for example
            }
        }
    }
    

    请注意,任何函数调用中的最后一个参数都可以放入单个闭包中。

    所以...

                        .onTapGesture(count: 1, perform: {
                            self.hideNavigationBar.toggle()
                        })
    

    可以变成……

                        .onTapGesture(count: 1) {
                            self.hideNavigationBar.toggle()
                        }
    

    在我看来更简单的语法。

    【讨论】:

    • 嘿,安德鲁,您在 xCode 中尝试过您的代码吗,因为我复制并粘贴了它,但是仍然存在活泼的行为。
    • @Mark 既然你提到了它......我实际上还没有能够为导航栏设置动画。这是一个常见的抱怨。我会做更多的研究并更新我的答案 - 它仍然是我的 iOS 14 目标中的一个问题......我已经成功完成并且可以建议的一件事是,虽然这不是解决方案,但可以为导航栏周围的元素设置动画.这会将用户的注意力从导航栏上移开。
    • 感谢您的意见。我将它提交给你永远不知道的 Apple 反馈。
    猜你喜欢
    • 2019-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 2021-03-04
    • 2020-12-22
    • 1970-01-01
    相关资源
    最近更新 更多