swift - ScrollView + NavigationView动画故障SwiftUI

标签 swift animation swiftui scrollview

我有一个简单的看法:

var body: some View {
        NavigationView {
            ScrollView {
                VStack {
                    ForEach(0..<2) { _ in
                        CardVew(for: cardData)
                    }
                }
            }
            .navigationBarTitle("Testing", displayMode: .automatic)
        }
    }
但是您可以用任何东西替换CardView-故障仍然存在。 Glitch video
有办法解决吗?
Xcode 12.0.1,Swift 5

最佳答案

将顶部填充设置为1会破坏至少两个主要方面:

  • 滚动 View 不会在NavigationView和TabView下扩展-这使其失去了滚动在条形下的内容的优美模糊效果。
  • 在滚动 View 上设置背景将导致大标题NavigationView停止折叠。

  • 当我不得不在正在处理的应用程序的所有屏幕上更改背景颜色时,我遇到了这些问题。
    因此,我做了一些更多的挖掘和实验,并设法找到了解决该问题的不错的解决方案。
    这是原始解决方案:
    我们将ScrollView封装为2个几何读取器。
    最重要的一点是尊重安全区域-我们需要这一点才能阅读安全区域插图
    第二个是全屏显示。
    我们将滚动 View 放入第二个几何读取器中-使其大小变为全屏。
    然后,我们使用VStack通过应用安全区域填充来添加内容。
    最后-我们拥有不会闪烁的滚动 View ,并且可以接受背景而不会破坏导航栏的大标题。
    struct ContentView: View {
        var body: some View {
            NavigationView {
                GeometryReader { geometryWithSafeArea in
                    GeometryReader { geometry in
                        ScrollView {
                            VStack {
    
                                Color.red.frame(width: 100, height: 100, alignment: .center)
    
                                ForEach(0..<5) { i in
    
                                    Text("\(i)")
                                        .frame(maxWidth: .infinity)
                                        .background(Color.green)
    
                                    Spacer()
                                }
    
                                Color.red.frame(width: 100, height: 100, alignment: .center)
                            }
                            .padding(.top, geometryWithSafeArea.safeAreaInsets.top)
                            .padding(.bottom, geometryWithSafeArea.safeAreaInsets.bottom)
                            .padding(.leading, geometryWithSafeArea.safeAreaInsets.leading)
                            .padding(.trailing, geometryWithSafeArea.safeAreaInsets.trailing)
                        }
                        .background(Color.yellow)
                    }
                    .edgesIgnoringSafeArea(.all)
                }
                .navigationBarTitle(Text("Example"))
            }
        }
    }
    
    优雅的解决方案
    由于该解决方案现在很清晰-让我们创建一个优雅的解决方案,只需替换填充修补程序即可将其重复使用并应用于任何现有ScrollView。
    我们创建了ScrollView的扩展,该扩展声明了fixFlickering函数。
    逻辑基本上是,我们将接收器包装到几何读取器中,并使用安全区域填充将其内容包装到VStack中。
    之所以使用ScrollView,是因为编译器错误地推断出嵌套滚动 View 的内容,该内容应与接收者相同。显式声明AnyView将使其接受包装的内容。
    有2个重载:
  • 第一个不接受任何参数,您可以在任何现有的滚动 View 中调用它,例如。您可以将.padding(.top, 1)替换为.fixFlickering()-就是这样。
  • 第二个接受configurator闭包,该闭包用于为您提供设置嵌套滚动 View 的机会。那是必需的,因为我们不使用接收器而只是包装它,而是创建一个新的ScrollView实例,并且仅使用接收器的配置和内容。在此关闭中,您可以按任何方式修改提供的ScrollView,例如。设置背景色。
  • extension ScrollView {
        
        public func fixFlickering() -> some View {
            
            return self.fixFlickering { (scrollView) in
                
                return scrollView
            }
        }
        
        public func fixFlickering<T: View>(@ViewBuilder configurator: @escaping (ScrollView<AnyView>) -> T) -> some View {
            
            GeometryReader { geometryWithSafeArea in
                GeometryReader { geometry in
                    configurator(
                    ScrollView<AnyView>(self.axes, showsIndicators: self.showsIndicators) {
                        AnyView(
                        VStack {
                            self.content
                        }
                        .padding(.top, geometryWithSafeArea.safeAreaInsets.top)
                        .padding(.bottom, geometryWithSafeArea.safeAreaInsets.bottom)
                        .padding(.leading, geometryWithSafeArea.safeAreaInsets.leading)
                        .padding(.trailing, geometryWithSafeArea.safeAreaInsets.trailing)
                        )
                    }
                    )
                }
                .edgesIgnoringSafeArea(.all)
            }
        }
    }
    
    例子1
    struct ContentView: View {
        var body: some View {
            NavigationView {
                ScrollView {
                    VStack {
                        Color.red.frame(width: 100, height: 100, alignment: .center)
    
                        ForEach(0..<5) { i in
    
                            Text("\(i)")
                                .frame(maxWidth: .infinity)
                                .background(Color.green)
                            
                            Spacer()
                        }
    
                        Color.red.frame(width: 100, height: 100, alignment: .center)
                    }
                }
                .fixFlickering { scrollView in
                    
                    scrollView
                        .background(Color.yellow)
                }
                .navigationBarTitle(Text("Example"))
            }
        }
    }
    
    例子2
    struct ContentView: View {
        var body: some View {
            NavigationView {
                ScrollView {
                    VStack {
                        Color.red.frame(width: 100, height: 100, alignment: .center)
    
                        ForEach(0..<5) { i in
    
                            Text("\(i)")
                                .frame(maxWidth: .infinity)
                                .background(Color.green)
                            
                            Spacer()
                        }
    
                        Color.red.frame(width: 100, height: 100, alignment: .center)
                    }
                }
                .fixFlickering()
                .navigationBarTitle(Text("Example"))
            }
        }
    }
    

    关于swift - ScrollView + NavigationView动画故障SwiftUI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64280447/

    相关文章:

    swift - 在 NSTokenField 中设置 token

    ios - TextView 中的按钮

    Android:覆盖 Activity 主题对话框的挂起转换不起作用

    c++ - 如何在用 C++ 编写的控制台应用程序中制作加载动画?

    ios - 以编程方式添加后,使用约束为 UIView 设置动画

    swift - 如何使用 UserDefaults registerDefaults()

    ios - swift 2 : Can't find audio file path when I use variables as file names

    Swift 编译器错误 : "Type ' Watermark' does not conform to protocol 'ViewModifier' "

    ios - 使用 SwiftUI 中断后恢复 AVPlayer

    javascript - 在 swiftui 中评估 JavaScript