简体   繁体   English

仅在固定标题时自定义部分标题,否则不自定义(SwiftUI)

[英]Customise Section Headers ONLY when Headers are pinned, otherwise not (SwiftUI)

My question is simple: Is there any way to customise a Section's Header ONLY when it gets pinned, but keep it as it was before if not pinned?我的问题很简单:有什么方法可以仅在固定部分的标题时自定义它,但如果没有固定,则保持原样?

I am trying to add a .shadow to a Section's Header and I don't want it to be visible all the time, but only when starting to scroll down past the Header in the parent ScrollView (when the header gets pinned).我正在尝试将 .shadow 添加到部分的标题中,并且我不希望它一直可见,但仅在开始向下滚动到父 ScrollView 中的标题时(当标题被固定时)。

I am mainly looking for a pure SwiftUI solution but I am also open to discuss other solutions.我主要是在寻找一个纯粹的 SwiftUI 解决方案,但我也愿意讨论其他解决方案。 :) :)

struct WorkoutCardView: View {
    @Binding var workout: Workout
    @State var expandWorkout: Bool = false
    
    @Environment(\.colorScheme) var colorScheme
    
    var body: some View {
        LazyVStack(alignment: .leading, pinnedViews: .sectionHeaders) {
            Section {
                if expandWorkout {
                    WCExerciseSectionView(workout: $workout)
                }
            } header: {
                WCTitleSectionView(workout: $workout)
                    .background {
                        Color(uiColor: .systemBackground)
                        Color(uiColor: .systemFill)
                    }
                    .cornerRadius(10)
                    .shadow(color: colorScheme == .light ?
                            Color.black.opacity(expandWorkout ? 0.6 : 0) :
                                Color.white.opacity(expandWorkout ? 0.6 : 0), radius: 5, x: 0, y: 2)
                    .padding(.all, 2)
            }
        }
        .padding(.all, 8)
        .background {
            RoundedRectangle(cornerRadius: 10)
                .fill(Color(uiColor: .systemFill))
        }
        .padding(.all, 8)
        .onTapGesture {
            withAnimation {
                expandWorkout.toggle()
            }
        }
    }
}

在此处查看当前结果

A possible approach is based on dynamic detection of header position relative to container coordinate space and if it is zero (ie pinned at top) then change style correspondingly.一种可能的方法是基于相对于容器坐标空间的标题位置的动态检测,如果它为零(即固定在顶部),则相应地更改样式。

Tested with Xcode 13.4 / iOS 15.5使用 Xcode 13.4 / iOS 15.5 测试

演示

Here is main part:这是主要部分:

                } header: {
                    HeaderView(value: "HEADER \(i + 1)", pinned: i == pinned)
                        .background(GeometryReader {
                            // detect current position of header
                            Color.clear.preference(key: ViewOffsetKey.self,
                                value: $0.frame(in: .named("area")).origin.y)
                        })
                }
                .onPreferenceChange(ViewOffsetKey.self) {
                    // verify if position is zero (pinned) in container coordinates
                    if $0 == 0 {
                        self.pinned = i
                    } else if self.pinned == i {
                        // clean-up if changed (might depend - for simplicity)
                        self.pinned = nil
                    }
                }
            }
        }
    }.clipped()
}.coordinateSpace(name: "area")    // << here !!

Test module on GitHub GitHub 上的测试模块

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM