scenee / FloatingPanel

A clean and easy-to-use floating panel UI component for iOS
MIT License
5.61k stars 509 forks source link

Preserve the scroll view position while moving between states #587

Closed fawzirifai closed 1 year ago

fawzirifai commented 1 year ago

Description

In the Maps example, while changing the search panel states the scroll view moves to the top.

Expected behavior

The scroll view position should be preserved while changing states like in Apple Maps.

Actual behavior

While changing states the scroll view moves to the top.

Steps to reproduce

Move the Search panel to the full state, scroll to the bottom of the scroll view, then move the panel to the half state.

Code example that reproduces the issue I am using the code in the Maps example.

How do you display panel(s)? Added as a child view controller.

How many panels do you displays? 1

Environment

Library version 2.6.1

Installation method I am using the example included in the library.

iOS version(s) 16.4.1

Xcode version 14.3

scenee commented 1 year ago

Thanks for your report. I'm fixing this problem now.

fawzirifai commented 1 year ago

what is the status of this, please? @scenee

fawzirifai commented 1 year ago

This commit fixes the issue, why it is not merged with the main yet? @scenee https://github.com/scenee/FloatingPanel/commit/03bb3bff9b090c5cb71ad3b7bbc6a7e6d7d35479

scenee commented 1 year ago

Oh no! I had forgotten to continue working on this branch. Thank you for reminding me.

Indeed, while that commit certainly resolves the issue, I was thinking I couldn't merge it alone because the library also needs to consider other cases.

I'll review the branch again and work towards merging it.

fawzirifai commented 1 year ago

Thanks for your reply, I appreciate it.

gunnarsson commented 2 months ago

This fix broke a piece of code of mine. I wonder if anybody could help me adjust it to work well with more modern versions of FloatingPanel.

Here's what I want to achieve: If the user expands the panel to .full state and scrolls down to the bottom of the panel, and then drags the handle down to move it to .half state, the content should scroll to top. Otherwise the user has to expand the panel again, manually scroll to top, and then pull it down to .half again, which is tedious.

Here's what I used to do:

    func floatingPanelDidChangeState(_ fpc: FloatingPanelController) {
        // If the content is scrolled down, restore it to the top when the state of the panel
        // changes, to prevent an awkward state where you have to move the panel up to full
        // in order to be able to scroll the content up again
        if fpc.state == .tip || fpc.state == .half {
            DispatchQueue.main.async {
                fpc.trackedScrollView?.setContentOffset(CGPoint.zero, animated: fpc.state == .half)
            }
        }
    }

The new pinning of the scroll position immediately sets the content offset back to the original position. I can make it work by delaying the async call an arbitrary amount of time, but that feels very hacky. Given this new functionality, how can I achieve the behavior I'm after? Can I prevent the pinning, or make my contentOffset adjustment in a more suitable callback?