简体   繁体   中英

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).

I am mainly looking for a pure SwiftUI solution but I am also open to discuss other solutions. :)

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

演示

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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