Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strange scrolling behavior - all content of the FloatingPanel is scrolling #633

Closed
JelliedFish opened this issue May 24, 2024 · 6 comments · Fixed by #652
Closed

Strange scrolling behavior - all content of the FloatingPanel is scrolling #633

JelliedFish opened this issue May 24, 2024 · 6 comments · Fixed by #652

Comments

@JelliedFish
Copy link

JelliedFish commented May 24, 2024

Introduction

First of all, thank you for your library - it's a huge work that deserves respect 💪🏻
I will be glad if you help me figure out the problem ❤️

📓 Description

During the migration from v1.x to v2.8.2 I've found a strange behavior.
When I scroll through the tableView, which is in the FloatingPanel's content VC, the elements not related to the tableView are scrolled too and its animation differs from the contents of the tableView.

Note

An interesting thing: if you set the absoluteInset to not to unequal to zero, then everything works fine.

Note

If you scroll the FloatingPanel when the move animation has not ended, then the same behavior. But even it breaks the solution with absoluteInset > 0.

ℹ️ Expected behavior

  • The tableView’s content (scroll view) scrolls
  • Header (not subview of the table view) doesn’t scroll

⚠️ Actual behavior

  • The tableView’s content (scroll view) scrolls
  • Header (not subview of the table view) scrolls

🧑🏻‍💻 Steps to reproduce

I've created the simple app for testing, which includes:

  1. The RootViewController.
Code of the RootViewController

class RootViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

  1. The EmbeddedViewController which stored in the RootViewController and have all constraints as zero to safeArea.
    It also stores the FloatingPanelController.
Code of the EmbeddedViewController

class EmbeddedViewController: UIViewController {

    private var floatingPanelController: TestFloatingPanelController!

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .purple

        floatingPanelController = MyFloatingPanelController()

        floatingPanelController.addPanel(toParent: self)
    }
} 

  1. The MyFloatingPanelController which implements the FloatingPanelController. With basic realization.
Code of the MyFloatingPanelController

private enum Constants {

    enum PositionInset {

        static let full: CGFloat = 0
        static let tip: CGFloat = 53
    }
}

final class MyFloatingPanelController: FloatingPanelController {

    let contentVC: PanelContentViewController

    init() {
        self.contentVC = PanelContentViewController()
        super.init(delegate: nil)
        delegate = self
        setUpPanel()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func setUpPanel() {
        contentMode = .fitToBounds
        self.set(contentViewController: contentVC)
        self.track(scrollView: contentVC.tableView)
    }
}

extension MyFloatingPanelController: FloatingPanelControllerDelegate {

    func floatingPanel(
        _ vc: FloatingPanelController,
        layoutFor newCollection: UITraitCollection
    ) -> FloatingPanelLayout {
        return MyPanelLayout()
    }
}

final class MyPanelLayout: FloatingPanelLayout {

    var position: FloatingPanelPosition {
        return .bottom
    }

    var initialState: FloatingPanelState {
        return .tip
    }

    var anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] {
        return [
            .full: FloatingPanelLayoutAnchor(
                absoluteInset: Constants.PositionInset.full,
                edge: .top,
                referenceGuide: .safeArea),
            .tip: FloatingPanelLayoutAnchor(
                absoluteInset: Constants.PositionInset.tip,
                edge: .bottom,
                referenceGuide: .safeArea)
        ]
    }
}

  1. The PanelContentViewController with basic tableView and header arranged by StackView.
Code of the PanelContentViewController

class PanelContentViewController: UIViewController {

    let tableView: UITableView = {
        let tableView = UITableView()
        tableView.backgroundColor = .yellow
        tableView.translatesAutoresizingMaskIntoConstraints = false
        return tableView
    }()

    private let headerLabel: UILabel = {
        let label = UILabel()
        label.text = "Table Header"
        label.textAlignment = .center
        label.backgroundColor = .lightGray
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    private let data = [
        "Item 1",
        "Item 2",
        "Item 3",
        "Item 4",
        "Item 5",
        "Item 6",
        "Item 7",
        "Item 8",
        "Item 9",
        "Item 10",
        "Item 11",
        "Item 12",
        "Item 12",
        "Item 12",
        "Item 12",
        "Item 12",
        "Item 12",
        "Item 12",
        "Item 12",
        "Item 12",
        "Item 12"
    ]


    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .green

        tableView.delegate = self
        tableView.dataSource = self
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")

        let stackView = UIStackView(arrangedSubviews: [headerLabel, tableView])
        stackView.axis = .vertical
        stackView.spacing = 8
        stackView.translatesAutoresizingMaskIntoConstraints = false

        view.addSubview(stackView)

        NSLayoutConstraint.activate([
            stackView.topAnchor.constraint(equalTo: view.topAnchor),
            stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            stackView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])

        headerLabel.heightAnchor.constraint(equalToConstant: 60).isActive = true
    }
}

extension PanelContentViewController: UITableViewDelegate, UITableViewDataSource {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = data[indexPath.row]
        return cell
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableView.automaticDimension
    }
}

🧑🏻‍💻 Source code

You can test this app manually:

With version 2.8.2
TestFloatingPanel.zip

With version 1.7.6
TestFloatingPanel.zip

❓How do you display panel(s)?

  • Add as child view controllers

❓ How many panels do you displays?

  • 1

Screenshots

Now (v2.8.2) Was (v1.7.6)

Fixed `grabberView` behavior

Fixed animations

🧰 Environment

🔢 Library version

⛏️ Installation methods

  • Swift Package Manager

