8000 Preference Key subviews flipped · Issue #540 · TokamakUI/Tokamak · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
Preference Key subviews flipped #540
Open
@shial4

Description

@shial4

Describe the bug
While working on the gestures, and testing difference approaches, including Preference Keys to report changes up the view tree. I've noticed that the actual view order (in HStack) is being flipped. Result can be see in the attached video

HStack {
                Rectangle()
                    .fill(Color.purple)
                    .frame(width: 100, height: 100)
                    .onTapGesture() {
                        print("🟢 1st gesture")
                    }
                    .onTapGesture() {
                        print("🟢 2nd gesture, should not be called")
                    }
                    .onTapGesture() {
                        print("🟢 3rd gesture, should not be called")
                    }
                    .simultaneousGesture(
                        TapGesture().onEnded({ _ in
                            print("🟢 simultaneousGesture gesture")
                        })
                    )
                    .onLongPressGesture {
                        print("🟢 onLongPressGesture")
                    }
                Text("Tap Parent")
            }
            .background(
                Color.gray
                    .onTapGesture() {
                        print("🩶 Background gesture")
                    }
            )
            .onTapGesture() {
                print("🔵 Parent gesture")
            }

Used code to trigger the issue


private struct GesturePreference: Equatable {
    let priority: UInt8
    let mask: GestureMask
}

private struct GesturePreferenceKey: PreferenceKey {
    static var defaultValue: [GesturePreference] = []
    
    static func reduce(value: inout [GesturePreference], nextValue: () -> [GesturePreference]) {
        value.append(contentsOf: nextValue())
    }
}

private struct GesturePreferenceModifier<G: Gesture>: ViewModifier {
    @Environment(\.isEnabled) var isEnabled
    @State var shouldEnableGestures: Bool = false
    
    let gesture: G
    let priority: UInt8
    let mask: GestureMask
    
    init(
        gesture: G,
        priority: UInt8,
        mask: GestureMask
    ) {
        self.gesture = gesture
        self.priority = priority
        self.mask = mask
    }
    
    func body(content: Content) -> some View {
        GestureView(
            gesture: gesture,
            isEnabled: isGestureEnabled,
            content: content
        )
        // ISSUE HAPPENS WITH EITHER PREFERENCE ATTACHED 
        .preference(key: GesturePreferenceKey.self, value: [
            GesturePreference(priority: priority, mask: mask)
        ])
        .onPreferenceChange(GesturePreferenceKey.self) { preferences in
            // Find the highest priority preference that matches the mask
            let highestMatchingPreference = preferences
                .filter { $0.mask.contains(mask) }
                .max { $0.priority < $1.priority }

            // Disable gestures if no matching preference is found or it's not the highest priority
            let newValue = highestMatchingPreference?.priority == priority
            if self.shouldEnableGestures != newValue {
                self.shouldEnableGestures = newValue
                print("🚀", preferences.count, self.shouldEnableGestures, String(describing: gesture.body.self))
            }
        }
    }
}

with the modifier applied like this:

modifier(GesturePreferenceModifier(gesture: gesture.body, priority: 0, mask: mask))

To Reproduce
Steps to reproduce the behavior:

  1. Create a preference key
  2. Create HStack View with modifier applied to it and its subviews
  3. change state (i.e. on tap)
  4. See error

Expected behavior
Views remain, in expected order

Screenshots

Desktop (please complete the following information):

Screen_Recording_2023-08-08_at_18.14.15.mov

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions

    0