Skip to content

Commit 02e0faa

Browse files
committed
初步实现Custom Presentation
1 parent 8e9d9b9 commit 02e0faa

8 files changed

Lines changed: 144 additions & 58 deletions

File tree

CustomTransition/CustomTransition-Swift/CustomTransition-Swift.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
9B34A0F01C6AD7FC0085D279 /* CustomPresentationFirstViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B34A0EF1C6AD7FC0085D279 /* CustomPresentationFirstViewController.swift */; };
1111
9B34A0F21C6AD8370085D279 /* CustomPresentationSecondViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B34A0F11C6AD8370085D279 /* CustomPresentationSecondViewController.swift */; };
1212
9B34A0F41C6AD85D0085D279 /* CustomPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B34A0F31C6AD85D0085D279 /* CustomPresentationController.swift */; };
13+
9B34A1301C6B42110085D279 /* CustomPresentationAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B34A12F1C6B42110085D279 /* CustomPresentationAnimator.swift */; };
1314
9B5074F91C671E4A00C89416 /* CrossDissolveFirstViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B5074F81C671E4A00C89416 /* CrossDissolveFirstViewController.swift */; };
1415
9B5074FB1C68403000C89416 /* CrossDissolveSecondViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B5074FA1C68403000C89416 /* CrossDissolveSecondViewController.swift */; };
1516
9B5074FF1C6843CE00C89416 /* UIViewShortHand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B5074FE1C6843CE00C89416 /* UIViewShortHand.swift */; };
@@ -53,6 +54,7 @@
5354
9B34A0EF1C6AD7FC0085D279 /* CustomPresentationFirstViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomPresentationFirstViewController.swift; sourceTree = "<group>"; };
5455
9B34A0F11C6AD8370085D279 /* CustomPresentationSecondViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomPresentationSecondViewController.swift; sourceTree = "<group>"; };
5556
9B34A0F31C6AD85D0085D279 /* CustomPresentationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomPresentationController.swift; sourceTree = "<group>"; };
57+
9B34A12F1C6B42110085D279 /* CustomPresentationAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomPresentationAnimator.swift; sourceTree = "<group>"; };
5658
9B5074F81C671E4A00C89416 /* CrossDissolveFirstViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CrossDissolveFirstViewController.swift; sourceTree = "<group>"; };
5759
9B5074FA1C68403000C89416 /* CrossDissolveSecondViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CrossDissolveSecondViewController.swift; sourceTree = "<group>"; };
5860
9B5074FE1C6843CE00C89416 /* UIViewShortHand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewShortHand.swift; sourceTree = "<group>"; };
@@ -120,6 +122,7 @@
120122
9B34A0EF1C6AD7FC0085D279 /* CustomPresentationFirstViewController.swift */,
121123
9B34A0F11C6AD8370085D279 /* CustomPresentationSecondViewController.swift */,
122124
9B34A0F31C6AD85D0085D279 /* CustomPresentationController.swift */,
125+
9B34A12F1C6B42110085D279 /* CustomPresentationAnimator.swift */,
123126
);
124127
path = "Custom Presentation";
125128
sourceTree = "<group>";
@@ -408,6 +411,7 @@
408411
9B50750C1C68D95600C89416 /* InteractivitySecondViewController.swift in Sources */,
409412
9B34A0F41C6AD85D0085D279 /* CustomPresentationController.swift in Sources */,
410413
9B5075051C68982400C89416 /* CrossDissolveAnimator.swift in Sources */,
414+
9B34A1301C6B42110085D279 /* CustomPresentationAnimator.swift in Sources */,
411415
9B5CEE021C66D44E003D0D6F /* AppDelegate.swift in Sources */,
412416
9B5075071C68CBE800C89416 /* HalfWaySpringAnimator.swift in Sources */,
413417
9B50750A1C68D94400C89416 /* InteractivityFirstViewController.swift in Sources */,

CustomTransition/CustomTransition-Swift/CustomTransition-Swift/Cross Dissolve/CrossDissolveFirstViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class CrossDissolveFirstViewController: UIViewController, UIViewControllerTransi
3737

3838
/// 为了使用自定义present动画进行的一些设置
3939
crossDissolveSecondViewController.modalPresentationStyle = .FullScreen
40-
crossDissolveSecondViewController.transitioningDelegate = self;
40+
crossDissolveSecondViewController.transitioningDelegate = self
4141
}
4242
}
4343

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//
2+
// CustomPresentationAnimator.swift
3+
// CustomTransition-Swift
4+
//
5+
// Created by 张星宇 on 16/2/10.
6+
// Copyright © 2016年 zxy. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
class CustomPresentationAnimator: NSObject, UIViewControllerAnimatedTransitioning {
12+
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
13+
if let isAnimated = transitionContext?.isAnimated() {
14+
return isAnimated ? 0.35 : 0
15+
}
16+
return 0
17+
}
18+
19+
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
20+
let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)
21+
let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)
22+
let containerView = transitionContext.containerView()
23+
24+
let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)
25+
let toView = transitionContext.viewForKey(UITransitionContextToViewKey)
26+
let isPresenting = (toViewController?.presentingViewController == fromViewController)
27+
28+
var fromViewFinalFrame = transitionContext.finalFrameForViewController(fromViewController!)
29+
var toViewInitialFrame = transitionContext.initialFrameForViewController(toViewController!)
30+
let toViewFinalFrame = transitionContext.finalFrameForViewController(toViewController!)
31+
32+
if toView != nil {
33+
containerView?.addSubview(toView!)
34+
}
35+
36+
if isPresenting {
37+
toViewInitialFrame.origin = CGPointMake(CGRectGetMinX(containerView!.bounds), CGRectGetMaxY(containerView!.bounds))
38+
toViewInitialFrame.size = toViewFinalFrame.size
39+
toView?.frame = toViewInitialFrame
40+
} else {
41+
fromViewFinalFrame = CGRectOffset(fromView!.frame, 0, CGRectGetHeight(fromView!.frame))
42+
}
43+
44+
let transitionDuration = self.transitionDuration(transitionContext)
45+
UIView.animateWithDuration(transitionDuration, animations: {
46+
if isPresenting {
47+
toView?.frame = toViewFinalFrame
48+
}
49+
else {
50+
fromView?.frame = fromViewFinalFrame
51+
}
52+
53+
}) { (finished: Bool) -> Void in
54+
let wasCancelled = transitionContext.transitionWasCancelled()
55+
transitionContext.completeTransition(!wasCancelled)
56+
}
57+
}
58+
}

CustomTransition/CustomTransition-Swift/CustomTransition-Swift/Custom Presentation/CustomPresentationController.swift

Lines changed: 43 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import UIKit
1010

11-
class CustomPresentationController: UIPresentationController, UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning {
11+
class CustomPresentationController: UIPresentationController, UIViewControllerTransitioningDelegate {
1212

1313
let CORNER_RADIUS: CGFloat = 16
1414
var presentationWrappingView: UIView? = nil
@@ -20,6 +20,13 @@ class CustomPresentationController: UIPresentationController, UIViewControllerTr
2020
presentedViewController.modalPresentationStyle = .Custom
2121
}
2222

23+
override func presentedView() -> UIView? {
24+
return self.presentationWrappingView
25+
}
26+
}
27+
28+
// MARK: - 两组对应的方法,实现自定义presentation
29+
extension CustomPresentationController {
2330
override func presentationTransitionWillBegin() {
2431
let presentedViewControllerView = super.presentedView()
2532
let presentationWrapperView = UIView(frame: self.frameOfPresentedViewInContainerView())
@@ -47,7 +54,7 @@ class CustomPresentationController: UIPresentationController, UIViewControllerTr
4754
dimmingView.opaque = false
4855
dimmingView.autoresizingMask = [UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleHeight]
4956
dimmingView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: Selector("dimmingViewTapped:")))
50-
self.dimmingView = dimmingView;
57+
self.dimmingView = dimmingView
5158
self.containerView?.addSubview(dimmingView)
5259

5360
let transitionCoordinator = self.presentingViewController.transitionCoordinator()
@@ -79,58 +86,46 @@ class CustomPresentationController: UIPresentationController, UIViewControllerTr
7986
}
8087
}
8188

89+
// MARK: - UI事件处理
90+
extension CustomPresentationController {
91+
func dimmingViewTapped(sender: UITapGestureRecognizer) {
92+
self.presentingViewController.dismissViewControllerAnimated(true, completion: nil)
93+
}
94+
}
8295

96+
// MARK: - Autolayout
8397
extension CustomPresentationController {
84-
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
85-
if let isAnimated = transitionContext?.isAnimated() {
86-
return isAnimated ? 0.35 : 0
98+
override func preferredContentSizeDidChangeForChildContentContainer(container: UIContentContainer) {
99+
super.preferredContentSizeDidChangeForChildContentContainer(container)
100+
101+
if let container = container as? UIViewController where
102+
container == self.presentedViewController{
103+
self.containerView?.setNeedsLayout()
87104
}
88-
return 0
89105
}
90106

91-
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
92-
let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)
93-
let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)
94-
let containerView = transitionContext.containerView()
95-
96-
let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)
97-
let toView = transitionContext.viewForKey(UITransitionContextToViewKey)
98-
let isPresenting = (self.presentingViewController == fromViewController)
99-
100-
let fromViewInitialFrame = transitionContext.initialFrameForViewController(fromViewController!)
101-
var fromViewFinalFrame = transitionContext.finalFrameForViewController(fromViewController!)
102-
var toViewInitialFrame = transitionContext.initialFrameForViewController(toViewController!)
103-
let toViewFinalFrame = transitionContext.finalFrameForViewController(toViewController!)
104-
105-
if toView != nil {
106-
containerView?.addSubview(toView!)
107+
override func sizeForChildContentContainer(container: UIContentContainer, withParentContainerSize parentSize: CGSize) -> CGSize {
108+
if let container = container as? UIViewController where
109+
container == self.presentedViewController{
110+
return container.preferredContentSize
107111
}
108-
109-
if isPresenting {
110-
toViewInitialFrame.origin = CGPointMake(CGRectGetMinX(containerView!.bounds), CGRectGetMaxY(containerView!.bounds));
111-
toViewInitialFrame.size = toViewFinalFrame.size;
112-
toView?.frame = toViewInitialFrame;
113-
} else {
114-
// Because our presentation wraps the presented view controller's view
115-
// in an intermediate view hierarchy, it is more accurate to rely
116-
// on the current frame of fromView than fromViewInitialFrame as the
117-
// initial frame (though in this example they will be the same).
118-
fromViewFinalFrame = CGRectOffset(fromView!.frame, 0, CGRectGetHeight(fromView!.frame));
112+
else {
113+
return super.sizeForChildContentContainer(container, withParentContainerSize: parentSize)
119114
}
115+
}
120116

121-
let transitionDuration = self.transitionDuration(transitionContext)
122-
UIView.animateWithDuration(transitionDuration, animations: {
123-
if isPresenting {
124-
toView?.frame = toViewFinalFrame;
125-
}
126-
else {
127-
fromView?.frame = fromViewFinalFrame;
128-
}
129-
130-
}) { (finished: Bool) -> Void in
131-
let wasCancelled = transitionContext.transitionWasCancelled()
132-
transitionContext.completeTransition(!wasCancelled)
133-
}
117+
override func frameOfPresentedViewInContainerView() -> CGRect {
118+
let containerViewBounds = self.containerView?.bounds
119+
let presentedViewContentSize = self.sizeForChildContentContainer(self.presentedViewController, withParentContainerSize: (containerViewBounds?.size)!)
120+
let presentedViewControllerFrame = CGRectMake(containerViewBounds!.origin.x, CGRectGetMaxY(containerViewBounds!) - presentedViewContentSize.height, (containerViewBounds?.size.width)!, presentedViewContentSize.height)
121+
return presentedViewControllerFrame
122+
}
123+
124+
override func containerViewWillLayoutSubviews() {
125+
super.containerViewWillLayoutSubviews()
126+
127+
self.dimmingView?.frame = (self.containerView?.bounds)!
128+
self.presentationWrappingView?.frame = self.frameOfPresentedViewInContainerView()
134129
}
135130
}
136131

@@ -141,10 +136,10 @@ extension CustomPresentationController {
141136
}
142137

143138
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
144-
return self
139+
return CustomPresentationAnimator()
145140
}
146141

147142
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
148-
return self
143+
return CustomPresentationAnimator()
149144
}
150145
}

CustomTransition/CustomTransition-Swift/CustomTransition-Swift/Custom Presentation/CustomPresentationFirstViewController.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class CustomPresentationFirstViewController: UIViewController {
4343
}
4444
}
4545

