Skip to content
This repository has been archived by the owner on Aug 30, 2023. It is now read-only.

Commit

Permalink
Merge branch 'release-candidate' into stable
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeff Verkoeyen committed Jul 20, 2017
2 parents 423240f + 00dbc1d commit d605986
Show file tree
Hide file tree
Showing 13 changed files with 320 additions and 12 deletions.
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
# 3.1.0

This minor release resolves a build warning and introduces the ability to customize navigation
controller transitions.

## New features

- MDMTransitionNavigationControllerDelegate makes it possible to customize transitions in a
UINavigationController.

## Source changes

* [Add transition navigation controller delegate (#29)](https://github.com/material-motion/transitioning-objc/commit/c1c212030bb8ef8abc3eaaccc315e1880b1b01a1) (featherless)
* [Fix null dereference caught by the static analyzer (#30)](https://github.com/material-motion/transitioning-objc/commit/1aef0121ec4b5313ba3883a3fd3425551c19af14) (ianegordon)

## API changes

## MDMTransitionNavigationControllerDelegate

*new* class: MDMTransitionNavigationControllerDelegate.

# 3.0.1

Fixed the umbrella header name to match the library name.
Expand Down
2 changes: 1 addition & 1 deletion MotionTransitioning.podspec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Pod::Spec.new do |s|
s.name = "MotionTransitioning"
s.summary = "Light-weight API for building UIViewController transitions."
s.version = "3.0.1"
s.version = "3.1.0"
s.authors = "The Material Motion Authors"
s.license = "Apache 2.0"
s.homepage = "https://github.com/material-motion/transitioning-objc"
Expand Down
4 changes: 2 additions & 2 deletions Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
PODS:
- CatalogByConvention (2.1.1)
- MotionTransitioning (3.0.1)
- MotionTransitioning (3.1.0)

DEPENDENCIES:
- CatalogByConvention
Expand All @@ -12,7 +12,7 @@ EXTERNAL SOURCES:

SPEC CHECKSUMS:
CatalogByConvention: c3a5319de04250a7cd4649127fcfca5fe3322a43
MotionTransitioning: a8b09749a075e420a599324fdf628465e8b1b219
MotionTransitioning: 5a4188866a5b016f7181dd41c1a14f93809688ec

PODFILE CHECKSUM: db2e7ac8d9d65704a2cbffa0b77e39a574cb7248

Expand Down
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ commands:
1. [Architecture](#architecture)
2. [How to create a simple transition](#how-to-create-a-simple-transition)
3. [How to customize presentation](#how-to-customize-presentation)
4. [How to customize navigation controller transitions](#how-to-customize-navigation-controller-transitions)
### Architecture
Expand Down Expand Up @@ -248,6 +249,27 @@ extension MyPresentationController: Transition {
}
```

### How to customize navigation controller transitions

`UINavigationController` ignores the `transitioningDelegate` property on any view
controller pushed onto or popped off of the stack, instead relying on its delegate instance to
customize any transitions. This means that our `transitionController` will be
ignored by a navigation controller.

In order to customize individual push/pop transitions with the `transitionController`, you
can make use of the `TransitionNavigationControllerDelegate` singleton class. If you
assign a shared delegate to your navigation controller's delegate, your navigation controller
will honor the animation and interaction settings defined by your individual view controller's
`transitionController`.

```swift
navigationController.delegate = TransitionNavigationControllerDelegate.sharedDelegate()

// Subsequent pushes and pops will honor the pushed/popped view controller's
// transitionController settings as though the view controllers were being
// presented/dismissed.
```

## Contributing

We welcome contributions!
Expand Down
2 changes: 1 addition & 1 deletion examples/FadeExample.m
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ - (void)viewDidLoad {
}

+ (NSArray<NSString *> *)catalogBreadcrumbs {
return @[ @"1. Fade transition (objc)" ];
return @[ @"Fade transition (objc)" ];
}

@end
Expand Down
4 changes: 2 additions & 2 deletions examples/FadeExample.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
import UIKit
import MotionTransitioning

// This example demonstrates the minimal path to building a custom transition using the Material
// Motion Transitioning APIs in Swift. The essential steps have been documented below.
// This example demonstrates the minimal path to building a custom transition using the Motion
// Transitioning APIs in Swift. The essential steps have been documented below.

class FadeExampleViewController: ExampleViewController {

Expand Down
115 changes: 115 additions & 0 deletions examples/NavControllerFadeExample.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
Copyright 2017-present The Material Motion Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import UIKit
import MotionTransitioning

// This example demonstrates how to build a custom UINavigationController transition using the
// Motion Transitioning APIs in Swift. The essential steps have been documented below.

class NavControllerFadeExampleViewController: ExampleViewController {

func didTap() {
let modalViewController = ModalViewController()
modalViewController.title = "Example view controller"

// The transition controller is an associated object on all UIViewController instances that
// allows you to customize the way the view controller is presented. The primary API on the
// controller that you'll make use of is the `transition` property. Setting this property will
// dictate how the view controller is presented. For this example we've built a custom
// FadeTransition, so we'll make use of that now:
modalViewController.transitionController.transition = FadeTransition()

cachedNavDelegate = navigationController?.delegate

// In order to customize navigation controller transitions you must implement the necessary
// delegate methods. By setting the shared transition navigation controller delegate instance
// we're able to customize push/pop transitions using our transitionController.

navigationController?.delegate = TransitionNavigationControllerDelegate.sharedDelegate()

navigationController?.pushViewController(modalViewController, animated: true)
}
private var cachedNavDelegate: UINavigationControllerDelegate?

override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)

if parent == nil { // Popped off
// Restore the previous delegate, if any.
navigationController?.delegate = cachedNavDelegate

cachedNavDelegate = nil
}
}

override func viewDidLoad() {
super.viewDidLoad()

let label = UILabel(frame: view.bounds)
label.autoresizingMask = [.flexibleWidth, .flexibleHeight]
label.textColor = .white
label.textAlignment = .center
label.text = "Tap to start the transition"
view.addSubview(label)

let tap = UITapGestureRecognizer(target: self, action: #selector(didTap))
view.addGestureRecognizer(tap)
}

override func exampleInformation() -> ExampleInfo {
return .init(title: type(of: self).catalogBreadcrumbs().last!,
instructions: "Tap to present a modal transition.")
}
}

// Transitions must be NSObject types that conform to the Transition protocol.
private final class FadeTransition: NSObject, Transition {

// The sole method we're expected to implement, start is invoked each time the view controller is
// presented or dismissed.
func start(with context: TransitionContext) {
CATransaction.begin()

CATransaction.setCompletionBlock {
// Let UIKit know that the transition has come to an end.
context.transitionDidEnd()
}

let fade = CABasicAnimation(keyPath: "opacity")

fade.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)

// Define our animation assuming that we're going forward (presenting)...
fade.fromValue = 0
fade.toValue = 1

// ...and reverse it if we're going backwards (dismissing).
if context.direction == .backward {
let swap = fade.fromValue
fade.fromValue = fade.toValue
fade.toValue = swap
}

// Add the animation...
context.foreViewController.view.layer.add(fade, forKey: fade.keyPath)

// ...and ensure that our model layer reflects the final value.
context.foreViewController.view.layer.setValue(fade.toValue, forKeyPath: fade.keyPath!)

CATransaction.commit()
}
}
10 changes: 7 additions & 3 deletions examples/apps/Catalog/TableOfContents.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@
// MARK: Catalog by convention

extension FadeExampleViewController {
class func catalogBreadcrumbs() -> [String] { return ["1. Fade transition"] }
class func catalogBreadcrumbs() -> [String] { return ["Fade transition"] }
}

extension NavControllerFadeExampleViewController {
class func catalogBreadcrumbs() -> [String] { return ["Fade transition (nav controller)"] }
}

extension MenuExampleViewController {
class func catalogBreadcrumbs() -> [String] { return ["2. Menu transition"] }
class func catalogBreadcrumbs() -> [String] { return ["Menu transition"] }
}

extension CustomPresentationExampleViewController {
class func catalogBreadcrumbs() -> [String] { return ["3. Custom presentation transitions"] }
class func catalogBreadcrumbs() -> [String] { return ["Custom presentation transitions"] }
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
667A3F491DEE269400CB3A99 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 667A3F481DEE269400CB3A99 /* Assets.xcassets */; };
667A3F4C1DEE269400CB3A99 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 667A3F4A1DEE269400CB3A99 /* LaunchScreen.storyboard */; };
667A3F541DEE273000CB3A99 /* TableOfContents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 667A3F531DEE273000CB3A99 /* TableOfContents.swift */; };
66A320FC1F1E716600E2EAC3 /* NavControllerFadeExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 664CC3D91F1E6F3000B80804 /* NavControllerFadeExample.swift */; };
66BBC75E1ED37DAD0015CB9B /* FadeExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BBC75D1ED37DAD0015CB9B /* FadeExample.swift */; };
66BBC76D1ED4C8790015CB9B /* ExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BBC7691ED4C8790015CB9B /* ExampleViewController.swift */; };
66BBC76E1ED4C8790015CB9B /* ExampleViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BBC76A1ED4C8790015CB9B /* ExampleViews.swift */; };
Expand Down Expand Up @@ -56,6 +57,7 @@
6629151F1ED5E137002B9A5D /* ModalViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModalViewController.swift; sourceTree = "<group>"; };
662915211ED5F222002B9A5D /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../../../README.md; sourceTree = "<group>"; };
662915221ED64A10002B9A5D /* TransitionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransitionTests.swift; sourceTree = "<group>"; };
664CC3D91F1E6F3000B80804 /* NavControllerFadeExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavControllerFadeExample.swift; sourceTree = "<group>"; };
666FAA801D384A6B000363DA /* TransitionsCatalog.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TransitionsCatalog.app; sourceTree = BUILT_PRODUCTS_DIR; };
666FAA831D384A6B000363DA /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = Catalog/AppDelegate.swift; sourceTree = "<group>"; };
666FAA8A1D384A6B000363DA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
Expand Down Expand Up @@ -172,6 +174,7 @@
66BBC7731ED729A70015CB9B /* FadeExample.h */,
66BBC7741ED729A70015CB9B /* FadeExample.m */,
072A063A1EEE26A900B9B5FC /* MenuExample.swift */,
664CC3D91F1E6F3000B80804 /* NavControllerFadeExample.swift */,
);
name = examples;
path = ../..;
Expand Down Expand Up @@ -478,6 +481,7 @@
072A063B1EEE26A900B9B5FC /* MenuExample.swift in Sources */,
66BBC76D1ED4C8790015CB9B /* ExampleViewController.swift in Sources */,
667A3F541DEE273000CB3A99 /* TableOfContents.swift in Sources */,
66A320FC1F1E716600E2EAC3 /* NavControllerFadeExample.swift in Sources */,
66BBC7701ED4C8790015CB9B /* Layout.swift in Sources */,
6629151E1ED5E0E0002B9A5D /* CustomPresentationExample.swift in Sources */,
66BBC76E1ED4C8790015CB9B /* ExampleViews.swift in Sources */,
Expand Down
57 changes: 57 additions & 0 deletions src/MDMTransitionNavigationControllerDelegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
Copyright 2017-present The Material Motion Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#import <UIKit/UIKit.h>

/**
This class provides a singleton implementation of UINavigationControllerDelegate that makes it
possible to configure view controller transitions using each view controller's transition
controller.
This class is not meant to be instantiated directly.
The +delegate should be assigned as the delegate for any UINavigationController instance that
wishes to configure transitions using the mdm_transitionController (transitionController in Swift)
property on a view controller.
If a navigation controller already has its own delegate, then that delegate can simply forward
the two necessary methods to the +sharedInstance of this class.
*/
NS_SWIFT_NAME(TransitionNavigationControllerDelegate)
@interface MDMTransitionNavigationControllerDelegate : NSObject

/**
Use when directly invoking methods.
Only supported methods are exposed.
*/
+ (instancetype)sharedInstance;

/**
Can be set as a navigation controller's delegate.
*/
+ (id<UINavigationControllerDelegate>)sharedDelegate;

#pragma mark <UINavigationControllerDelegate> Support

- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC;
- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController;

@end
Loading

0 comments on commit d605986

Please sign in to comment.