我正在制作一个简单的视图与滚动视图和顶部标题的内容.当用户向下滚动时,我想隐藏标题,而当用户向上滚动时,我想要显示它.我有三个不同的选项卡,如果我手动在它们之间滑动,一切都很好.如果我try 并单击标题中的按钮来切换选项卡,滚动视图稍微调整了一下滚动视图,但什么也不做,那么我就会收到下面的大量错误.
The code works when (either or)个
- 移除.ignoresSafeArea(edges: .top)可以解决该问题
- 删除TabView并使用条件呈现来显示选项卡.
我想保留忽略安全区域和选项卡视图的功能,我如何解决这个问题?
The behavior of the UICollectionViewFlowLayout is not defined because: the item height must be less than the height of the UICollectionView minus the section insets top and bottom values, minus the content insets top and bottom values个
import SwiftUI
struct FeedViewSec: View {
@Environment(\.colorScheme) var colorScheme
@State private var selection = 0
@State var headerHeight: CGFloat = 130
@State var headerOffset: CGFloat = 0
@State var lastHeaderOffset: CGFloat = 0
@State var direction: SwipeDirection = .none
@State var shiftOffset: CGFloat = 0
var body: some View {
NavigationStack {
ZStack(alignment: .bottomTrailing){
TabView(selection: $selection) {
scrollBody().tag(0)
scrollBody().tag(1)
scrollBody().tag(2)
}.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
}
.overlay(alignment: .top) {
headerView().offset(y: -headerOffset < headerHeight ? headerOffset : (headerOffset < 0 ? headerOffset : 0))
}
.ignoresSafeArea(edges: .top)
}
}
func scrollBody() -> some View {
ScrollView {
LazyVStack {
Color.clear.frame(height: 130)
ForEach(0..<30){ i in
RoundedRectangle(cornerRadius: 15).frame(width: 100, height: 100)
}
}
.offsetY { previous, current in
if previous > current {
if direction != .up && current < 0{
shiftOffset = current - headerOffset
direction = .up
lastHeaderOffset = headerOffset
}
let offset = current < 0 ? (current - shiftOffset) : 0
headerOffset = (-offset < headerHeight ? (offset < 0 ? offset : 0) : -headerHeight * 2.0)
} else {
if direction != .down{
shiftOffset = current
direction = .down
lastHeaderOffset = headerOffset
}
let offset = lastHeaderOffset + (current - shiftOffset)
headerOffset = (offset > 0 ? 0 : offset)
}
}
}.coordinateSpace(name: "SCROLL")
}
func headerView() -> some View {
VStack(spacing: 0){
HStack {
HStack(spacing: 1){
Text("Explore").font(.title).bold()
Image(systemName: "chevron.down").font(.body).bold()
}
Spacer()
}
.padding(.leading)
HStack(alignment: .center, spacing: 0) {
Button {
withAnimation(.easeInOut){
selection = 0
}
} label: {
Text("New")
.foregroundColor(.black).bold()
.frame(width: 80, height: 25)
}
.background((selection == 0) ? colorScheme == .dark ? .gray.opacity(0.3) : .gray : colorScheme == .dark ? .gray : .gray.opacity(0.3))
Button {
withAnimation(.easeInOut){
selection = 1
}
} label: {
Text("LeaderBoard")
.foregroundColor(.black).bold()
.frame(width: 120, height: 25)
}
.background((selection == 1) ? colorScheme == .dark ? .gray.opacity(0.3) : .gray : colorScheme == .dark ? .gray : .gray.opacity(0.3))
Button {
withAnimation(.easeInOut){
selection = 2
}
} label: {
Text("Hot")
.foregroundColor(.black).bold()
.frame(width: 80, height: 25)
}
.background((selection == 2) ? colorScheme == .dark ? .gray.opacity(0.3) : .gray : colorScheme == .dark ? .gray : .gray.opacity(0.3))
}
.mask {
RoundedRectangle(cornerRadius: 5)
}
.padding(.top, 8)
Color.clear.frame(height: 13)
}
.padding(.top, top_Inset())
.background(.ultraThinMaterial)
}
}
func top_Inset() -> CGFloat {
let scenes = UIApplication.shared.connectedScenes
let windowScene = scenes.first as? UIWindowScene
let window = windowScene?.windows.first
return window?.safeAreaInsets.top ?? 0
}
extension View{
@ViewBuilder
func offsetY(completion: @escaping (CGFloat,CGFloat)->())->some View{
self.modifier(OffsetHelper(onChange: completion))
}
func safeArea()->UIEdgeInsets{
guard let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene else{return .zero}
guard let safeArea = scene.windows.first?.safeAreaInsets else{return .zero}
return safeArea
}
}
struct OffsetHelper: ViewModifier{
var onChange: (CGFloat,CGFloat)->()
@State var currentOffset: CGFloat = 0
@State var previousOffset: CGFloat = 0
func body(content: Content) -> some View {
content
.overlay {
GeometryReader{proxy in
let minY = proxy.frame(in: .named("SCROLL")).minY
Color.clear
.preference(key: OffsetKeyNew.self, value: minY)
.onPreferenceChange(OffsetKeyNew.self) { value in
previousOffset = currentOffset
currentOffset = value
onChange(previousOffset,currentOffset)
}
}
}
}
}
struct OffsetKeyNew: PreferenceKey{
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = nextValue()
}
}
struct HeaderBoundsKey: PreferenceKey{
static var defaultValue: Anchor<CGRect>?
static func reduce(value: inout Anchor<CGRect>?, nextValue: () -> Anchor<CGRect>?) {
value = nextValue()
}
}
enum SwipeDirection{
case up
case down
case none
}