Skip to content

Commit

Permalink
Merge pull request #82 from kazuhiro4949/feature/overlayviewcontrller
Browse files Browse the repository at this point in the history
Add  the animation coordinator of PagingFocusView to PagingMenuView
  • Loading branch information
kazuhiro4949 authored Dec 1, 2018
2 parents e77844f + 479bd78 commit 85e87c9
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 44 deletions.
56 changes: 52 additions & 4 deletions PagingKit/PagingMenuView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,34 @@ open class PagingMenuViewCell: UIView {
public internal(set) var index: Int!
}


/// A set of methods that provides support for animations associated with a focus view transition.
/// You can use a coordinator object to perform tasks that are related to a transition but that are separate from what the animator objects are doing.
open class PagingMenuFocusViewAnimationCoordinator {
/// A frame at the start position
public let beginFrame: CGRect
/// A frame at the end position
public let endFrame: CGRect

fileprivate var animationHandler: ((PagingMenuFocusViewAnimationCoordinator) -> Void)?
fileprivate var completionHandler: ((Bool) -> Void)?

init(beginFrame: CGRect, endFrame: CGRect) {
self.beginFrame = beginFrame
self.endFrame = endFrame
}

/// Runs the specified animations at the same time as the focus view animations.
///
/// - Parameters:
/// - animation: A block containing the animations you want to perform. These animations run in the same context as the focus view animations and therefore have the same default attributes.
/// - completion: The block of code to execute after the animation finishes. You may specify nil for this
open func animateFocusView(alongside animation: @escaping (PagingMenuFocusViewAnimationCoordinator) -> Void, completion: ((Bool) -> Void)?) {
animationHandler = animation
completionHandler = completion
}
}

/// A view that focus menu corresponding to current page.
open class PagingMenuFocusView: UIView {
open var selectedIndex: Int?
Expand Down Expand Up @@ -110,6 +138,19 @@ public protocol PagingMenuViewDelegate: class {
/// - pagingMenuView: The paging menu view requesting this information.
/// - index: The index that specifies the location of the item.
func pagingMenuView(pagingMenuView: PagingMenuView, didSelectItemAt index: Int)

/// Notifies the menu view that the frame of its focus view is about to change.
///
/// - Parameters:
/// - pagingMenuView: a menu view object informing the delegate.
/// - index: end index
/// - coordinator: animator coordinator
func pagingMenuView(pagingMenuView: PagingMenuView, willAnimateFocusViewTo index: Int, with coordinator: PagingMenuFocusViewAnimationCoordinator)
}

public extension PagingMenuViewDelegate {
public func pagingMenuView(pagingMenuView: PagingMenuView, didSelectItemAt index: Int) {}
public func pagingMenuView(pagingMenuView: PagingMenuView, willAnimateFocusViewTo index: Int, with coordinator: PagingMenuFocusViewAnimationCoordinator) {}
}

/// Displays menu lists of information and supports selection and paging of the information.
Expand Down Expand Up @@ -372,11 +413,18 @@ open class PagingMenuView: UIScrollView {
focusView.selectedIndex = index
visibleCells.selectCell(with: index)

let coordinator = PagingMenuFocusViewAnimationCoordinator(beginFrame: focusView.frame, endFrame: itemFrame)
menuDelegate?.pagingMenuView(pagingMenuView: self, willAnimateFocusViewTo: index, with: coordinator)
UIView.perform(.delete, on: [], options: UIView.AnimationOptions(rawValue: 0), animations: { [weak self] in
self?.contentOffset = offset
self?.focusView.frame = itemFrame
self?.focusView.layoutIfNeeded()
}, completion:completeHandler)
guard let _self = self else { return }
_self.contentOffset = offset
_self.focusView.frame = itemFrame
_self.focusView.layoutIfNeeded()
coordinator.animationHandler?(coordinator)
}, completion: { (finished) in
coordinator.completionHandler?(finished)
completeHandler(finished)
})
}

// MARK:- Internal
Expand Down
15 changes: 15 additions & 0 deletions PagingKit/PagingMenuViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,21 @@ public protocol PagingMenuViewControllerDelegate: class {
/// - page: An page number focusing the new selected menu in menu view controller.
/// - previousPage: An page number previously focusing menu in menu view controller.
func menuViewController(viewController: PagingMenuViewController, didSelect page: Int, previousPage: Int)


/// Notifies the menu view controller that the frame of its focus view is about to change.
///
/// - Parameters:
/// - viewController: A menu view controller object informing the delegate.
/// - index: end index
/// - coordinator: animator coordinator
func menuViewController(viewController: PagingMenuViewController, willAnimateFocusViewTo index: Int, with coordinator: PagingMenuFocusViewAnimationCoordinator)
}

