New file |
| | |
| | | |
| | | // 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 |