Note

Also checked when adding locally

📱 iOS version(s)

  • iOS 15.0-17.4

💻 Xcode version(s)

  • Xcode 15.2-15.3
@scenee
Copy link
Owner

scenee commented Jun 10, 2024

Thank you for your report and comment :) I'll check this with the attached source code.

@JelliedFish
Copy link
Author

Hi ! Thank you very much for the reply 🥹
We are really looking forward it with our team 🫂

scenee added a commit that referenced this issue Jul 1, 2024
`pre > .zero` condition is not working for `FloatingPanelLayoutAnchor` with
zero or minus `absoluteInset`. In fact, the condition is not needed here.
scenee added a commit that referenced this issue Jul 2, 2024
…633)

`pre > .zero` condition is not working for `FloatingPanelLayoutAnchor` with
zero or minus `absoluteInset`. In fact, the condition is not needed here.
scenee added a commit that referenced this issue Jul 2, 2024
…633)

`pre > .zero` condition is not working for `FloatingPanelLayoutAnchor` with
zero or minus `absoluteInset`. In fact, the condition is not needed here.
scenee added a commit that referenced this issue Jul 2, 2024
…633)

`pre > .zero` condition is not working for `FloatingPanelLayoutAnchor` with
zero or minus `absoluteInset`. In fact, the condition is not needed here.
scenee added a commit that referenced this issue Jul 3, 2024
…633)

`pre > .zero` condition is not working for `FloatingPanelLayoutAnchor` with
zero or minus `absoluteInset`. In fact, the condition is not needed here.
scenee added a commit that referenced this issue Jul 3, 2024
…633)

`pre > .zero` condition is not working for `FloatingPanelLayoutAnchor` with
zero or minus `absoluteInset`. In fact, the condition is not needed here.
scenee added a commit that referenced this issue Jul 4, 2024
…633)

Removed the `pre > .zero` condition from `FloatingPanelLayoutAnchor` as it was not appropriate for zero or negative `absoluteInset` values. 

Added documentation for `shouldScrollingContentInMoving(from:to:)` to prevent similar mistakes in the future.
@scenee
Copy link
Owner

scenee commented Jul 4, 2024

@JelliedFish
Thanks to your sample projects, I could fix this issue. The fix has been merged into the master branch already. I'm going to release it in version 2.8.4.

Additionally, I found the problem in TestFloatingPanel is that the animation around .tip state is choppy. I’ve also encountered this same issue before, but it was not on the library side. This can be fixed with the following patch to change the AutoLayout priority. Thanks.

diff --git a/TestFloatingPanel/PanelContentViewController.swift b/TestFloatingPanel/PanelContentViewController.swift
index b218448..ec56cf4 100644
--- a/TestFloatingPanel/PanelContentViewController.swift
+++ b/TestFloatingPanel/PanelContentViewController.swift
@@ -73,8 +73,9 @@ class PanelContentViewController: UIViewController {
             stackView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
         ])
 
-        headerLabel.heightAnchor.constraint(equalToConstant: 60).isActive = true
-
+        let const = headerLabel.heightAnchor.constraint(equalToConstant: 60)
+        const.priority = .defaultLow
+        const.isActive = true
     }
 }

@JelliedFish
Copy link
Author

@scenee
Thank you very much for the reply ! Your decision helped a lot and fixed previous problem ! 😎

Note

Also thank u very much for helping with the "animation around .tip state" ❤️

I wanted to close the bug, but decided to wait for the updated version to be tested ⏳

However, over time, I noticed a new bug, bro ☹️
It's not as explicit as the last one and It's not so easy to reproduce. But users of our app noticed it 👀
I began to study and was able to reproduce it in the same test app.

ℹ️ Expected behavior

  • The tableView’s content (scroll view) scrolls
  • Header (not subview of the table view) doesn’t scroll

⚠️ Actual behavior

  • The tableView’s content (scroll view) scrolls
  • Header (not subview of the table view) scrolls

Important

I will be able to reproduce the error only if the number of items in the table did not exceed the screen size. But maybe it doesn't matter.

🧑🏻‍💻 Steps to reproduce

I've updated a bit the testing app from the PR description.

I've added the TopViewController. The EmbeddedViewController also stores the Floating Panel. The application has only changed by:

  1. Added extra VC
  2. All tableView objects on the screen

You can install it manually from here: TestFloatingPanel.zip

Tip

To reproduce this error, I advise you to scroll the entire Floating Panel up and when it is at the top try to scroll up again. Sometimes it goes behind the screen.

❓How do you display panel(s)?

  • Add as child view controllers

❓ How many panels do you displays?

  • 1

Screenshots

OK (v2.8.5) Not OK (v2.8.5)

Fixed `grabberView` behavior

Fixed animations

🧰 Environment

🔢 Library version

2.8.5

⛏️ Installation methods

  • Swift Package Manager

Note

Also checked when adding locally

📱 iOS version(s)

  • iOS 15.0-17.4

💻 Xcode version(s)

  • Xcode 15.2-15.4

@scenee
Copy link
Owner

scenee commented Oct 17, 2024

Thank you for your patience. I'll take a look for the new issue later.

@scenee
Copy link
Owner

scenee commented Nov 2, 2024

I've created a patch, #652 for the 2nd issue.

scenee added a commit that referenced this issue Nov 9, 2024
…ost expanded state (#652)

I decided to disallow interrupting panel interactions while bouncing over the most expanded state in order to fix the 2nd issue in #633, #633 (comment).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants