// ZFOrentationObserver.m // ZFPlayer // // Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng ) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. #import "ZFOrientationObserver.h" @interface UIWindow (CurrentViewController) /*! @method currentViewController @return Returns the topViewController in stack of topMostController. */ + (UIViewController*)zf_currentViewController; @end @implementation UIWindow (CurrentViewController) + (UIViewController*)zf_currentViewController; { UIWindow *window = [[UIApplication sharedApplication].delegate window]; UIViewController *topViewController = [window rootViewController]; while (true) { if (topViewController.presentedViewController) { topViewController = topViewController.presentedViewController; } else if ([topViewController isKindOfClass:[UINavigationController class]] && [(UINavigationController*)topViewController topViewController]) { topViewController = [(UINavigationController *)topViewController topViewController]; } else if ([topViewController isKindOfClass:[UITabBarController class]]) { UITabBarController *tab = (UITabBarController *)topViewController; topViewController = tab.selectedViewController; } else { break; } } return topViewController; } @end static UIWindow *kWindow; @interface ZFOrientationObserver () @property (nonatomic, weak) UIView *view; @property (nonatomic, assign, getter=isFullScreen) BOOL fullScreen; @property (nonatomic, assign) NSInteger playerViewIndex; @property (nonatomic, strong) UIView *cell; @property (nonatomic, assign) NSInteger playerViewTag; @property (nonatomic, assign) ZFRotateType roateType; @end @implementation ZFOrientationObserver - (instancetype)init { self = [super init]; if (self) { _duration = 0.25; _fullScreenMode = ZFFullScreenModeLandscape; kWindow = [(id)[UIApplication sharedApplication].delegate valueForKey:@"window"]; _shouldAutorotate = YES; } return self; } - (instancetype)initWithRotateView:(UIView *)rotateView containerView:(UIView *)containerView { if ([self init]) { _roateType = ZFRotateTypeNormal; _view = rotateView; _containerView = containerView; } return self; } - (void)cellModelRotateView:(UIView *)rotateView rotateViewAtCell:(UIView *)cell playerViewTag:(NSInteger)playerViewTag { self.roateType = ZFRotateTypeCell; self.view = rotateView; self.cell = cell; self.playerViewTag = playerViewTag; } - (void)cellSmallModelRotateView:(UIView *)rotateView containerView:(UIView *)containerView { self.roateType = ZFRotateTypeCellSmall; self.view = rotateView; self.containerView = containerView; } - (void)dealloc { [self removeDeviceOrientationObserver]; } - (void)addDeviceOrientationObserver { if (![UIDevice currentDevice].generatesDeviceOrientationNotifications) { [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; } [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDeviceOrientationChange) name:UIDeviceOrientationDidChangeNotification object:nil]; } - (void)removeDeviceOrientationObserver { if (![UIDevice currentDevice].generatesDeviceOrientationNotifications) { [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications]; } [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil]; } - (void)handleDeviceOrientationChange { if (self.fullScreenMode == ZFFullScreenModePortrait) return; if (!self.shouldAutorotate) return; if (UIDeviceOrientationIsValidInterfaceOrientation([UIDevice currentDevice].orientation)) { _currentOrientation = (UIInterfaceOrientation)[UIDevice currentDevice].orientation; } else { _currentOrientation = UIInterfaceOrientationUnknown; return; } UIInterfaceOrientation currentOrientation = [UIApplication sharedApplication].statusBarOrientation; // Determine that if the current direction is the same as the direction you want to rotate, do nothing if (_currentOrientation == currentOrientation) return; switch (_currentOrientation) { case UIInterfaceOrientationPortrait: { [self enterLandscapeFullScreen:UIInterfaceOrientationPortrait animated:YES]; } break; case UIInterfaceOrientationLandscapeLeft: { [self enterLandscapeFullScreen:UIInterfaceOrientationLandscapeLeft animated:YES]; } break; case UIInterfaceOrientationLandscapeRight: { [self enterLandscapeFullScreen:UIInterfaceOrientationLandscapeRight animated:YES]; } break; default: break; } } - (void)enterLandscapeFullScreen:(UIInterfaceOrientation)orientation animated:(BOOL)animated { if (self.fullScreenMode == ZFFullScreenModeLandscape) { UIView *superview = nil; CGRect frame; if (UIInterfaceOrientationIsLandscape(orientation)) { superview = kWindow; if (!self.isFullScreen) { /// It's not set from the other side of the screen to this side self.view.frame = [self.view convertRect:self.view.frame toView:superview]; } for (NSInteger i = 0; i < _containerView.subviews.count; i++) { if (self.containerView.subviews[i] == self.view) { self.playerViewIndex = i; break; } } self.fullScreen = YES; [superview addSubview:_view]; } else { if (self.roateType == ZFRotateTypeCell) { superview = [self.cell viewWithTag:self.playerViewTag]; } else { superview = self.containerView; } self.fullScreen = NO; } frame = [superview convertRect:superview.bounds toView:kWindow]; _currentOrientation = orientation; [UIApplication sharedApplication].statusBarOrientation = orientation; if (self.orientationWillChange) { self.orientationWillChange(self, self.isFullScreen); } [UIView animateWithDuration:self.duration animations:^{ self.view.transform = [self getTransformRotationAngle:orientation]; [UIView animateWithDuration:self.duration animations:^{ self.view.frame = frame; [self.view layoutIfNeeded]; }]; } completion:^(BOOL finished) { if (!UIInterfaceOrientationIsLandscape(orientation) && self.roateType == ZFRotateTypeNormal) { [superview insertSubview:self.view atIndex:self.playerViewIndex]; } else if (!UIInterfaceOrientationIsLandscape(orientation)) { [superview addSubview:self.view]; } self.view.frame = superview.bounds; if (self.orientationDidChanged) self.orientationDidChanged(self, self.isFullScreen); }]; } } /// Gets the rotation Angle of the transformation. - (CGAffineTransform)getTransformRotationAngle:(UIInterfaceOrientation)orientation { if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation) && orientation == UIInterfaceOrientationPortrait) { return CGAffineTransformIdentity; } if (orientation == UIInterfaceOrientationPortrait) { return CGAffineTransformIdentity; } else if (orientation == UIInterfaceOrientationLandscapeLeft){ return CGAffineTransformMakeRotation(-M_PI_2); } else if(orientation == UIInterfaceOrientationLandscapeRight){ return CGAffineTransformMakeRotation(M_PI_2); } return CGAffineTransformIdentity; } - (void)enterPortraitFullScreen:(BOOL)fullScreen animated:(BOOL)animated { if (self.fullScreenMode == ZFFullScreenModeLandscape) return; UIView *superview = nil; if (fullScreen) { superview = kWindow; self.view.frame = [self.view convertRect:self.view.frame toView:superview]; [superview addSubview:self.view]; self.fullScreen = YES; if (self.orientationWillChange) { self.orientationWillChange(self, self.isFullScreen); } } else { if (self.roateType == ZFRotateTypeCell) { superview = [self.cell viewWithTag:self.playerViewTag]; } else { superview = self.containerView; } self.fullScreen = NO; if (self.orientationWillChange) { self.orientationWillChange(self, self.isFullScreen); } } CGRect frame = [superview convertRect:superview.bounds toView:kWindow]; [UIView animateWithDuration:self.duration animations:^{ self.view.frame = frame; [self.view layoutIfNeeded]; } completion:^(BOOL finished) { [superview addSubview:self.view]; self.view.frame = superview.bounds; if (self.orientationDidChanged) { self.orientationDidChanged(self, self.isFullScreen); } }]; } - (void)setLockedScreen:(BOOL)lockedScreen { _lockedScreen = lockedScreen; if (lockedScreen) { [self removeDeviceOrientationObserver]; } else { [self addDeviceOrientationObserver]; } } - (void)setFullScreen:(BOOL)fullScreen { _fullScreen = fullScreen; [[UIWindow zf_currentViewController] setNeedsStatusBarAppearanceUpdate]; } - (void)setStatusBarHidden:(BOOL)statusBarHidden { _statusBarHidden = statusBarHidden; [[UIWindow zf_currentViewController] setNeedsStatusBarAppearanceUpdate]; } @end