From 265b805fa96b803525052b113ecd46f8e4a871c9 Mon Sep 17 00:00:00 2001 From: Shin Yamamoto Date: Thu, 20 Jun 2019 21:52:22 +0900 Subject: [PATCH 1/2] No more need FloatingPanel to conform UIScrollViewDelegate --- Framework/Sources/FloatingPanel.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework/Sources/FloatingPanel.swift b/Framework/Sources/FloatingPanel.swift index f336f43..5671639 100644 --- a/Framework/Sources/FloatingPanel.swift +++ b/Framework/Sources/FloatingPanel.swift @@ -8,7 +8,7 @@ import UIKit.UIGestureRecognizerSubclass // For Xcode 9.4.1 /// /// FloatingPanel presentation model /// -class FloatingPanel: NSObject, UIGestureRecognizerDelegate, UIScrollViewDelegate { +class FloatingPanel: NSObject, UIGestureRecognizerDelegate { // MUST be a weak reference to prevent UI freeze on the presentation modally weak var viewcontroller: FloatingPanelController! From 5c848d9bf548d4bb1fb0f4afccac400ebcfa455f Mon Sep 17 00:00:00 2001 From: Shin Yamamoto Date: Tue, 2 Jul 2019 19:07:49 +0900 Subject: [PATCH 2/2] Fix the scroll indicator lock on a contentVC reset The locking logic couldn't take care of the case where a content view controller of a FloatingPanelController object is replaced. --- Framework/Sources/FloatingPanel.swift | 13 +++--- Framework/Sources/UIExtensions.swift | 3 ++ Framework/Tests/FloatingPanelTests.swift | 51 ++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 7 deletions(-) diff --git a/Framework/Sources/FloatingPanel.swift b/Framework/Sources/FloatingPanel.swift index 5671639..53b005d 100644 --- a/Framework/Sources/FloatingPanel.swift +++ b/Framework/Sources/FloatingPanel.swift @@ -52,8 +52,6 @@ class FloatingPanel: NSObject, UIGestureRecognizerDelegate { private var scrollBouncable = false private var scrollIndictorVisible = false - private var isScrollLocked: Bool = false - // MARK: - Interface init(_ vc: FloatingPanelController, layout: FloatingPanelLayout, behavior: FloatingPanelBehavior) { @@ -118,6 +116,8 @@ class FloatingPanel: NSObject, UIGestureRecognizerDelegate { self.animator = nil if self.state == self.layoutAdapter.topMostState { self.unlockScrollView() + } else { + self.lockScrollView() } completion?() } @@ -128,6 +128,8 @@ class FloatingPanel: NSObject, UIGestureRecognizerDelegate { self.updateLayout(to: to) if self.state == self.layoutAdapter.topMostState { self.unlockScrollView() + } else { + self.lockScrollView() } completion?() } @@ -863,11 +865,10 @@ class FloatingPanel: NSObject, UIGestureRecognizerDelegate { private func lockScrollView() { guard let scrollView = scrollView else { return } - if isScrollLocked { + if scrollView.isLocked { log.debug("Already scroll locked.") return } - isScrollLocked = true scrollBouncable = scrollView.bounces scrollIndictorVisible = scrollView.showsVerticalScrollIndicator @@ -878,9 +879,7 @@ class FloatingPanel: NSObject, UIGestureRecognizerDelegate { } private func unlockScrollView() { - guard let scrollView = scrollView, isScrollLocked else { return } - - isScrollLocked = false + guard let scrollView = scrollView, scrollView.isLocked else { return } scrollView.isDirectionalLockEnabled = false scrollView.bounces = scrollBouncable diff --git a/Framework/Sources/UIExtensions.swift b/Framework/Sources/UIExtensions.swift index a33139b..991f8ef 100644 --- a/Framework/Sources/UIExtensions.swift +++ b/Framework/Sources/UIExtensions.swift @@ -107,6 +107,9 @@ extension UIScrollView { var contentOffsetZero: CGPoint { return CGPoint(x: 0.0, y: 0.0 - contentInset.top) } + var isLocked: Bool { + return !showsVerticalScrollIndicator && !bounces && isDirectionalLockEnabled + } } extension UISpringTimingParameters { diff --git a/Framework/Tests/FloatingPanelTests.swift b/Framework/Tests/FloatingPanelTests.swift index 7287a17..e9530b6 100644 --- a/Framework/Tests/FloatingPanelTests.swift +++ b/Framework/Tests/FloatingPanelTests.swift @@ -4,6 +4,7 @@ // import XCTest +@testable import FloatingPanel class FloatingPanelTests: XCTestCase { @@ -11,4 +12,54 @@ class FloatingPanelTests: XCTestCase { override func tearDown() {} + func test_scrolllock() { + let fpc = FloatingPanelController() + fpc.loadViewIfNeeded() + fpc.view.frame = CGRect(x: 0, y: 0, width: 375, height: 667) + let contentVC1 = UITableViewController(nibName: nil, bundle: nil) + XCTAssertEqual(contentVC1.tableView.showsVerticalScrollIndicator, true) + XCTAssertEqual(contentVC1.tableView.bounces, true) + + fpc.set(contentViewController: contentVC1) + fpc.track(scrollView: contentVC1.tableView) + fpc.show(animated: false, completion: nil) // half + XCTAssertEqual(fpc.position, .half) + XCTAssertEqual(contentVC1.tableView.showsVerticalScrollIndicator, false) + XCTAssertEqual(contentVC1.tableView.bounces, false) + + fpc.move(to: .full, animated: false) + XCTAssertEqual(contentVC1.tableView.showsVerticalScrollIndicator, true) + XCTAssertEqual(contentVC1.tableView.bounces, true) + + fpc.move(to: .tip, animated: false) + XCTAssertEqual(contentVC1.tableView.showsVerticalScrollIndicator, false) + XCTAssertEqual(contentVC1.tableView.bounces, false) + + let exp1 = expectation(description: "move to full with animation") + fpc.move(to: .full, animated: true) { + XCTAssertEqual(contentVC1.tableView.showsVerticalScrollIndicator, true) + XCTAssertEqual(contentVC1.tableView.bounces, true) + exp1.fulfill() + } + wait(for: [exp1], timeout: 1.0) + + let exp2 = expectation(description: "move to tip with animation") + fpc.move(to: .tip, animated: false) { + XCTAssertEqual(contentVC1.tableView.showsVerticalScrollIndicator, false) + XCTAssertEqual(contentVC1.tableView.bounces, false) + exp2.fulfill() + } + wait(for: [exp2], timeout: 1.0) + + // Reset the content vc + let contentVC2 = UITableViewController(nibName: nil, bundle: nil) + XCTAssertEqual(contentVC2.tableView.showsVerticalScrollIndicator, true) + XCTAssertEqual(contentVC2.tableView.bounces, true) + fpc.set(contentViewController: contentVC2) + fpc.track(scrollView: contentVC2.tableView) + fpc.show(animated: false, completion: nil) + XCTAssertEqual(fpc.position, .half) + XCTAssertEqual(contentVC2.tableView.showsVerticalScrollIndicator, false) + XCTAssertEqual(contentVC2.tableView.bounces, false) + } }