694

GitHub - SCENEE/FloatingPanel: A easy-to-use Floating Panel UI component for iOS

 5 years ago
source link: https://github.com/SCENEE/FloatingPanel
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

README.md

FloatingPanel

FloatingPanel is a simple and easy-to-use UI component for a new interface introduced in Apple Maps, Shortcuts and Stocks app. The new interface displays the related contents and utilities in parallel as a user wants.

Maps Stocks

Maps(Landscape)

Features

  • Simple container view controller
  • Fluid animation and gesture handling
  • Scroll view tracking
  • Common UI elements: Grabber handle, Backdrop and Surface rounding corners
  • 2 or 3 anchor positions(full, half, tip)
  • Layout customization for all trait environments(i.e. Landscape orientation support)
  • Behavior customization
  • Free from common issues of Auto Layout and gesture handling

Examples are here.

Requirements

FloatingPanel is written in Swift 4.2. Compatible with iOS 10.0+

Installation

CocoaPods

FloatingPanel is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'FloatingPanel'

Carthage

For Carthage, add the following to your Cartfile:

github "scenee/FloatingPanel"

Getting Started

import UIKit
import FloatingPanel

class ViewController: UIViewController, FloatingPanelControllerDelegate {
    var fpc: FloatingPanelController!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Initialize a `FloatingPanelController` object.
        fpc = FloatingPanelController()

        // Assign self as the delegate of the controller.
        fpc.delegate = self // Optional

        // Add a content view controller.
        let contentVC = ContentViewController()
        fpc.show(contentVC, sender: nil)

        // Track a scroll view(or the siblings) in the content view controller.
        fpc.track(scrollView: contentVC.tableView)

        // Add the views managed by the `FloatingPanelController` object to self.view.
        fpc.add(toParent: self)
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        // Remove the views managed by the `FloatingPanelController` object from self.view.
        fpc.removeFromParent()
    }
    ...
}

Usage

Move a positon with an animation

Move a floating panel to the top and middle of a view while opening and closeing a search bar like Apple Maps.

    func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
        ...
        fpc.move(to: .half, animated: true)
    }

    func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
        ...
        fpc.move(to: .full, animated: true)
    }

Make your contents correspond with FloatingPanel behavior

class ViewController: UIViewController, FloatingPanelControllerDelegate {
    ...
    func floatingPanelWillBeginDragging(_ vc: FloatingPanelController) {
        if vc.position == .full {
            searchVC.searchBar.showsCancelButton = false
            searchVC.searchBar.resignFirstResponder()
        }
    }

    func floatingPanelDidEndDragging(_ vc: FloatingPanelController, withVelocity velocity: CGPoint, targetPosition: FloatingPanelPosition) {
        if targetPosition != .full {
            searchVC.hideHeader()
        }
    }
    ...
}

Support your landscape layout with a FloatingPanelLayout object

class ViewController: UIViewController, FloatingPanelControllerDelegate {
    ...
    func floatingPanel(_ vc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout? {
        return (newCollection.verticalSizeClass == .compact) ? FloatingPanelLandscapeLayout() : nil
    }
    ...
}

class FloatingPanelLandscapeLayout: FloatingPanelLayout {
    public var initialPosition: FloatingPanelPosition {
        return .tip
    }
    public var supportedPositions: [FloatingPanelPosition] {
        return [.full, .tip]
    }

    public func insetFor(position: FloatingPanelPosition) -> CGFloat? {
        switch position {
            case .full: return 16.0
            case .tip: return 69.0
            default: return nil
        }
    }

    public func prepareLayout(surfaceView: UIView, in view: UIView) -> [NSLayoutConstraint] {
        return [
            surfaceView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuid.leftAnchor, constant: 8.0),
            surfaceView.widthAnchor.constraint(equalToConstant: 291),
        ]
    }
}

Modify your floating panel's interaction with a FloatingPanelBehavior object

class ViewController: UIViewController, FloatingPanelControllerDelegate {
    ...
    func floatingPanel(_ vc: FloatingPanelController, behaviorFor newCollection: UITraitCollection) -> FloatingPanelBehavior? {
        return FloatingPanelStocksBehavior()
    }
    ...
}
...

class FloatingPanelStocksBehavior: FloatingPanelBehavior {
    var velocityThreshold: CGFloat {
        return 15.0
    }

    func interactionAnimator(to targetPosition: FloatingPanelPosition, with velocity: CGVector) -> UIViewPropertyAnimator {
        let damping = self.damping(with: velocity)
        let springTiming = UISpringTimingParameters(dampingRatio: damping, initialVelocity: velocity)
        return UIViewPropertyAnimator(duration: 0.5, timingParameters: springTiming)
    }
    ...
}

Create an additional floating panel for a detail

class ViewController: UIViewController, FloatingPanelControllerDelegate {
    var searchPanelVC: FloatingPanelController!
    var detailPanelVC: FloatingPanelController!

    override func viewDidLoad() {
        // Setup Search panel
        self.searchPanelVC = FloatingPanelController()

        let searchVC = SearchViewController()
        self.searchPanelVC.show(searchVC, sender: nil)
        self.searchPanelVC.track(scrollView: contentVC.tableView)

        self.searchPanelVC.add(toParent: self)

        // Setup Detail panel
        self.detailPanelVC = FloatingPanelController()

        let contentVC = ContentViewController()
        self.detailPanelVC.show(contentVC, sender: nil)
        self.detailPanelVC.track(scrollView: contentVC.scrollView)

        self.detailPanelVC.add(toParent: self)
    }
    ...
}

Author

Shin Yamamoto [email protected]

License

FloatingPanel is available under the MIT license. See the LICENSE file for more info.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK