Commit cae21143 by whitepixelstudios Committed by GitHub

Merge pull request #3 from CosmicMind/master

Update version
parents be45d80b 112992a8
......@@ -16,3 +16,12 @@ profile
*.moved-aside
*.playground
*.framework
Sources/Frameworks/Motion/.git*
Sources/Frameworks/Motion/.gitignore
Sources/Frameworks/Motion/.swift-version
Sources/Frameworks/Motion/CONTRIBUTING.md
Sources/Frameworks/Motion/Motion.podspec
Sources/Frameworks/Motion/Motion.xcodeproj/
Sources/Frameworks/Motion/Sources/Info.plist
Sources/Frameworks/Motion/Sources/Motion.h
Pod::Spec.new do |s|
s.name = 'Material'
s.version = '2.8.1'
s.version = '2.9.4'
s.license = 'BSD-3-Clause'
s.summary = 'Material Design library used to create beautiful applications.'
s.summary = 'A Material Design library for creating beautiful applications.'
s.homepage = 'http://materialswift.com'
s.social_media_url = 'https://www.facebook.com/cosmicmindcom'
s.authors = { 'CosmicMind, Inc.' => 'support@cosmicmind.com' }
......
......@@ -10,7 +10,7 @@
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "0F44C283-777E-4E3F-9E10-FC52C3C270CE",
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
"9CF35BC641478FBD765F7442D4034ED362261E0A" : "Material\/",
"0F3E254D46E5A5B90D1542854F510B7D145A9F31" : "Material\/Frameworks\/Motion\/"
"0F3E254D46E5A5B90D1542854F510B7D145A9F31" : "Material\/Sources\/Frameworks\/Motion\/"
},
"DVTSourceControlWorkspaceBlueprintNameKey" : "Material",
"DVTSourceControlWorkspaceBlueprintVersion" : 204,
......
......@@ -4,14 +4,20 @@
Welcome to **Material,** a Material Design library used to create beautiful applications. Material's animation system has been completely reworked to take advantage of [Motion](https://github.com/CosmicMind/Motion), a library dedicated to animations and transitions.
[![Carthage compatible](https://img.shields.io/badge/Carthage-Compatible-brightgreen.svg?style=flat)](https://github.com/Carthage/Carthage)
[![Version](https://img.shields.io/cocoapods/v/Material.svg?style=flat)](http://cocoapods.org/pods/Material)
[![License](https://img.shields.io/cocoapods/l/Material.svg?style=flat)](https://github.com/lkzhao/Material/blob/master/LICENSE?raw=true)
![Xcode 8.2+](https://img.shields.io/badge/Xcode-8.2%2B-blue.svg)
![iOS 8.0+](https://img.shields.io/badge/iOS-8.0%2B-blue.svg)
![Swift 3.0+](https://img.shields.io/badge/Swift-3.0%2B-orange.svg)
[![Donate](https://img.shields.io/badge/Donate-PayPal-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=9D6MURMLLUNQ2)
## Photos Sample
Take a look at a sample [Photos](https://github.com/CosmicMind/Samples/tree/master/Projects/Programmatic/Photos) project to get started.
![Photos](http://www.cosmicmind.com/motion/projects/photos.gif)
* [Photos Sample](https://github.com/CosmicMind/Samples/tree/master/Projects/Programmatic/Photos)
## Sample Projects
Take a look at [Sample Projects](https://github.com/CosmicMind/Samples) to get your projects started.
......@@ -27,8 +33,8 @@ Take a look at [Sample Projects](https://github.com/CosmicMind/Samples) to get y
- [x] Icons
- [x] TextField
- [X] Snackbar
- [x] TabBar
- [x] Tabs
- [x] Chips
- [X] SearchBar
- [x] NavigationController
- [x] NavigationDrawer
......@@ -150,7 +156,7 @@ A SearchBar is a powerful navigation tool that allows for user's input with an i
## Tabs
Tabs is a new component that links a customizable TabBar to a stack of view controllers making a powerful and visually pleasing component to have in any application. The TabBar can be aligned at the top or bottom of the view controller.
Tabs is a new component that links a customizable TabBar to a stack of view controllers making a powerful and visually pleasing component to have in any application.
![Tabs](http://www.cosmicmind.com/material/white/page-tab-bar-controller.gif)
......
......@@ -12,7 +12,7 @@ Take a look at a sample [Photos](https://github.com/CosmicMind/Samples/tree/mast
* [Photos Sample](https://github.com/CosmicMind/Samples/tree/master/Projects/Programmatic/Photos)
### Who is this for?
### Who is Motion for?
Motion is designed for beginner to expert developers. For beginners, you will be exposed to very powerful APIs that would take time and experience to develop on your own, and experts will appreciate the time saved by using Motion.
......
......@@ -29,18 +29,18 @@
import UIKit
public extension CAMediaTimingFunction {
// default
// Default
static let linear = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
static let easeIn = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
static let easeOut = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
static let easeInOut = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
// material
// Material
static let standard = CAMediaTimingFunction(controlPoints: 0.4, 0.0, 0.2, 1.0)
static let deceleration = CAMediaTimingFunction(controlPoints: 0.0, 0.0, 0.2, 1)
static let acceleration = CAMediaTimingFunction(controlPoints: 0.4, 0.0, 1, 1)
static let sharp = CAMediaTimingFunction(controlPoints: 0.4, 0.0, 0.6, 1)
// easing.net
// Easing.net
static let easeOutBack = CAMediaTimingFunction(controlPoints: 0.175, 0.885, 0.32, 1.75)
}
......@@ -31,7 +31,7 @@ internal struct AssociatedObject {
- Parameter initializer: Object initializer.
- Returns: The associated reference for the initializer object.
*/
public static func get<T: Any>(base: Any, key: UnsafePointer<UInt8>, initializer: () -> T) -> T {
static func get<T: Any>(base: Any, key: UnsafePointer<UInt8>, initializer: () -> T) -> T {
if let v = objc_getAssociatedObject(base, key) as? T {
return v
}
......@@ -48,7 +48,7 @@ internal struct AssociatedObject {
- Parameter value: The object instance to set for the associated object.
- Returns: The associated reference for the initializer object.
*/
public static func set<T: Any>(base: Any, key: UnsafePointer<UInt8>, value: T) {
static func set<T: Any>(base: Any, key: UnsafePointer<UInt8>, value: T) {
objc_setAssociatedObject(base, key, value, .OBJC_ASSOCIATION_RETAIN)
}
}
......@@ -305,7 +305,7 @@ internal extension Motion {
context.clean()
if isFinished && isPresenting && toOverFullScreen {
// finished presenting a overFullScreen VC
// finished presenting a overFullScreen view controller.
context.unhide(rootView: tv)
context.removeSnapshots(rootView: tv)
context.storeViewAlpha(rootView: fv)
......@@ -314,7 +314,7 @@ internal extension Motion {
fv.removeFromSuperview()
fv.addSubview(c)
} else if !isFinished && !isPresenting && fromOverFullScreen {
// cancelled dismissing a overFullScreen VC
// Cancelled dismissing a overFullScreen view controller.
context.unhide(rootView: fv)
context.removeSnapshots(rootView: fv)
context.storeViewAlpha(rootView: tv)
......@@ -328,7 +328,7 @@ internal extension Motion {
c.removeFromSuperview()
}
// move fromView & toView back from our container back to the one supplied by UIKit
// Move fromView & toView back from our container back to the one supplied by UIKit.
if (toOverFullScreen && isFinished) || (fromOverFullScreen && !isFinished) {
tc.addSubview(isFinished ? fv : tv)
}
......@@ -336,7 +336,7 @@ internal extension Motion {
tc.addSubview(isFinished ? tv : fv)
if isPresenting != isFinished, !isContainerController {
// only happens when present a .overFullScreen VC
// Only happens when present a .overFullScreen view controller.
// bug: http://openradar.appspot.com/radar?id=5320103646199808
UIApplication.shared.keyWindow!.addSubview(isPresenting ? fv : tv)
}
......@@ -418,8 +418,9 @@ fileprivate extension Motion {
}
context.loadViewAlpha(rootView: tv)
context.loadViewAlpha(rootView: fv)
v.addSubview(tv)
context.loadViewAlpha(rootView: fv)
v.addSubview(fv)
}
......
......@@ -311,7 +311,6 @@ public extension MotionContext {
let nextSiblings = siblingViews[siblingViews.index(of: pairedView)!+1..<siblingViews.count]
containerView.addSubview(pairedSnapshot)
containerView.addSubview(snapshot)
for subview in pairedView.subviews {
insertGlobalViewTree(view: subview)
......@@ -320,9 +319,6 @@ public extension MotionContext {
for sibling in nextSiblings {
insertGlobalViewTree(view: sibling)
}
} else {
containerView.addSubview(snapshot)
}
containerView.addSubview(snapshot)
......
......@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.8.1</string>
<string>2.9.4</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
......
......@@ -31,17 +31,22 @@
import UIKit
public struct Application {
/// A reference to the main UIWindow.
/// An optional reference to the main UIWindow.
public static var keyWindow: UIWindow? {
return UIApplication.shared.keyWindow
}
/// A Boolean indicating if the device is in Landscape mode.
/// An optional reference to the top most view controller.
public static var rootViewController: UIViewController? {
return keyWindow?.rootViewController
}
/// A boolean indicating if the device is in Landscape mode.
public static var isLandscape: Bool {
return UIApplication.shared.statusBarOrientation.isLandscape
}
/// A Boolean indicating if the device is in Portrait mode.
/// A boolean indicating if the device is in Portrait mode.
public static var isPortrait: Bool {
return !isLandscape
}
......
......@@ -265,6 +265,7 @@ open class Bar: View {
autoresizingMask = .flexibleWidth
interimSpacePreset = .interimSpace3
contentEdgeInsetsPreset = .square1
prepareContentView()
}
}
......
......@@ -130,19 +130,20 @@ open class BottomNavigationController: UITabBarController {
when subclassing.
*/
open func prepare() {
view.backgroundColor = .white
view.clipsToBounds = true
view.backgroundColor = .white
view.contentScaleFactor = Screen.scale
prepareTabBar()
}
}
extension BottomNavigationController {
fileprivate extension BottomNavigationController {
/// Prepares the tabBar.
fileprivate func prepareTabBar() {
func prepareTabBar() {
tabBar.isTranslucent = false
tabBar.heightPreset = .normal
tabBar.depthPreset = .depth1
tabBar.dividerColor = Color.grey.lighten3
tabBar.dividerAlignment = .top
let image = UIImage()
......
......@@ -228,7 +228,7 @@ open class Card: PulseView {
if 0 == h || nil != view as? UILabel {
(view as? UILabel)?.sizeToFit()
h = view.sizeThatFits(CGSize(width: w, height: CGFloat.greatestFiniteMagnitude)).height
h = view.sizeThatFits(CGSize(width: w, height: .greatestFiniteMagnitude)).height
}
view.width = w
......
......@@ -108,7 +108,7 @@ extension NSMutableAttributedString {
- Parameter value: Any type.
- Parameter range: A NSRange.
*/
open func addAttribute(characterAttribute: CharacterAttribute, value: Any, range: NSRange) {
open func add(characterAttribute: CharacterAttribute, value: Any, range: NSRange) {
addAttribute(CharacterAttributeToValue(attribute: characterAttribute), value: value, range: range)
}
......@@ -117,9 +117,9 @@ extension NSMutableAttributedString {
- Parameter characterAttributes: A Dictionary of CharacterAttribute type keys and Any type values.
- Parameter range: A NSRange.
*/
open func addAttributes(characterAttributes: [CharacterAttribute: Any], range: NSRange) {
open func add(characterAttributes: [CharacterAttribute: Any], range: NSRange) {
for (k, v) in characterAttributes {
addAttribute(characterAttribute: k, value: v, range: range)
add(characterAttribute: k, value: v, range: range)
}
}
......@@ -129,9 +129,9 @@ extension NSMutableAttributedString {
- Parameter value: Any type.
- Parameter range: A NSRange.
*/
open func updateAttribute(characterAttribute: CharacterAttribute, value: Any, range: NSRange) {
removeAttribute(characterAttribute: characterAttribute, range: range)
addAttribute(characterAttribute: characterAttribute, value: value, range: range)
open func update(characterAttribute: CharacterAttribute, value: Any, range: NSRange) {
remove(characterAttribute: characterAttribute, range: range)
add(characterAttribute: characterAttribute, value: value, range: range)
}
/**
......@@ -139,9 +139,9 @@ extension NSMutableAttributedString {
- Parameter characterAttributes: A Dictionary of CharacterAttribute type keys and Any type values.
- Parameter range: A NSRange.
*/
open func updateAttributes(characterAttributes: [CharacterAttribute: Any], range: NSRange) {
open func update(characterAttributes: [CharacterAttribute: Any], range: NSRange) {
for (k, v) in characterAttributes {
updateAttribute(characterAttribute: k, value: v, range: range)
update(characterAttribute: k, value: v, range: range)
}
}
......@@ -150,7 +150,7 @@ extension NSMutableAttributedString {
- Parameter characterAttribute: A CharacterAttribute.
- Parameter range: A NSRange.
*/
open func removeAttribute(characterAttribute: CharacterAttribute, range: NSRange) {
open func remove(characterAttribute: CharacterAttribute, range: NSRange) {
removeAttribute(CharacterAttributeToValue(attribute: characterAttribute), range: range)
}
......@@ -159,9 +159,9 @@ extension NSMutableAttributedString {
- Parameter characterAttributes: An Array of CharacterAttributes.
- Parameter range: A NSRange.
*/
open func removeAttributes(characterAttributes: [CharacterAttribute], range: NSRange) {
open func remove(characterAttributes: [CharacterAttribute], range: NSRange) {
for k in characterAttributes {
removeAttribute(characterAttribute: k, range: range)
remove(characterAttribute: k, range: range)
}
}
}
/*
* Copyright (C) 2015 - 2017, Daniel Dahan and CosmicMind, Inc. <http://cosmicmind.com>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of CosmicMind nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import UIKit
fileprivate var ChipItemKey: UInt8 = 0
@objc(ChipBarAlignment)
public enum ChipBarAlignment: Int {
case top
case bottom
case hidden
}
extension UIViewController {
/**
A convenience property that provides access to the ChipBarController.
This is the recommended method of accessing the ChipBarController
through child UIViewControllers.
*/
public var chipsController: ChipBarController? {
return traverseViewControllerHierarchyForClassType()
}
}
open class ChipBarController: TransitionController {
/**
A Display value to indicate whether or not to
display the rootViewController to the full view
bounds, or up to the toolbar height.
*/
open var displayStyle = DisplayStyle.partial {
didSet {
layoutSubviews()
}
}
/// The ChipBar used to switch between view controllers.
@IBInspectable
open let chipBar = ChipBar()
/// The chipBar alignment.
open var chipBarAlignment = ChipBarAlignment.bottom {
didSet {
layoutSubviews()
}
}
open override func layoutSubviews() {
super.layoutSubviews()
layoutChipBar()
layoutContainer()
layoutRootViewController()
}
open override func prepare() {
super.prepare()
prepareChipBar()
}
}
fileprivate extension ChipBarController {
/// Prepares the ChipBar.
func prepareChipBar() {
chipBar.depthPreset = .depth1
view.addSubview(chipBar)
}
}
fileprivate extension ChipBarController {
/// Layout the container.
func layoutContainer() {
chipBar.width = view.width
switch displayStyle {
case .partial:
let p = chipBar.height
let y = view.height - p
switch chipBarAlignment {
case .top:
container.y = p
container.height = y
case .bottom:
container.y = 0
container.height = y
case .hidden:
container.y = 0
container.height = view.height
}
container.width = view.width
case .full:
container.frame = view.bounds
}
}
/// Layout the chipBar.
func layoutChipBar() {
chipBar.width = view.width
switch chipBarAlignment {
case .top:
chipBar.isHidden = false
chipBar.y = 0
case .bottom:
chipBar.isHidden = false
chipBar.y = view.height - chipBar.height
case .hidden:
chipBar.isHidden = true
}
}
/// Layout the rootViewController.
func layoutRootViewController() {
rootViewController.view.frame = container.bounds
}
}
......@@ -31,13 +31,6 @@
import UIKit
open class FABButton: Button {
/**
Prepares the view instance when intialized. When subclassing,
it is recommended to override the prepare method
to initialize property values and other setup operations.
The super.prepare method should always be called immediately
when subclassing.
*/
open override func prepare() {
super.prepare()
depthPreset = .depth1
......
......@@ -43,18 +43,11 @@ extension UIViewController {
through child UIViewControllers.
*/
public var fabMenuController: FABMenuController? {
var viewController: UIViewController? = self
while nil != viewController {
if viewController is FABMenuController {
return viewController as? FABMenuController
}
viewController = viewController?.parent
}
return nil
return traverseViewControllerHierarchyForClassType()
}
}
open class FABMenuController: RootController {
open class FABMenuController: TransitionController {
/// Reference to the MenuView.
@IBInspectable
open let fabMenu = FABMenu()
......@@ -86,29 +79,42 @@ extension FABMenuController {
fileprivate func prepareFABMenu() {
fabMenu.delegate = self
fabMenu.zPosition = 1000
fabMenu.handleFABButtonCallback = handleFABButtonCallback
fabMenu.handleOpenCallback = handleOpenCallback
fabMenu.handleCloseCallback = handleCloseCallback
fabMenu.handleCompletionCallback = handleCompletionCallback
fabMenu.handleFABButtonCallback = { [weak self] in
self?.handleFABButtonCallback(button: $0)
}
fabMenu.handleOpenCallback = { [weak self] in
self?.handleOpenCallback()
}
fabMenu.handleCloseCallback = { [weak self] in
self?.handleCloseCallback()
}
fabMenu.handleCompletionCallback = { [weak self] in
self?.handleCompletionCallback(view: $0)
}
view.addSubview(fabMenu)
}
}
extension FABMenuController {
fileprivate extension FABMenuController {
/// Shows the fabMenuBacking.
fileprivate func showFabMenuBacking() {
func showFabMenuBacking() {
showFade()
showBlurView()
}
/// Hides the fabMenuBacking.
fileprivate func hideFabMenuBacking() {
func hideFabMenuBacking() {
hideFade()
hideBlurView()
}
/// Shows the blurView.
fileprivate func showBlurView() {
func showBlurView() {
guard .blur == fabMenuBacking else {
return
}
......@@ -129,7 +135,7 @@ extension FABMenuController {
}
/// Hides the blurView.
fileprivate func hideBlurView() {
func hideBlurView() {
guard .blur == fabMenuBacking else {
return
}
......@@ -143,7 +149,7 @@ extension FABMenuController {
}
/// Shows the fade.
fileprivate func showFade() {
func showFade() {
guard .fade == fabMenuBacking else {
return
}
......@@ -158,7 +164,7 @@ extension FABMenuController {
}
/// Hides the fade.
fileprivate func hideFade() {
func hideFade() {
guard .fade == fabMenuBacking else {
return
}
......@@ -173,13 +179,12 @@ extension FABMenuController {
}
}
extension FABMenuController {
fileprivate extension FABMenuController {
/**
Handler to toggle the FABMenu opened or closed.
- Parameter button: A UIButton.
*/
@objc
fileprivate func handleFABButtonCallback(button: UIButton) {
func handleFABButtonCallback(button: UIButton) {
guard fabMenu.isOpened else {
fabMenu.open(isTriggeredByUserInteraction: true)
return
......@@ -189,15 +194,13 @@ extension FABMenuController {
}
/// Handler for when the FABMenu.open function is called.
@objc
fileprivate func handleOpenCallback() {
func handleOpenCallback() {
isUserInteractionEnabled = false
showFabMenuBacking()
}
/// Handler for when the FABMenu.close function is called.
@objc
fileprivate func handleCloseCallback() {
func handleCloseCallback() {
isUserInteractionEnabled = false
hideFabMenuBacking()
}
......@@ -206,7 +209,7 @@ extension FABMenuController {
Completion handler for FABMenu open and close calls.
- Parameter view: A UIView.
*/
fileprivate func handleCompletionCallback(view: UIView) {
func handleCompletionCallback(view: UIView) {
if view == fabMenu.fabMenuItems.last {
isUserInteractionEnabled = true
}
......
......@@ -31,13 +31,6 @@
import UIKit
open class FlatButton: Button {
/**
Prepares the view instance when intialized. When subclassing,
it is recommended to override the prepare method
to initialize property values and other setup operations.
The super.prepare method should always be called immediately
when subclassing.
*/
open override func prepare() {
super.prepare()
cornerRadiusPreset = .cornerRadius1
......
......@@ -31,13 +31,6 @@
import UIKit
open class IconButton: Button {
/**
Prepares the view instance when intialized. When subclassing,
it is recommended to override the prepare method
to initialize property values and other setup operations.
The super.prepare method should always be called immediately
when subclassing.
*/
open override func prepare() {
super.prepare()
pulseAnimation = .center
......
......@@ -30,12 +30,6 @@
import UIKit
@objc(ToolbarAlignment)
public enum ToolbarAlignment: Int {
case top
case bottom
}
open class ImageCard: Card {
/**
A Display value to indicate whether or not to
......
......@@ -43,14 +43,7 @@ extension UIViewController {
through child UIViewControllers.
*/
public var navigationDrawerController: NavigationDrawerController? {
var viewController: UIViewController? = self
while nil != viewController {
if viewController is NavigationDrawerController {
return viewController as? NavigationDrawerController
}
viewController = viewController?.parent
}
return nil
return traverseViewControllerHierarchyForClassType()
}
}
......@@ -143,7 +136,7 @@ public protocol NavigationDrawerControllerDelegate {
}
@objc(NavigationDrawerController)
open class NavigationDrawerController: RootController {
open class NavigationDrawerController: TransitionController {
/**
A CGFloat property that is used internally to track
the original (x) position of the container view when panning.
......@@ -415,8 +408,8 @@ open class NavigationDrawerController: RootController {
prepare()
}
open override func transition(to viewController: UIViewController, duration: TimeInterval = 0.5, options: UIViewAnimationOptions = [], animations: (() -> Void)? = nil, completion: ((Bool) -> Void)? = nil) {
super.transition(to: viewController, duration: duration, options: options, animations: animations) { [weak self, completion = completion] (result) in
open override func transition(to viewController: UIViewController, completion: ((Bool) -> Void)? = nil) {
super.transition(to: viewController) { [weak self, completion = completion] (result) in
guard let s = self else {
return
}
......@@ -452,6 +445,8 @@ open class NavigationDrawerController: RootController {
vc.view.center = CGPoint(x: rightViewWidth / 2, y: v.bounds.height / 2)
}
}
rootViewController.view.frame = container.bounds
}
open override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
......@@ -976,7 +971,7 @@ extension NavigationDrawerController {
/// Prepares the contentViewController.
fileprivate func prepareContentViewController() {
contentViewController.view.backgroundColor = .black
prepare(viewController: contentViewController, withContainer: view)
prepare(viewController: contentViewController, in: view)
view.sendSubview(toBack: contentViewController.view)
}
......@@ -986,7 +981,7 @@ extension NavigationDrawerController {
return
}
prepare(viewController: leftViewController, withContainer: v)
prepare(viewController: leftViewController, in: v)
}
/// A method that prepares the rightViewController.
......@@ -995,7 +990,7 @@ extension NavigationDrawerController {
return
}
prepare(viewController: rightViewController, withContainer: v)
prepare(viewController: rightViewController, in: v)
}
/// A method that prepares the leftView.
......@@ -1046,6 +1041,7 @@ extension NavigationDrawerController {
leftPanGesture = UIPanGestureRecognizer(target: self, action: #selector(handleLeftViewPanGesture(recognizer:)))
leftPanGesture!.delegate = self
leftPanGesture!.cancelsTouchesInView = false
view.addGestureRecognizer(leftPanGesture!)
}
......@@ -1069,6 +1065,7 @@ extension NavigationDrawerController {
rightPanGesture = UIPanGestureRecognizer(target: self, action: #selector(handleRightViewPanGesture(recognizer:)))
rightPanGesture!.delegate = self
rightPanGesture!.cancelsTouchesInView = false
view.addGestureRecognizer(rightPanGesture!)
}
......
......@@ -84,8 +84,16 @@ public class NavigationItem: NSObject {
}
}
/// An optional reference to the NavigationBar.
public var navigationBar: NavigationBar? {
return contentView.superview?.superview as? NavigationBar
var v = contentView.superview
while nil != v {
if let navigationBar = v as? NavigationBar {
return navigationBar
}
v = v?.superview
}
return nil
}
open override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
......
......@@ -31,13 +31,6 @@
import UIKit
open class RaisedButton: Button {
/**
Prepares the view instance when intialized. When subclassing,
it is recommended to override the prepare method
to initialize property values and other setup operations.
The super.prepare method should always be called immediately
when subclassing.
*/
open override func prepare() {
super.prepare()
depthPreset = .depth1
......
......@@ -148,18 +148,11 @@ open class SearchBar: Bar {
return
}
textField.frame = contentView.bounds
layoutTextField()
layoutLeftView()
layoutClearButton()
}
/**
Prepares the view instance when intialized. When subclassing,
it is recommended to override the prepare method
to initialize property values and other setup operations.
The super.prepare method should always be called immediately
when subclassing.
*/
open override func prepare() {
super.prepare()
prepareTextField()
......@@ -168,10 +161,9 @@ open class SearchBar: Bar {
}
extension SearchBar {
/// Layout the clearButton.
open func layoutClearButton() {
let h = textField.frame.height
clearButton.frame = CGRect(x: textField.frame.width - h - 4, y: 4, width: h, height: h - 8)
/// Layout the textField.
open func layoutTextField() {
textField.frame = contentView.bounds
}
/// Layout the leftView.
......@@ -185,12 +177,18 @@ extension SearchBar {
(v as? UIImageView)?.contentMode = .scaleAspectFit
}
/// Layout the clearButton.
open func layoutClearButton() {
let h = textField.frame.height
clearButton.frame = CGRect(x: textField.frame.width - h - 4, y: 4, width: h, height: h - 8)
}
}
extension SearchBar {
fileprivate extension SearchBar {
/// Clears the textField text.
@objc
fileprivate func handleClearButton() {
func handleClearButton() {
guard nil == textField.delegate?.textFieldShouldClear || true == textField.delegate?.textFieldShouldClear?(textField) else {
return
}
......@@ -206,14 +204,14 @@ extension SearchBar {
// Live updates the search results.
@objc
fileprivate func handleEditingChanged(textField: UITextField) {
func handleEditingChanged(textField: UITextField) {
delegate?.searchBar?(searchBar: self, didChange: textField, with: textField.text)
}
}
extension SearchBar {
fileprivate extension SearchBar {
/// Prepares the textField.
fileprivate func prepareTextField() {
func prepareTextField() {
textField.contentScaleFactor = Screen.scale
textField.font = RobotoFont.regular(with: 17)
textField.backgroundColor = Color.clear
......@@ -226,7 +224,7 @@ extension SearchBar {
}
/// Prepares the clearButton.
fileprivate func prepareClearButton() {
func prepareClearButton() {
clearButton = IconButton(image: Icon.cm.close, tintColor: placeholderColor)
clearButton.contentEdgeInsets = .zero
isClearButtonAutoHandleEnabled = true
......
......@@ -30,21 +30,20 @@
import UIKit
extension UIViewController {
@objc(SearchBarAlignment)
public enum SearchBarAlignment: Int {
case top
case bottom
}
public extension UIViewController {
/**
A convenience property that provides access to the SearchBarController.
This is the recommended method of accessing the SearchBarController
through child UIViewControllers.
*/
public var searchBarController: SearchBarController? {
var viewController: UIViewController? = self
while nil != viewController {
if viewController is SearchBarController {
return viewController as? SearchBarController
}
viewController = viewController?.parent
}
return nil
var searchBarController: SearchBarController? {
return traverseViewControllerHierarchyForClassType()
}
}
......@@ -53,49 +52,71 @@ open class SearchBarController: StatusBarController {
@IBInspectable
open let searchBar = SearchBar()
/// The searchBar alignment.
open var searchBarAlignment = SearchBarAlignment.top {
didSet {
layoutSubviews()
}
}
open override func layoutSubviews() {
super.layoutSubviews()
let y = Application.shouldStatusBarBeHidden || statusBar.isHidden ? 0 : statusBar.height
searchBar.y = y
searchBar.width = view.width
switch displayStyle {
case .partial:
let h = y + searchBar.height
rootViewController.view.y = h
rootViewController.view.height = view.height - h
case .full:
rootViewController.view.frame = view.bounds
}
layoutSearchBar()
layoutContainer()
layoutRootViewController()
}
/**
Prepares the view instance when intialized. When subclassing,
it is recommended to override the prepare method
to initialize property values and other setup operations.
The super.prepare method should always be called immediately
when subclassing.
*/
open override func prepare() {
super.prepare()
displayStyle = .partial
prepareStatusBar()
prepareSearchBar()
}
}
extension SearchBarController {
/// Prepares the statusBar.
fileprivate func prepareStatusBar() {
shouldHideStatusBarOnRotation = false
}
fileprivate extension SearchBarController {
/// Prepares the searchBar.
fileprivate func prepareSearchBar() {
searchBar.depthPreset = .depth1
func prepareSearchBar() {
searchBar.zPosition = 1000
searchBar.depthPreset = .depth1
view.addSubview(searchBar)
}
}
fileprivate extension SearchBarController {
/// Layout the container.
func layoutContainer() {
switch displayStyle {
case .partial:
let p = searchBar.height
let q = statusBarOffsetAdjustment
let h = view.height - p - q
switch searchBarAlignment {
case .top:
container.y = q + p
container.height = h
case .bottom:
container.y = q
container.height = h
}
container.width = view.width
case .full:
container.frame = view.bounds
}
}
/// Layout the searchBar.
func layoutSearchBar() {
searchBar.x = 0
searchBar.y = .top == searchBarAlignment ? statusBarOffsetAdjustment : view.height - searchBar.height
searchBar.width = view.width
}
/// Layout the rootViewController.
func layoutRootViewController() {
rootViewController.view.frame = container.bounds
}
}
......@@ -78,18 +78,11 @@ extension UIViewController {
through child UIViewControllers.
*/
public var snackbarController: SnackbarController? {
var viewController: UIViewController? = self
while nil != viewController {
if viewController is SnackbarController {
return viewController as? SnackbarController
}
viewController = viewController?.parent
}
return nil
return traverseViewControllerHierarchyForClassType()
}
}
open class SnackbarController: RootController {
open class SnackbarController: TransitionController {
/// Reference to the Snackbar.
open let snackbar = Snackbar()
......
......@@ -37,18 +37,11 @@ extension UIViewController {
through child UIViewControllers.
*/
public var statusBarController: StatusBarController? {
var viewController: UIViewController? = self
while nil != viewController {
if viewController is StatusBarController {
return viewController as? StatusBarController
}
viewController = viewController?.parent
}
return nil
return traverseViewControllerHierarchyForClassType()
}
}
open class StatusBarController: RootController {
open class StatusBarController: TransitionController {
/**
A Display value to indicate whether or not to
display the rootViewController to the full view
......@@ -81,19 +74,20 @@ open class StatusBarController: RootController {
}
}
/// An adjustment based on the rules for displaying the statusBar.
open var statusBarOffsetAdjustment: CGFloat {
return Application.shouldStatusBarBeHidden || statusBar.isHidden ? 0 : statusBar.height
}
/// A boolean that indicates to hide the statusBar on rotation.
open var shouldHideStatusBarOnRotation = true
open var shouldHideStatusBarOnRotation = false
/// A reference to the statusBar.
open let statusBar = UIView()
/**
To execute in the order of the layout chain, override this
method. LayoutSubviews should be called immediately, unless you
have a certain need.
*/
open override func layoutSubviews() {
super.layoutSubviews()
if shouldHideStatusBarOnRotation {
statusBar.isHidden = Application.shouldStatusBarBeHidden
}
......@@ -103,20 +97,17 @@ open class StatusBarController: RootController {
switch displayStyle {
case .partial:
let h = statusBar.height
rootViewController.view.y = h
rootViewController.view.height = view.height - h
container.y = h
container.height = view.height - h
case .full:
rootViewController.view.frame = view.bounds
container.frame = view.bounds
}
rootViewController.view.frame = container.bounds
container.zPosition = statusBar.zPosition + (Application.shouldStatusBarBeHidden ? 1 : -1)
}
/**
Prepares the view instance when intialized. When subclassing,
it is recommended to override the prepare method
to initialize property values and other setup operations.
The super.prepare method should always be called immediately
when subclassing.
*/
open override func prepare() {
super.prepare()
prepareStatusBar()
......
......@@ -40,27 +40,27 @@ public enum TextFieldPlaceholderAnimation: Int {
public protocol TextFieldDelegate: UITextFieldDelegate {
/**
A delegation method that is executed when the textField changed.
- Parameter textField: A UITextField.
- Parameter textField: A TextField.
- Parameter didChange text: An optional String.
*/
@objc
optional func textField(textField: UITextField, didChange text: String?)
optional func textField(textField: TextField, didChange text: String?)
/**
A delegation method that is executed when the textField will clear.
- Parameter textField: A UITextField.
- Parameter textField: A TextField.
- Parameter willClear text: An optional String.
*/
@objc
optional func textField(textField: UITextField, willClear text: String?)
optional func textField(textField: TextField, willClear text: String?)
/**
A delegation method that is executed when the textField is cleared.
- Parameter textField: A UITextField.
- Parameter textField: A TextField.
- Parameter didClear text: An optional String.
*/
@objc
optional func textField(textField: UITextField, didClear text: String?)
optional func textField(textField: TextField, didClear text: String?)
}
open class TextField: UITextField {
......@@ -283,7 +283,7 @@ open class TextField: UITextField {
clearButtonMode = .never
rightViewMode = .whileEditing
rightView = clearIconButton
isClearIconButtonAutoHandled = isClearIconButtonAutoHandled ? true : false
isClearIconButtonAutoHandled = { isClearIconButtonAutoHandled }()
layoutSubviews()
}
......@@ -330,7 +330,7 @@ open class TextField: UITextField {
clearButtonMode = .never
rightViewMode = .whileEditing
rightView = visibilityIconButton
isVisibilityIconButtonAutoHandled = isVisibilityIconButtonAutoHandled ? true : false
isVisibilityIconButtonAutoHandled = { isVisibilityIconButtonAutoHandled }()
layoutSubviews()
}
......@@ -338,7 +338,7 @@ open class TextField: UITextField {
/// Enables the automatic handling of the visibilityIconButton.
@IBInspectable
open var isVisibilityIconButtonAutoHandled: Bool = true {
open var isVisibilityIconButtonAutoHandled = true {
didSet {
visibilityIconButton?.removeTarget(self, action: #selector(handleVisibilityIconButton), for: .touchUpInside)
......@@ -428,21 +428,21 @@ open class TextField: UITextField {
}
}
extension TextField {
fileprivate extension TextField {
/// Prepares the divider.
fileprivate func prepareDivider() {
func prepareDivider() {
dividerColor = dividerNormalColor
}
/// Prepares the placeholderLabel.
fileprivate func preparePlaceholderLabel() {
func preparePlaceholderLabel() {
placeholderNormalColor = Color.darkText.others
placeholderLabel.backgroundColor = .clear
addSubview(placeholderLabel)
}
/// Prepares the detailLabel.
fileprivate func prepareDetailLabel() {
func prepareDetailLabel() {
detailLabel.font = RobotoFont.regular(with: 12)
detailLabel.numberOfLines = 0
detailColor = Color.darkText.others
......@@ -450,46 +450,46 @@ extension TextField {
}
/// Prepares the leftView.
fileprivate func prepareLeftView() {
func prepareLeftView() {
leftView?.contentMode = .left
leftViewMode = .always
updateLeftViewColor()
}
/// Prepares the target handlers.
fileprivate func prepareTargetHandlers() {
func prepareTargetHandlers() {
addTarget(self, action: #selector(handleEditingDidBegin), for: .editingDidBegin)
addTarget(self, action: #selector(handleEditingChanged), for: .editingChanged)
addTarget(self, action: #selector(handleEditingDidEnd), for: .editingDidEnd)
}
/// Prepares the textAlignment.
fileprivate func prepareTextAlignment() {
func prepareTextAlignment() {
textAlignment = .rightToLeft == Application.userInterfaceLayoutDirection ? .right : .left
}
}
extension TextField {
fileprivate extension TextField {
/// Updates the leftView tint color.
fileprivate func updateLeftViewColor() {
func updateLeftViewColor() {
leftView?.tintColor = isEditing ? leftViewActiveColor : leftViewNormalColor
}
/// Updates the placeholderLabel text color.
fileprivate func updatePlaceholderLabelColor() {
func updatePlaceholderLabelColor() {
tintColor = placeholderActiveColor
placeholderLabel.textColor = isEditing ? placeholderActiveColor : placeholderNormalColor
}
/// Updates the detailLabel text color.
fileprivate func updateDetailLabelColor() {
func updateDetailLabelColor() {
detailLabel.textColor = detailColor
}
}
extension TextField {
fileprivate extension TextField {
/// Layout the placeholderLabel.
fileprivate func layoutPlaceholderLabel() {
func layoutPlaceholderLabel() {
let w = leftViewWidth + textInset
let h = 0 == height ? intrinsicContentSize.height : height
......@@ -515,7 +515,7 @@ extension TextField {
}
/// Layout the detailLabel.
fileprivate func layoutDetailLabel() {
func layoutDetailLabel() {
let c = dividerContentEdgeInsets
detailLabel.height = detailLabel.sizeThatFits(CGSize(width: width, height: .greatestFiniteMagnitude)).height
detailLabel.x = c.left
......@@ -524,12 +524,12 @@ extension TextField {
}
/// Layout the a button.
fileprivate func layoutButton(button: UIButton?) {
func layoutButton(button: UIButton?) {
button?.frame = CGRect(x: width - height, y: 0, width: height, height: height)
}
/// Layout the leftView.
fileprivate func layoutLeftView() {
func layoutLeftView() {
guard let v = leftView else {
return
}
......@@ -540,10 +540,10 @@ extension TextField {
}
}
extension TextField {
fileprivate extension TextField {
/// Handles the text editing did begin state.
@objc
fileprivate func handleEditingDidBegin() {
func handleEditingDidBegin() {
leftViewEditingBeginAnimation()
placeholderEditingDidBeginAnimation()
dividerEditingDidBeginAnimation()
......@@ -551,13 +551,13 @@ extension TextField {
// Live updates the textField text.
@objc
fileprivate func handleEditingChanged(textField: UITextField) {
func handleEditingChanged(textField: UITextField) {
(delegate as? TextFieldDelegate)?.textField?(textField: self, didChange: textField.text)
}
/// Handles the text editing did end state.
@objc
fileprivate func handleEditingDidEnd() {
func handleEditingDidEnd() {
leftViewEditingEndAnimation()
placeholderEditingDidEndAnimation()
dividerEditingDidEndAnimation()
......@@ -565,7 +565,7 @@ extension TextField {
/// Handles the clearIconButton TouchUpInside event.
@objc
fileprivate func handleClearIconButton() {
func handleClearIconButton() {
guard nil == delegate?.textFieldShouldClear || true == delegate?.textFieldShouldClear?(self) else {
return
}
......@@ -581,7 +581,7 @@ extension TextField {
/// Handles the visibilityIconButton TouchUpInside event.
@objc
fileprivate func handleVisibilityIconButton() {
func handleVisibilityIconButton() {
isSecureTextEntry = !isSecureTextEntry
if !isSecureTextEntry {
......
......@@ -135,13 +135,6 @@ open class Toolbar: Bar {
}
}
/**
Prepares the view instance when intialized. When subclassing,
it is recommended to override the prepare method
to initialize property values and other setup operations.
The super.prepare method should always be called immediately
when subclassing.
*/
open override func prepare() {
super.prepare()
contentViewAlignment = .center
......
......@@ -30,185 +30,94 @@
import UIKit
extension UIViewController {
@objc(ToolbarAlignment)
public enum ToolbarAlignment: Int {
case top
case bottom
}
public extension UIViewController {
/**
A convenience property that provides access to the ToolbarController.
This is the recommended method of accessing the ToolbarController
through child UIViewControllers.
*/
public var toolbarController: ToolbarController? {
var viewController: UIViewController? = self
while nil != viewController {
if viewController is ToolbarController {
return viewController as? ToolbarController
}
viewController = viewController?.parent
}
return nil
var toolbarController: ToolbarController? {
return traverseViewControllerHierarchyForClassType()
}
}
@objc(ToolbarControllerDelegate)
public protocol ToolbarControllerDelegate {
/// Delegation method that executes when the floatingViewController will open.
@objc
optional func toolbarControllerWillOpenFloatingViewController(toolbarController: ToolbarController)
/// Delegation method that executes when the floatingViewController will close.
@objc
optional func toolbarControllerWillCloseFloatingViewController(toolbarController: ToolbarController)
/// Delegation method that executes when the floatingViewController did open.
@objc
optional func toolbarControllerDidOpenFloatingViewController(toolbarController: ToolbarController)
/// Delegation method that executes when the floatingViewController did close.
@objc
optional func toolbarControllerDidCloseFloatingViewController(toolbarController: ToolbarController)
}
@objc(ToolbarController)
open class ToolbarController: StatusBarController {
/// Reference to the Toolbar.
@IBInspectable
open let toolbar = Toolbar()
/// Internal reference to the floatingViewController.
private var internalFloatingViewController: UIViewController?
/// Delegation handler.
open weak var delegate: ToolbarControllerDelegate?
/// A floating UIViewController.
open var floatingViewController: UIViewController? {
get {
return internalFloatingViewController
/// The toolbar alignment.
open var toolbarAlignment = ToolbarAlignment.top {
didSet {
layoutSubviews()
}
set(value) {
if let v = internalFloatingViewController {
v.view.layer.rasterizationScale = Screen.scale
v.view.layer.shouldRasterize = true
delegate?.toolbarControllerWillCloseFloatingViewController?(toolbarController: self)
internalFloatingViewController = nil
UIView.animate(withDuration: 0.5,
animations: { [weak self] in
guard let s = self else {
return
}
v.view.center.y = 2 * s.view.bounds.height
s.toolbar.alpha = 1
s.rootViewController.view.alpha = 1
}) { [weak self] _ in
guard let s = self else {
return
}
v.willMove(toParentViewController: nil)
v.view.removeFromSuperview()
v.removeFromParentViewController()
v.view.layer.shouldRasterize = false
s.isUserInteractionEnabled = true
s.toolbar.isUserInteractionEnabled = true
DispatchQueue.main.async { [weak self] in
guard let s = self else {
return
open override func layoutSubviews() {
super.layoutSubviews()
layoutToolbar()
layoutContainer()
layoutRootViewController()
}
s.delegate?.toolbarControllerDidCloseFloatingViewController?(toolbarController: s)
}
}
}
open override func prepare() {
super.prepare()
displayStyle = .partial
if let v = value {
// Add the noteViewController! to the view.
addChildViewController(v)
v.view.frame = view.bounds
v.view.center.y = 2 * view.bounds.height
v.view.isHidden = true
view.insertSubview(v.view, aboveSubview: toolbar)
v.view.layer.zPosition = 1500
v.didMove(toParentViewController: self)
v.view.isHidden = false
v.view.layer.rasterizationScale = Screen.scale
v.view.layer.shouldRasterize = true
view.layer.rasterizationScale = Screen.scale
view.layer.shouldRasterize = true
internalFloatingViewController = v
isUserInteractionEnabled = false
toolbar.isUserInteractionEnabled = false
delegate?.toolbarControllerWillOpenFloatingViewController?(toolbarController: self)
UIView.animate(withDuration: 0.5,
animations: { [weak self, v = v] in
guard let s = self else {
return
prepareToolbar()
}
}
v.view.center.y = s.view.bounds.height / 2
s.toolbar.alpha = 0.5
s.rootViewController.view.alpha = 0.5
}) { [weak self, v = v] _ in
guard let s = self else {
return
fileprivate extension ToolbarController {
/// Prepares the toolbar.
func prepareToolbar() {
toolbar.zPosition = 1000
toolbar.depthPreset = .depth1
view.addSubview(toolbar)
}
}
v.view.layer.shouldRasterize = false
s.view.layer.shouldRasterize = false
DispatchQueue.main.async { [weak self] in
guard let s = self else {
return
}
fileprivate extension ToolbarController {
/// Layout the container.
func layoutContainer() {
switch displayStyle {
case .partial:
let p = toolbar.height
let q = statusBarOffsetAdjustment
let h = view.height - p - q
s.delegate?.toolbarControllerDidOpenFloatingViewController?(toolbarController: s)
}
}
switch toolbarAlignment {
case .top:
container.y = q + p
container.height = h
case .bottom:
container.y = q
container.height = h
}
}
}
open override func layoutSubviews() {
super.layoutSubviews()
container.width = view.width
let y = Application.shouldStatusBarBeHidden || statusBar.isHidden ? 0 : statusBar.height
toolbar.y = y
toolbar.width = view.width
switch displayStyle {
case .partial:
let h = y + toolbar.height
rootViewController.view.y = h
rootViewController.view.height = view.height - h
case .full:
rootViewController.view.frame = view.bounds
container.frame = view.bounds
}
}
/**
Prepares the view instance when intialized. When subclassing,
it is recommended to override the prepare method
to initialize property values and other setup operations.
The super.prepare method should always be called immediately
when subclassing.
*/
open override func prepare() {
super.prepare()
displayStyle = .partial
prepareStatusBar()
prepareToolbar()
}
}
extension ToolbarController {
/// Prepares the statusBar.
fileprivate func prepareStatusBar() {
shouldHideStatusBarOnRotation = false
/// Layout the toolbar.
func layoutToolbar() {
toolbar.x = 0
toolbar.y = .top == toolbarAlignment ? statusBarOffsetAdjustment : view.height - toolbar.height
toolbar.width = view.width
}
/// Prepares the toolbar.
fileprivate func prepareToolbar() {
toolbar.depthPreset = .depth1
view.addSubview(toolbar)
/// Layout the rootViewController.
func layoutRootViewController() {
rootViewController.view.frame = container.bounds
}
}
......@@ -30,7 +30,40 @@
import UIKit
open class RootController: UIViewController {
internal extension UIViewController {
/**
Finds a view controller with a given type based on
the view controller subclass.
- Returns: An optional of type T.
*/
func traverseViewControllerHierarchyForClassType<T: UIViewController>() -> T? {
var v: UIViewController? = self
while nil != v {
if v is T {
return v as? T
}
v = v?.parent as? TransitionController
}
return Application.rootViewController?.traverseTransitionViewControllerHierarchyForClassType()
}
/**
Traverses the child view controllers to find the correct view controller type T.
- Returns: An optional of type T.
*/
func traverseTransitionViewControllerHierarchyForClassType<T: UIViewController>() -> T? {
if let v = self as? T {
return v
} else if let v = self as? TransitionController {
return v.rootViewController.traverseTransitionViewControllerHierarchyForClassType()
}
return nil
}
}
open class TransitionController: UIViewController {
/**
A Boolean property used to enable and disable interactivity
with the rootViewController.
......@@ -45,13 +78,20 @@ open class RootController: UIViewController {
}
}
/// A reference to the container view.
@IBInspectable
open let container = UIView()
/**
A UIViewController property that references the active
main UIViewController. To swap the rootViewController, it
is recommended to use the transitionFromRootViewController
helper method.
*/
open fileprivate(set) var rootViewController: UIViewController!
open internal(set) var rootViewController: UIViewController!
/// The transition type used during a transition.
open var motionTransitionType = MotionTransitionType.fade
/**
An initializer that initializes the object with a NSCoder object.
......@@ -93,39 +133,30 @@ open class RootController: UIViewController {
A method to swap rootViewController objects.
- Parameter toViewController: The UIViewController to swap
with the active rootViewController.
- Parameter duration: A TimeInterval that sets the
animation duration of the transition.
- Parameter options: UIViewAnimationOptions thst are used
when animating the transition from the active rootViewController
to the toViewController.
- Parameter animations: An animation block that is executed during
the transition from the active rootViewController
to the toViewController.
- Parameter completion: A completion block that is execited after
the transition animation from the active rootViewController
to the toViewController has completed.
*/
open func transition(to viewController: UIViewController, duration: TimeInterval = 0.5, options: UIViewAnimationOptions = [], animations: (() -> Void)? = nil, completion: ((Bool) -> Void)? = nil) {
rootViewController.willMove(toParentViewController: nil)
addChildViewController(viewController)
viewController.view.frame = rootViewController.view.frame
transition(from: rootViewController,
to: viewController,
duration: duration,
options: options,
animations: animations) { [weak self, viewController = viewController, completion = completion] (result) in
open func transition(to viewController: UIViewController, completion: ((Bool) -> Void)? = nil) {
guard let fvc = rootViewController else {
return
}
let tvc = viewController
tvc.view.isHidden = false
tvc.view.frame = container.bounds
tvc.motionModalTransitionType = motionTransitionType
view.isUserInteractionEnabled = false
Motion.shared.transition(from: fvc, to: tvc, in: container) { [weak self, tvc = tvc, completion = completion] (isFinished) in
guard let s = self else {
return
}
viewController.didMove(toParentViewController: s)
s.rootViewController.removeFromParentViewController()
s.rootViewController = viewController
s.rootViewController.view.clipsToBounds = true
s.rootViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
s.rootViewController.view.contentScaleFactor = Screen.scale
s.view.sendSubview(toBack: s.rootViewController.view)
completion?(result)
s.rootViewController = tvc
s.view.isUserInteractionEnabled = true
completion?(isFinished)
}
}
......@@ -147,14 +178,25 @@ open class RootController: UIViewController {
view.clipsToBounds = true
view.backgroundColor = .white
view.contentScaleFactor = Screen.scale
prepareContainer()
prepareRootViewController()
}
}
extension RootController {
internal extension TransitionController {
/// Prepares the container view.
func prepareContainer() {
container.frame = view.bounds
container.clipsToBounds = true
container.contentScaleFactor = Screen.scale
container.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(container)
}
/// A method that prepares the rootViewController.
internal func prepareRootViewController() {
prepare(viewController: rootViewController, withContainer: view)
func prepareRootViewController() {
prepare(viewController: rootViewController, in: container)
}
/**
......@@ -162,10 +204,10 @@ extension RootController {
the BarController within the passed in
container view.
- Parameter viewController: A UIViewController to add as a child.
- Parameter withContainer container: A UIView that is the parent of the
- Parameter in container: A UIView that is the parent of the
passed in controller view within the view hierarchy.
*/
internal func prepare(viewController: UIViewController?, withContainer container: UIView) {
func prepare(viewController: UIViewController?, in container: UIView) {
guard let v = viewController else {
return
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment