设备支持的翻转有哪些 , 程序在设备左转再左转之后打印出的日志是程序方向不变 , 即:设备倒向 , 程序不是倒向反而还是左向;
transitioningDelegate:告诉系统我的转场动画要自定义而不是默认;
UIViewControllerAnimatedTransitioning:两个代理方法:
- (NSTimeInterval)transitionDuration:(id
和)transitionContext - (void)animateTransition:(id
)transitionContext
AppDelegate
#import "AppDelegate.h"
#import "TestViewController.h"
#import "CustomNavigationControllerDelegate.h"
@interface AppDelegate ()
{
CustomNavigationControllerDelegate *_customNavigationDelegate;
}
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
TestViewController *testVC = [[TestViewController alloc] init];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:testVC];
_customNavigationDelegate = [[CustomNavigationControllerDelegate alloc] init];
nav.delegate = _customNavigationDelegate;
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
return YES;
}
@end
TestViewController.m
#import "TestViewController.h"
#import "TestSecondViewController.h"
#import "PresentAnimation.h"
#import "DismissAnimation.h"
@interface TestViewController ()
{
UIButton *_button;
UITextField *_textField;
PresentAnimation *_presentAnimation;
DismissAnimation *_dismissAnimation;
UIButton *_pushButton;
}
@end
@implementation TestViewController
/**
* 设备支持的翻转有哪些 , 程序在设备左转再左转之后打印出的日志是程序方向不变 , 即:设备倒向 , 程序不是倒向反而还是左向;
*/
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
//默认的是:UIInterfaceOrientationMaskAllButUpsideDown , 所以在屏幕倒向的时候程序仍然是左向;
NSUInteger mask = [super supportedInterfaceOrientations];
if (mask == UIInterfaceOrientationMaskAll) {
NSLog(@"mask all");
} else if (mask == UIInterfaceOrientationMaskAllButUpsideDown) {
NSLog(@"mask all but upsidedown");
}
//支持全部方向:
return UIInterfaceOrientationMaskAll;
}
#pragma mark - 防止设备旋转的过程中状态栏消失
- (BOOL)prefersStatusBarHidden {
return NO;
}
#pragma mark - init
- (instancetype)init
{
self = [super init];
if (self) {
//UIDeviceOrientationDidChangeNotification通知:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
//UIApplicationDidChangeStatusBarOrientationNotification通知:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarOrientationChanged:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
//键盘变换通知:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
_presentAnimation = [[PresentAnimation alloc] init];
_dismissAnimation = [[DismissAnimation alloc] init];
}
return self;
}
#pragma mark - 生命周期
- (void)viewDidLoad {
[super viewDidLoad];
_button = [[UIButton alloc] init];
[_button setBackgroundColor:[UIColor orangeColor]];
_button.frame = CGRectMake(100, 100, 150, 50);
[_button setTitle:@"Present Button" forState:UIControlStateNormal];
[_button addTarget:self action:@selector(presentButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_button];
_pushButton = [[UIButton alloc] init];
[_pushButton setBackgroundColor:[UIColor orangeColor]];
_pushButton.frame = CGRectMake(100, 200, 150, 50);
[_pushButton setTitle:@"Push Button" forState:UIControlStateNormal];
[_pushButton addTarget:self action:@selector(pushButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_pushButton];
_textField = [[UITextField alloc] init];
_textField.backgroundColor = [UIColor lightGrayColor];
[_textField setText:@"text"];
_textField.frame = CGRectMake(100, 300, 200, 30);
[self.view addSubview:_textField];
}
#pragma mark - PUSH & POP 视图
- (void)pushButtonClick:(id)sender {
//initWithFromPush:方法:
TestSecondViewController *testSecondVC = [[TestSecondViewController alloc] initWithFromPush:YES];
[self.navigationController pushViewController:testSecondVC animated:YES];
}
#pragma mark - 模态视图
- (void)presentButtonClick:(id)sender {
TestSecondViewController *modalVC = [[TestSecondViewController alloc] init];
modalVC.delegate = self;
//三要素:
//1.告诉系统我的转场动画要自定义而不是默认:
modalVC.transitioningDelegate = self;
//这个style控制着模态视图跳转到新视图后原来视图的内容是否保留的操作:默认 UIModalPresentationFullScreen 不保留 , 在这里选择 UIModalPresentationCustom 可以保留:
modalVC.modalPresentationStyle = UIModalPresentationCustom;
[self presentViewController:modalVC animated:YES completion:nil];
}
#pragma mark -
- (void)testSecondViewControllerDidDismiss:(TestSecondViewController *)testSecondViewController {
[self dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark -
//自定义转场代理方法:
- (id)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
{
//因为返回值是 id 所以我要创建object对象去实现 UIViewControllerAnimatedTransitioning 即可!
if ([presented isKindOfClass:[TestSecondViewController class]]) {
return _presentAnimation;
}
return nil;
}
- (id)animationControllerForDismissedController:(UIViewController *)dismissed
{
if ([dismissed isKindOfClass:[TestViewController class]]) {
return _dismissAnimation;
}
return nil;
}
#pragma mark -
- (void)deviceOrientationChanged:(NSNotification *)noti {
NSLog(@"#1 receive device orientation changed notification");
NSLog(@"%@", [self descriptionForDeviceOrientation:[UIDevice currentDevice].orientation]);
NSLog(@"********************************************************************");
NSLog(@"%@", [self descriptionForInterfaceOrientation:[UIApplication sharedApplication].statusBarOrientation]);
}
- (NSString *)descriptionForDeviceOrientation:(UIDeviceOrientation)deviceOrientation {
switch (deviceOrientation) {
case UIDeviceOrientationLandscapeLeft:
return @"设备左向";
break;
case UIDeviceOrientationLandscapeRight:
return @"设备右向";
break;
case UIDeviceOrientationPortraitUpsideDown:
return @"设备倒向";
break;
case UIDeviceOrientationPortrait:
return @"设备正向";
break;
default:
break;
}
return @"其他方向";
}
- (NSString *)descriptionForInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
switch (interfaceOrientation) {
case UIInterfaceOrientationLandscapeLeft:
return @"程序左向";
break;
case UIInterfaceOrientationLandscapeRight:
return @"程序右向";
break;
case UIInterfaceOrientationPortraitUpsideDown:
return @"程序倒向";
break;
case UIInterfaceOrientationPortrait:
return @"程序正向";
break;
default:
break;
}
return @"其他方向";
}
#pragma mark -
- (void)statusBarOrientationChanged:(NSNotification *)noti {
NSLog(@"#2 receive interface orientation change");
NSLog(@"%@", [self descriptionForDeviceOrientation:[UIDevice currentDevice].orientation]);
NSLog(@"%@", [self descriptionForInterfaceOrientation:[UIApplication sharedApplication].statusBarOrientation]);
}
/**
* 横屏 UI 布局 与 竖屏的 UI 布局不同,如何来做?!
* 在屏幕发生旋转的时候重新进行layout布局即可! , 调用 viewWillTransitionToSize:方法;
*/
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator {
[coordinator animateAlongsideTransition:^(id _Nonnull context) {
//正在旋转中...
} completion:^(id _Nonnull context) {
//旋转完成!
NSLog(@"screen bounds = %@" , NSStringFromCGRect([UIScreen mainScreen].bounds));
}];
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
}
//屏幕旋转的过渡动画不够流畅 , 此时应该把 MainInterface 中的内 Main 删除即可!
- (void)viewDidLayoutSubviews {
if (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation)) {
_button.frame = CGRectMake(100, 100, 150, 50);
_pushButton.frame = CGRectMake(100, 200, 150, 50);
_textField.frame = CGRectMake(100, 300, 200, 30);
} else {
_button.frame = CGRectMake(100, 100, 150, 50);
_pushButton.frame = CGRectMake(100, 200, 150, 50);
_textField.frame = CGRectMake(300, 100, 200, 30);
}
}
#pragma mark - 键盘变换通知
- (void)keyboardDidShow:(NSNotification *)noti {
//NSLog(@"keyboard show, user info %@", notification.userInfo);
NSLog(@"keyboard show user info %@" , noti.userInfo);
}
/**
* 强制横屏方法用transform:view.transform = CGAffineTransformMakeRotation(M_PI_2);
* 但是用transform方法旋转的话需要进行隐藏statusBar操作 , 因为statusBar不会根据屏幕跟随旋转!
* UIDevice.orientation方法:
* NSNumber *number = [NSNumber numberWithInteger:UIDeviceOrientationPortrait];
[[UIDevice currentDevice] setValue:value forKey:@"orientation"];
*/
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
@end
TestSecondViewController.h
#import
@class TestSecondViewController;
@protocol TestSecondViewControllerDelegate
- (void)testSecondViewControllerDidDismiss:(TestSecondViewController *)testSecondViewController;
@end
@interface TestSecondViewController : UIViewController
@property (nonatomic, weak) id delegate;
- (instancetype)initWithFromPush:(BOOL)fromPush;
@end
TestSecondViewController.m
#import "TestSecondViewController.h"
@interface TestSecondViewController ()
{
UIButton *_button;
BOOL _fromPush;
}
@end
@implementation TestSecondViewController
#pragma mark - init
- (instancetype)initWithFromPush:(BOOL)fromPush {
self = [super init];
if (self) {
//在构造方法里记录一下,传进来的这个布尔值:
_fromPush = fromPush;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor lightGrayColor];
_button = [[UIButton alloc] init];
_button.backgroundColor = [UIColor redColor];
_button.frame = CGRectMake(100, 100, 150, 50);
if (_fromPush) {
[_button setTitle:@"Pop" forState:UIControlStateNormal];
} else {
[_button setTitle:@"Dismiss" forState:UIControlStateNormal];
}
[_button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_button];
}
#pragma mark - 按钮点击事件
- (void)buttonClicked:(id)sender {
if (_fromPush) {
[self.navigationController popViewControllerAnimated:YES];
} else {
if (_delegate && [_delegate respondsToSelector:@selector(testSecondViewControllerDidDismiss:)]) {
[_delegate testSecondViewControllerDidDismiss:self];
}
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
@end
PresentAnimation.h
#import
#import
@interface PresentAnimation : NSObject
@end
PresentAnimation.m
#import "PresentAnimation.h"
@implementation PresentAnimation
#pragma mark -
/**
* 动画时长:
*/
- (NSTimeInterval)transitionDuration:(nullable id )transitionContext
{
return 1.0f;
}
/**
* 动画效果:
*/
- (void)animateTransition:(id )transitionContext
{
//viewControllerKey:
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
//viewKey:
UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];
UIView *containerView = [transitionContext containerView];
[containerView addSubview:toView];
CGRect targetFrame = [transitionContext finalFrameForViewController:toVC];
//偏移量的操作:
//targetFrame = CGRectOffset(targetFrame, 0, 500);
toView.frame = CGRectOffset(targetFrame, 0, -targetFrame.size.height);
NSTimeInterval duration = [self transitionDuration:transitionContext];
[UIView animateWithDuration:duration delay:0 usingSpringWithDamping:0.6 initialSpringVelocity:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
toView.frame = targetFrame;
} completion:^(BOOL finished) {
//过场动画完成:
[transitionContext completeTransition:YES];
}];
}
@end
DismissAnimation.h
#import
#import
@interface DismissAnimation : NSObject
@end
DismissAnimation.m
#import "DismissAnimation.h"
@implementation DismissAnimation
- (NSTimeInterval)transitionDuration:(id)transitionContext
{
return 1;
}
- (void)animateTransition:(id)transitionContext
{
UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIView *fromView = [transitionContext viewForKey:UITransitionContextFromViewKey];
UIView *containerView = [transitionContext containerView];
[containerView addSubview:toView];
[containerView sendSubviewToBack:toView];
CGRect initFrame = [transitionContext initialFrameForViewController:fromVC];
CGRect targetFrame = CGRectOffset(initFrame, 0, - initFrame.size.height);
NSTimeInterval duration = [self transitionDuration:transitionContext];
[UIView animateWithDuration:duration animations:^{
fromView.frame = targetFrame;
} completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
}
@end
CustomNavigationControllerDelegate.h
#import
#import
@interface CustomNavigationControllerDelegate : NSObject
@property (nonatomic, weak) UINavigationController *navigationController;
@end
CustomNavigationControllerDelegate.m
#import "CustomNavigationControllerDelegate.h"
#import "TransformAnimation.h"
#import "PresentAnimation.h"
@interface CustomNavigationControllerDelegate ()
{
UIPercentDrivenInteractiveTransition *_innerPercentTransition;
BOOL _underInteracting;
}
@end
@implementation CustomNavigationControllerDelegate
- (nullable id )navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC NS_AVAILABLE_IOS(7_0)
{
if (operation == UINavigationControllerOperationPop)
{
return [[TransformAnimation alloc] init];
} else if (UINavigationControllerOperationPush)
{
return [[PresentAnimation alloc] init];
}
return nil;
}
#pragma mark - 交互式转场
- (nullable id )navigationController:(UINavigationController *)navigationController
interactionControllerForAnimationController:(id ) animationController
{
if (_underInteracting)
{
return _innerPercentTransition;
}
return nil;
}
//setter方法:
- (void)setNavigationController:(UINavigationController *)navigationController
{
_navigationController = navigationController;
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
[_navigationController.view addGestureRecognizer:panGesture];
}
#pragma mark - 手势
- (void)pan:(id)sender
{
if ([sender isKindOfClass:[UIPanGestureRecognizer class]])
{
UIPanGestureRecognizer *panGesture = sender;
switch (panGesture.state) {
case UIGestureRecognizerStateBegan:
{
_underInteracting = YES;
_innerPercentTransition = [[UIPercentDrivenInteractiveTransition alloc] init];
if ([_navigationController.viewControllers count] > 1)
{
[_navigationController popViewControllerAnimated:YES];
}
break;
}
case UIGestureRecognizerStateChanged:
{
CGPoint translationPoint = [panGesture translationInView:_navigationController.view];
CGFloat progress = translationPoint.x / CGRectGetWidth(_navigationController.view.bounds);
[_innerPercentTransition updateInteractiveTransition:progress];
break;
}
case UIGestureRecognizerStateEnded:
{
_underInteracting = NO;
if ([panGesture velocityInView:_navigationController.view].x > 0) {
[_innerPercentTransition finishInteractiveTransition];
}
else
{
[_innerPercentTransition cancelInteractiveTransition];
}
_innerPercentTransition = nil;
break;
}
default:
[_innerPercentTransition cancelInteractiveTransition];
_innerPercentTransition = nil;
break;
}
}
}
@end
TransformAnimation.h
#import
#import
@interface TransformAnimation : NSObject
@end
TransformAnimation.m
#import "TransformAnimation.h"
@implementation TransformAnimation
- (NSTimeInterval)transitionDuration:(nullable id )transitionContext
{
return 1.0f;
}
- (void)animateTransition:(id )transitionContext
{
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
[[transitionContext containerView] addSubview:toVC.view];
toVC.view.alpha = 0;
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
fromVC.view.transform = CGAffineTransformMakeScale(0.1, 0.1);
toVC.view.alpha = 1;
} completion:^(BOOL finished) {
//还原fromVC:
fromVC.view.transform = CGAffineTransformIdentity;
//动画结束后,完成上下文:
[transitionContext completeTransition:YES];
}];
}
@end