滚动视图+;NavigationView动画故障SwiftUI

滚动视图+;NavigationView动画故障SwiftUI,swift,animation,swiftui,scrollview,Swift,Animation,Swiftui,Scrollview,我有一个简单的观点: var主体:一些视图{ 导航视图{ 滚动视图{ VStack{ ForEach(0..这里有一个解决方法。将.padding(.top,1)添加到滚动视图中: struct ContentView: View { var body: some View { NavigationView { ScrollView { VStack {

我有一个简单的观点:

var主体:一些视图{
导航视图{
滚动视图{
VStack{

ForEach(0..这里有一个解决方法。将
.padding(.top,1)
添加到
滚动视图中

struct ContentView: View {
            
    var body: some View {
        NavigationView {
            ScrollView {
                VStack {
                    ForEach(0..<2) { _ in
                        Color.blue.frame(width: 350, height: 200)
                    }
                }
            }
            .padding(.top, 1)
            .navigationBarTitle("Testing", displayMode: .automatic)
        }
            
    }
}
struct ContentView:View{
var body:一些观点{
导航视图{
滚动视图{
VStack{

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

  • 滚动视图不在NavigationView和TabView下扩展-这使得它失去了滚动条下内容的美丽模糊效果
  • 在滚动视图上设置背景将导致大标题导航视图停止折叠
  • 当我不得不更改我正在使用的应用程序的所有屏幕的背景色时,我遇到了这些问题。 所以我做了更多的挖掘和实验,设法找到了一个很好的解决方案

    以下是原始解决方案: 我们将滚动视图包装为两个几何体读取器

    最上面的一个是关于安全区域的-我们需要这个来阅读安全区域插图 第二个是全屏

    我们将滚动视图放入第二个几何体阅读器,使其大小达到全屏

    然后,通过应用安全区域填充,使用VStack添加内容

    最后,我们有一个滚动视图,它不会闪烁,并且在不破坏导航栏大标题的情况下接受背景

    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"))
            }
        }
    }
    
    例1
    struct ContentView:View{
    var body:一些观点{
    导航视图{
    滚动视图{
    VStack{
    颜色。红色。边框(宽度:100,高度:100,对齐:。中心)
    
    ForEach(0..面对同样的问题,我做了一些调查。 这个小故障似乎来自scrollview反弹和滚动上下文减速的速度

    目前,我通过将减速率设置为fast,成功地消除了这个小故障。它似乎让swiftui在保持反弹动画活动的同时,更好地计算布局

    我的解决方法很简单,就是在视图的init中设置以下内容。缺点是这会影响滚动减速的速度

     init() {
        UIScrollView.appearance().decelerationRate = .fast
    }
    
    一个可能的改进是计算显示内容的大小,然后根据需要动态切换减速率。

    我简化了。这里是:

    extension ScrollView {
        private typealias PaddedContent = ModifiedContent<Content, _PaddingLayout>
        
        func fixFlickering() -> some View {
            GeometryReader { geo in
                ScrollView<PaddedContent>(axes, showsIndicators: showsIndicators) {
                    content.padding(geo.safeAreaInsets) as! PaddedContent
                }
                .edgesIgnoringSafeArea(.all)
            }
        }
    }
    

    谢谢你发布这篇文章!我很好奇是什么思维过程让你找到了这个解决方案…@PeterFriese,我开始在scrollView上方放置一个额外的视图,认为scrollView和导航栏之间存在交互作用。这很有效。然后我缩小了视图的大小,发现它可能非常短而且仍然有效k、 因为这个视图是作为填充的,所以我决定尝试用填充替换它,并且发现它也起了作用。所以这个公式是一部分直觉,一部分尝试的东西。@PeterFriese,如果你查看编辑历史,你会看到我的第一个解决方案是使用额外的视图。在swiftui两年后,我们仍然需要这些wo,这太疯狂了rkarounds!无论如何,谢谢你!@RicoCrescenzio,是的,我同意。有时它的边缘仍然有点粗糙。Swift语言需要3到4年的时间才能成熟。谢谢你这么详细的解释,我真的很感激这应该是公认的答案。这几乎是完美的,只是它没有更新
    滚动指示器集ode>!遗憾的是,我想知道您是否需要UIKit来真正正确地执行此操作。不幸的是,它不能与Stack V LazyTIL的
    pinnedView
    配合使用,关于
    \u PaddingLayout
    -这是否有文档记录?这看起来更优雅,但也更脆弱。@Steipet我通常通过打印SwiftUI视图来找到类似的东西,然后重新编写正在加载它生成的类型。我在任何地方都没有发现它的文档。如果您感兴趣,我还发现了Xcode自动完成初始值设定项,例如,我假设它是私有的。@Steipte虽然这个解决方案是“健壮的”,但我不确定使用诸如
    \u PaddingLayout
    之类的东西是否算作“私有API”。毕竟,这个解决方案pe通常是推断出来的。如果你像我一样有点不确定,你可以制作类似于
    struct ContentAcceptingScrollView{…}
    的东西,它只是在主体中创建一个
    ScrollView
    ,但是内容类型是推断出来的,所以我们不需要这种类型转换。
    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"))
            }
        }
    }
    
     init() {
        UIScrollView.appearance().decelerationRate = .fast
    }
    
    extension ScrollView {
        private typealias PaddedContent = ModifiedContent<Content, _PaddingLayout>
        
        func fixFlickering() -> some View {
            GeometryReader { geo in
                ScrollView<PaddedContent>(axes, showsIndicators: showsIndicators) {
                    content.padding(geo.safeAreaInsets) as! PaddedContent
                }
                .edgesIgnoringSafeArea(.all)
            }
        }
    }
    
    struct ContentView: View {
        var body: some View {
            NavigationView {
                ScrollView {
                    /* ... */
                }
                .fixFlickering()
            }
        }
    }