如何防止我的 SwiftUI 视图在滚动时调整大小 [英] How can I prevent my SwiftUI view resizing on scroll

查看:45
本文介绍了如何防止我的 SwiftUI 视图在滚动时调整大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I’m hoping someone can point me in the right direction - I have been experimenting with SwiftUI, I’ve created a view somewhat similar to the Twitter Profile UI.

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

I seem to have a weird effect when the header collapses.

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

There is a ‘sweet spot’ in which the header is collapsed and the tab bar resizes by a small amount before the scroll view contains to scroll under the header.

您可以在此视频中看到.

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

I don’t want the tab segment to resize at all, instead it should simply stay in place once the header has collapsed and the scroll view should move freely underneath it.

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

I’m sure I am missing something obvious, however some fresh eyes might be just the help I need.

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

Any thoughts on this would be much appreciated!

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", currentTab: $currentTab, animation: animation)
                                    .frame(maxWidth: .infinity)
                                TabButton(title: "Tab #3", currentTab: $currentTab, 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 值.

Here, Set 90 instead of 80. As your setting top tabbar view y offset 90 and your whole logic is based on 90 value.

@ViewBuilder func makeHeader() -> some View {
    ZStack {
        // Cover
        Color.red
            .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 < 90 ? 0 : -offset - 90) //<=== Here
}

这篇关于如何防止我的 SwiftUI 视图在滚动时调整大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