Skip to content

floatingPanelState(_:) modifier breaks panel interactivity when used with FloatingPanelControllerDelegate methods #680

@Sussia

Description

@Sussia

First of all thank you so much for providing this great package. We have been using it in our app for years now, since it is the best solution for panels. We are refactoring our app to SwiftUI and now it's time to update screens with panels. Unfortunately, I faced some issue with this package.

Description

We use floatingPanelState(_:) to programmatically control state of panel but also we use FloatingPanelControllerDelegate methods to perform some animations when panel is moving. Using both of them breaks panel interactivity.

Expected behavior

floatingPanelState(_:) and view updates on delegate methods don't break behavior of panel

Screen.Recording.2026-02-11.at.15.31.56.mov

Actual behavior

When trying to change state of a panel by swiping it moves properly and parent view updates properly

Screen.Recording.2026-02-11.at.15.29.17.mov

Steps to reproduce

MyCoordinator

final class MyCoordinator: FloatingPanelCoordinator {
    enum Event {
        case willBeginDragging
        case didEndAttracting
    }
    
    let action: (Event) -> Void
    var proxy: FloatingPanel.FloatingPanelProxy
    
    private lazy var delegate: FloatingPanelControllerDelegate? = self
    
    init(action: @escaping (Event) -> Void) {
        self.action = action
        self.proxy = .init(controller: FloatingPanelController())
    }
    
    func setupFloatingPanel<Main, Content>(mainHostingController: UIHostingController<Main>, contentHostingController: UIHostingController<Content>) where Main : View, Content : View {
        controller.delegate = delegate
        controller.set(contentViewController: contentHostingController)
        controller.addPanel(toParent: mainHostingController, animated: false)
    }
    
    func onUpdate<Representable>(context: UIViewControllerRepresentableContext<Representable>) where Representable : UIViewControllerRepresentable {
    }
}

extension MyCoordinator: FloatingPanelControllerDelegate {
    func floatingPanelWillBeginDragging(_ fpc: FloatingPanelController) {
        action(.willBeginDragging)
    }
    
    func floatingPanelDidEndAttracting(_ fpc: FloatingPanelController) {
        action(.didEndAttracting)
    }
}

ContentView

struct ContentView: View {
    @State var floatingState: FloatingPanelState? = .half
    @State var opacity: Double = 1
    
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
                .opacity(opacity)
                .animation(.easeIn(duration: 0.1), value: opacity)
            Text("Hello, world!")
            Spacer(minLength: .zero)
        }
        .floatingPanel(coordinator: MyCoordinator.self, onEvent: onEvent) { _ in
            Color.red
        }
        .floatingPanelState($floatingState) // <-- if this line is commented all works fine
    }
    
    func onEvent(_ event: MyCoordinator.Event) {
        switch event {
        case .willBeginDragging:
            DispatchQueue.main.async {
                opacity = 0
            }
        case .didEndAttracting:
            DispatchQueue.main.async {
                opacity = 1
            }
        }
    }
}

Environment

Library version

3.2.1

Installation method

Swift Package Manager

iOS version(s)

18.6

Xcode version

16.4

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions