如何防止我的 SwiftUI 视图在滚动时调整大小

问题描述

我希望有人能指出我正确的方向 - 我一直在试验 SwiftUI,我创建了一个与 Twitter 个人资料 UI 有点相似的视图。

标题折叠时,我似乎有一个奇怪的效果

在滚动视图包含在标题下滚动之前,有一个“最佳位置”,其中标题折叠并且标签栏调整了少量大小。

您可以在 this video 中看到。

我根本不希望标签段调整大小,而是应该在标题折叠后保持原位,并且滚动视图应该在其下方自由移动。

我确定我遗漏了一些明显的东西,但一些新鲜的眼睛可能正是我需要的帮助。

对此的任何想法将不胜感激!

import SwiftUI

struct ContentView: View {
    
    @State private var safeArea: EdgeInsets = EdgeInsets(.zero)
    @State private var offset: CGFloat = 0
    @State private var tabBarOffset: CGFloat = 0
    
    @State var currentTab = "Tab #1"
    @Namespace var animation
    
    var body: some View {
        GeometryReader { foo in
            ScrollView {
                vstack(spacing: 0) {
                    // Header
                    GeometryReader { proxy -> AnyView in
                        // Sticky Header
                        dispatchQueue.main.async {
                            offset = proxy.frame(in: .global).minY
                            safeArea = foo.safeAreaInsets
                        }
                        
                        return AnyView(makeHeader())
                    }
                    .frame(height: 180)
                    .zIndex(1)
                    
                    // Profile
                    vstack(spacing: 0) {
                        vstack(spacing: 0) {
                            HStack(spacing: 0) {
                                TabButton(title: "Tab #1",currentTab: $currentTab,animation: animation)
                                    .frame(maxWidth: .infinity)
                                TabButton(title: "Tab #2",animation: animation)
                                    .frame(maxWidth: .infinity)
                                TabButton(title: "Tab #3",animation: animation)
                                    .frame(maxWidth: .infinity)
                            }
                            Divider()
                        }
                        .padding(.top,20)
                        .background(Color.white)
                        .offset(y: tabBarOffset < 90 ? -tabBarOffset + 90 : 0)
                        .overlay(
                            GeometryReader { proxy -> Color in
                                dispatchQueue.main.async {
                                    tabBarOffset = proxy.frame(in: .global).minY
                                }
                                return Color.clear
                            }
                            .frame(width: 0,height: 0),alignment: .top
                        )
                        .zIndex(1)
                        vstack {
                            ForEach((0..<50)) {
                                Text("Row #\($0)")
                                Divider()
                            }
                        }
                        .padding(.top)
                        .zIndex(0)
                    }
                }
            }
            .ignoresSafeArea(.all,edges: .top)
        }
    }
    
    @viewbuilder func makeHeader() -> some View {
        ZStack {
            // Cover
            Color.gray
                .frame(maxWidth: .infinity)
                .frame(height: offset > 0 ? 180 + offset : 180)
        }
        .clipped()
        // Stretchy Effect
        .frame(height: offset > 0 ? 180 + offset : nil)
        .offset(y: offset > 0 ? -offset : -offset < 80 ? 0 : -offset - 80)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

struct TabButton: View {
    var title: String
    @Binding var currentTab: String
    var animation: Namespace.ID
    
    var body: some View {
        Button(
            action: {
                withAnimation { currentTab = title }
            },label: {
                Lazyvstack(spacing: 12) {
                    Text(title)
                        .fontWeight(.semibold)
                        .foregroundColor(currentTab == title ? .blue : .gray)
                        .padding(.horizontal)
                    
                    if currentTab == title {
                        Capsule()
                            .fill(Color.blue)
                            .frame(height: 1.2)
                            .matchedGeometryEffect(id: "TAB",in: animation)
                    } else {
                        Capsule()
                            .fill(Color.clear)
                            .frame(height: 1.2)
                    }
                    
                }
            }
        )
    }
}

解决方法

在这里,设置 90 而不是 80。作为您设置顶部标签栏视图 y 偏移 90 并且您的整个逻辑基于 90 值。

 DECLARE @MyTable TABLE( ID int,SomeCount int,SomeFlags int)
INSERT INTO @MyTable
    VALUES
            (1,2,0),(1,3,2),1),(2,1,4),5,1)
;

WITH SumTable   AS 
    (
        SELECT 
                iD,TestSum     =   SUM(SomeCount),BitOrSum    =   SUM(SomeCount | SomeFlags)
        FROM @MyTable
        GROUP BY ID
    )

SELECT  
        T.ID,S.TestSum,S.BitOrSum
FROM    @MyTable    T
JOIN    SumTable    S   ON  S.ID = T.ID
ORDER BY ID