46+
// MARK: - UI事件处理
4647
extension CustomPresentationFirstViewController {
4748
func animationButtonDidClicked() {
4849
customPresentationSecondViewController.transitioningDelegate = customPresentationController

CustomTransition/CustomTransition-Swift/CustomTransition-Swift/Custom Presentation/CustomPresentationSecondViewController.swift

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,47 @@
77
//
88

99
import UIKit
10+
import SnapKit
1011

1112
class CustomPresentationSecondViewController: UIViewController {
12-
13+
let slider = UISlider()
14+
1315
override func viewDidLoad() {
1416
super.viewDidLoad()
1517
view.backgroundColor = [254, 223, 224].color // 设置背景颜色
1618

1719
/// 创建label
18-
let label = UILabel(frame: CGRectMake(0,0,150,100))
19-
label.center = view.center
20+
let label = UILabel()
2021
label.text = "To"
2122
label.textAlignment = .Center
2223
label.font = UIFont(name: "Helvetica", size: 60)
2324
view.addSubview(label)
25+
label.snp_makeConstraints { (make) -> Void in
26+
make.centerX.equalTo(view)
27+
make.top.equalTo(view)
28+
make.height.equalTo(144)
29+
}
30+
31+
view.addSubview(slider)
32+
slider.snp_makeConstraints { (make) -> Void in
33+
make.centerX.equalTo(view)
34+
make.left.equalTo(view).offset(20)
35+
make.height.equalTo(30)
36+
}
37+
slider.addTarget(self, action: Selector("sliderValueChange:"), forControlEvents: .ValueChanged)
2438

2539
/// 创建button
26-
let button = UIButton(frame: CGRectMake(0,0,250,60))
27-
button.center = view.center
28-
button.frame.origin.y = view.frame.maxY - 100
40+
let button = UIButton()
2941
button.setTitleColor(UIColor.blueColor(), forState: .Normal)
3042
button.setTitle("Dismiss", forState: .Normal)
3143
button.addTarget(self, action: Selector("buttonDidClicked"), forControlEvents: .TouchUpInside)
3244
view.addSubview(button)
45+
button.snp_makeConstraints { (make) -> Void in
46+
make.bottom.equalTo(view).offset(-20)
47+
make.top.equalTo(slider.snp_bottom).offset(8)
48+
make.centerX.equalTo(view)
49+
make.width.equalTo(245)
50+
}
3351

3452
self.updatePreferredContentSizeWithTraitCollection(self.traitCollection)
3553
}
@@ -43,9 +61,14 @@ class CustomPresentationSecondViewController: UIViewController {
4361
extension CustomPresentationSecondViewController {
4462
func updatePreferredContentSizeWithTraitCollection(traitCollection: UITraitCollection) {
4563
self.preferredContentSize = CGSizeMake(self.view.bounds.size.width, traitCollection.verticalSizeClass == .Compact ? 270 : 420)
64+
65+
slider.maximumValue = Float(self.preferredContentSize.height)
66+
slider.minimumValue = 220
67+
slider.value = self.slider.maximumValue
4668
}
4769

4870
override func willTransitionToTraitCollection(newCollection: UITraitCollection, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
71+
super.willTransitionToTraitCollection(newCollection, withTransitionCoordinator: coordinator)
4972
self.updatePreferredContentSizeWithTraitCollection(newCollection)
5073
}
5174
}
@@ -57,4 +80,9 @@ extension CustomPresentationSecondViewController {
5780
*/
5881
self.dismissViewControllerAnimated(true, completion: nil)
5982
}
83+
84+
func sliderValueChange(sender: UISlider) {
85+
self.preferredContentSize = CGSizeMake(self.view.bounds.size.width, CGFloat(sender.value))
86+
}
87+
6088
}

CustomTransition/CustomTransition-Swift/CustomTransition-Swift/Interactivity/InteractivityFirstViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class InteractivityFirstViewController: UIViewController {
3838
view.addSubview(button)
3939

4040
/// 添加滑动交互手势
41-
interactiveTransitionRecognizer.edges = .Right;
41+
interactiveTransitionRecognizer.edges = .Right
4242
self.view.addGestureRecognizer(interactiveTransitionRecognizer)
4343
}
4444

CustomTransition/CustomTransition-Swift/CustomTransition-Swift/Interactivity/InteractivityTransitionAnimator.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,11 @@ class InteractivityTransitionAnimator: NSObject, UIViewControllerAnimatedTransit
6060

6161
UIView.animateWithDuration(self.transitionDuration(transitionContext), animations: { () -> Void in
6262
if isPresenting {
63-
toView?.frame = toFrame;
63+
toView?.frame = toFrame
6464
} else {
6565
// For a dismissal, the fromView slides off the screen.
6666
fromView?.frame = CGRectOffset(fromFrame, fromFrame.size.width * offset.dx,
67-
fromFrame.size.height * offset.dy);
67+
fromFrame.size.height * offset.dy)
6868
}
6969
}) { (finished: Bool) -> Void in
7070
let wasCanceled = transitionContext.transitionWasCancelled()

0 commit comments

Comments
 (0)