extension PagingMenuViewControllerDelegate {
public func menuViewController(viewController: PagingMenuViewController, focusViewDidEndTransition focusView: PagingMenuFocusView) {}

public func menuViewController(viewController: PagingMenuViewController, willAnimateFocusViewTo index: Int, with coordinator: PagingMenuFocusViewAnimationCoordinator) {}
}

/// The data source provides the paging menu view controller object with the information it needs to construct and modify the menus.
Expand Down Expand Up @@ -298,6 +309,10 @@ extension PagingMenuViewController: UIScrollViewDelegate {
// MARK:- PagingMenuViewDelegate

extension PagingMenuViewController: PagingMenuViewDelegate {
public func pagingMenuView(pagingMenuView: PagingMenuView, willAnimateFocusViewTo index: Int, with coordinator: PagingMenuFocusViewAnimationCoordinator) {
delegate?.menuViewController(viewController: self, willAnimateFocusViewTo: index, with: coordinator)
}

public func pagingMenuView(pagingMenuView: PagingMenuView, didSelectItemAt index: Int) {
guard menuView.focusView.selectedIndex != index else { return }

Expand Down
38 changes: 19 additions & 19 deletions iOS Sample/iOS Sample/OverlayMenuCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,29 @@ import PagingKit

class OverlayMenuCell: PagingMenuViewCell {
static let sizingCell = UINib(nibName: "OverlayMenuCell", bundle: nil).instantiate(withOwner: self, options: nil).first as! OverlayMenuCell

@IBOutlet weak var textLabel: UILabel!

var isHighlight: Bool = false {
didSet {
if isHighlight {
black(percent: 0)
} else {
black(percent: 1)
}
}
let maskInsets = UIEdgeInsets(top: 6, left: 8, bottom: 6, right: 8)

let textMaskView: UIView = {
let view = UIView()
view.backgroundColor = .black
return view
}()

@IBOutlet var highlightLabel: UILabel!
@IBOutlet var titleLabel: UILabel!

override func awakeFromNib() {
super.awakeFromNib()
highlightLabel.mask = textMaskView
}

func black(percent: CGFloat) {
let whiteRatio = 1 - percent
textLabel.textColor = UIColor(white: whiteRatio, alpha: 1)
override func layoutSubviews() {
super.layoutSubviews()
textMaskView.bounds = bounds.inset(by: maskInsets)
}

func highlightWithAnimation(isHighlight: Bool) {
UIView.transition(with: textLabel, duration: 0.4, options: .transitionCrossDissolve, animations: {
self.textLabel.textColor = isHighlight ? .white : .black
}, completion: { (_) in

})
func setFrame(_ menuView: PagingMenuView, maskFrame: CGRect, animated: Bool) {
textMaskView.frame = menuView.convert(maskFrame, to: highlightLabel).inset(by: maskInsets)
}
}
17 changes: 14 additions & 3 deletions iOS Sample/iOS Sample/OverlayMenuCell.xib
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12120" systemVersion="16E195" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
Expand All @@ -21,17 +21,28 @@
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rXC-N4-4ky">
<rect key="frame" x="16" y="8" width="241" height="31"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="rXC-N4-4ky" firstAttribute="top" secondItem="UfI-M3-AT8" secondAttribute="top" constant="8" id="987-XZ-nJb"/>
<constraint firstAttribute="bottom" secondItem="rXC-N4-4ky" secondAttribute="bottom" constant="8" id="Pg7-Jd-4w4"/>
<constraint firstItem="rXC-N4-4ky" firstAttribute="leading" secondItem="UfI-M3-AT8" secondAttribute="leading" constant="16" id="VWa-qv-U0l"/>
<constraint firstAttribute="trailing" secondItem="rXC-N4-4ky" secondAttribute="trailing" constant="16" id="e68-bs-8dj"/>
<constraint firstAttribute="trailing" secondItem="IQt-N5-kx9" secondAttribute="trailing" constant="16" id="uET-X1-Oe0"/>
<constraint firstAttribute="bottom" secondItem="IQt-N5-kx9" secondAttribute="bottom" constant="8" id="vKh-VV-Fr3"/>
<constraint firstItem="IQt-N5-kx9" firstAttribute="top" secondItem="UfI-M3-AT8" secondAttribute="top" constant="8" id="xEX-Z0-xha"/>
<constraint firstItem="IQt-N5-kx9" firstAttribute="leading" secondItem="UfI-M3-AT8" secondAttribute="leading" constant="16" id="yAr-vx-DeT"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="textLabel" destination="IQt-N5-kx9" id="0GA-wf-lBT"/>
<outlet property="highlightLabel" destination="rXC-N4-4ky" id="zMg-8O-9y4"/>
<outlet property="titleLabel" destination="IQt-N5-kx9" id="tym-Vc-Zsn"/>
</connections>
<point key="canvasLocation" x="145.5" y="-54.5"/>
</view>
Expand Down
41 changes: 23 additions & 18 deletions iOS Sample/iOS Sample/OverlayViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,11 @@ class OverlayViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

menuViewController?.register(nib: UINib(nibName: "OverlayMenuCell", bundle: nil), forCellWithReuseIdentifier: "identifier")
menuViewController?.registerFocusView(nib: UINib(nibName: "OverlayFocusView", bundle: nil), isBehindCell: true)
menuViewController?.reloadData(with: 0, completionHandler: { [weak self] (_) in
let cell = self?.menuViewController.currentFocusedCell as? OverlayMenuCell
cell?.isHighlight = true
menuViewController?.reloadData(with: 0, completionHandler: { [weak self, menuViewController = menuViewController!] (vc) in
let cell = self?.menuViewController.currentFocusedCell as! OverlayMenuCell
cell.setFrame(menuViewController.menuView, maskFrame: menuViewController.focusView.frame, animated: false)
})
contentViewController?.reloadData(with: 0)
}
Expand All @@ -65,20 +64,20 @@ class OverlayViewController: UIViewController {
contentViewController?.dataSource = self
}
}

}

extension OverlayViewController: PagingMenuViewControllerDataSource {
func menuViewController(viewController: PagingMenuViewController, cellForItemAt index: Int) -> PagingMenuViewCell {
let cell = viewController.dequeueReusableCell(withReuseIdentifier: "identifier", for: index) as! OverlayMenuCell
cell.textLabel.text = dataSource[index].menu
cell.isHighlight = viewController.currentFocusedIndex == index
cell.titleLabel.text = dataSource[index].menu
cell.highlightLabel.text = dataSource[index].menu
cell.setFrame(viewController.menuView, maskFrame: cell.frame, animated: false)
return cell
}


func menuViewController(viewController: PagingMenuViewController, widthForItemAt index: Int) -> CGFloat {
OverlayMenuCell.sizingCell.textLabel.text = dataSource[index].menu
OverlayMenuCell.sizingCell.titleLabel.text = dataSource[index].menu
var referenceSize = UIView.layoutFittingCompressedSize
referenceSize.height = viewController.view.bounds.height
let size = OverlayMenuCell.sizingCell.systemLayoutSizeFitting(referenceSize, withHorizontalFittingPriority: UILayoutPriority.defaultLow, verticalFittingPriority: UILayoutPriority.defaultHigh)
Expand All @@ -103,22 +102,28 @@ extension OverlayViewController: PagingContentViewControllerDataSource {

extension OverlayViewController: PagingMenuViewControllerDelegate {
func menuViewController(viewController: PagingMenuViewController, didSelect page: Int, previousPage: Int) {
viewController.visibleCells.compactMap { $0 as? OverlayMenuCell }.forEach { $0.highlightWithAnimation(isHighlight: false) }
let selectedCell = menuViewController.cellForItem(at: page) as? OverlayMenuCell
selectedCell?.highlightWithAnimation(isHighlight: true)
contentViewController?.scroll(to: page, animated: true)
}

func menuViewController(viewController: PagingMenuViewController, willAnimateFocusViewTo index: Int, with coordinator: PagingMenuFocusViewAnimationCoordinator) {
viewController.visibleCells.compactMap { $0 as? OverlayMenuCell }.forEach { cell in
cell.setFrame(viewController.menuView, maskFrame: coordinator.beginFrame, animated: true)
}

coordinator.animateFocusView(alongside: { coordinator in
viewController.visibleCells.compactMap { $0 as? OverlayMenuCell }.forEach { cell in
cell.setFrame(viewController.menuView, maskFrame: coordinator.endFrame, animated: true)
}
}, completion: nil)
}
}

extension OverlayViewController: PagingContentViewControllerDelegate {
func contentViewController(viewController: PagingContentViewController, didManualScrollOn index: Int, percent: CGFloat) {
if percent < 0.5 {
let cell = menuViewController.cellForItem(at: index) as? OverlayMenuCell
cell?.black(percent: percent * 2)
} else {
let cell = menuViewController.cellForItem(at: index + 1) as? OverlayMenuCell
cell?.black(percent: (1 - percent) * 2)
menuViewController.scroll(index: index, percent: percent, animated: false)
menuViewController.visibleCells.forEach {
let cell = $0 as! OverlayMenuCell
cell.setFrame(menuViewController.menuView, maskFrame: menuViewController.focusView.frame, animated: false)
}
menuViewController?.scroll(index: index, percent: percent, animated: false)
}
}

0 comments on commit 85e87c9

Please sign in to comment.