stevengharris / SplitView

A flexible way to split SwiftUI views with a draggable splitter
MIT License
146 stars 17 forks source link

use simultaneousGesture to drag the splitter #37

Closed bastiaanterhorst closed 4 months ago

bastiaanterhorst commented 4 months ago

I found myself wanting to capture the dragGesture in my custom splitter to tweak some styling as the splitter was being dragged. With the current implementation this is not possible since it uses .gesture() which 'eats' all events. This PR is a tiny tweak to switch to using .simultaneousGesture() which allows the splitter to also implement its own drag gestures without breaking the main splitter drag behaviour.

Here's an example splitter implementation that uses this functionality:

import SwiftUI
import SplitView

struct CustomSplitter: SplitDivider {
    @ObservedObject var hide: SideHolder
    @ObservedObject var styling: SplitStyling

    @State private var isHoveringOverSplit = false
    @State private var isHoveringOverSplitHandle = false
    @State private var isPressingOnSplitHandle = false

    var body: some View {

        ZStack {
            Color.mainContentBackground
                .frame(width: 22)
                .padding(0)
            ZStack {
                Color.mainContentBackground
                    .frame(width:22, height: 50)
                    .padding(0)
                RoundedRectangle(cornerRadius: 4.0)
                    .frame(width: isHoveringOverSplit ? 8 : 0, height: isHoveringOverSplit ? 40 : 0)
                    .foregroundColor(.dragHandle)
                    .opacity(isPressingOnSplitHandle ? 1.0 : isHoveringOverSplitHandle ? 0.75 : 0.25)
            }
            .contentShape(Rectangle())
            .onHover(perform: { hovering in
                withAnimation(.easeInOut(duration: 0.1)) {
                    isHoveringOverSplitHandle = hovering
                }
            })
            .gesture(DragGesture(minimumDistance: 0)
                .onChanged { _ in withAnimation(.easeInOut(duration: 0.1)) { isPressingOnSplitHandle = true } }
                .onEnded { _ in withAnimation(.easeInOut(duration: 0.1)) { isPressingOnSplitHandle = false } }

            )
            .simultaneousGesture(TapGesture()
                .onEnded {
                    withAnimation(.easeInOut(duration: 0.1)) {
                        hide.toggle()
                        isHoveringOverSplitHandle = false
                        isPressingOnSplitHandle = false
                    }
                    isHoveringOverSplit = false
                }
            )
        }
        .contentShape(Rectangle())
        .onHover(perform: { hovering in
            isHoveringOverSplit = hovering
        })
        .hoverCursor(NSCursor.resizeLeftRight)

    }}
stevengharris commented 4 months ago

Thanks very much for doing this. I will take a quick look and hopefully just merge.

stevengharris commented 4 months ago

Looks great, thanks again!

eduo commented 4 months ago

Would this change also enable dragging something onto a splitter with a hidden section and have it open that section to drop it there? Dragging items was not being recognized and I thought this might be it.

bastiaanterhorst commented 4 months ago

@eduo could very well be!