美文网首页
iOS 横屏竖屏切换问题

iOS 横屏竖屏切换问题

作者: 野咪咕 | 来源:发表于2024-01-14 09:47 被阅读0次

    首先系统设置只能竖屏

    1、UITabBarController 继承类实现

    //是否自动旋转

    -(BOOL)shouldAutorotate{

        return self.selectedViewController.shouldAutorotate;

    }

    //支持哪些屏幕方向

    - (UIInterfaceOrientationMask)supportedInterfaceOrientations {

        return [self.selectedViewController supportedInterfaceOrientations];

    }

    // persent出页面时的默认方向,

    // 网上很多文章认为是进入页面时的默认方向, 这个是不对的, 这个方法只针对present出来的vc, 注意看方法名后面  ForPresentation

    - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{

        return [self.selectedViewController preferredInterfaceOrientationForPresentation];

    }


    2、UINavigationController 继承类实现

    /是否自动旋转

    -(BOOL)shouldAutorotate{

        return self.topViewController.shouldAutorotate;

    }

    //支持哪些屏幕方向

    - (UIInterfaceOrientationMask)supportedInterfaceOrientations {

        return [self.topViewController supportedInterfaceOrientations];

    }

    // persent出页面时的默认方向,

    // 网上很多文章认为是进入页面时的默认方向, 这个是不对的, 这个方法只针对present出来的vc, 注意看方法名后面  ForPresentation

    - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{

        return [self.topViewController preferredInterfaceOrientationForPresentation];

    }

    3、AppDelegate.m实现

    - (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window

    {

         //避免导航栏导致bug

        [[UIApplication sharedApplication] setStatusBarHidden:NO];

    //_allowRotate 自己定义的属性,随便可以定义bool值,目的就是在某个viewController让window先支持屏幕旋转

        if (_allowRotate == 1) {

                return UIInterfaceOrientationMaskAll;

            }else{

                return (UIInterfaceOrientationMaskPortrait);

            }

    }


    4、viewController 页面

    //1.决定当前界面是否开启自动转屏,如果返回NO,后面两个方法也不会被调用,只是会支持默认的方向

    - (BOOL)shouldAutorotate {

          return YES;

    }


    //2.返回支持的旋转方向

    //iPad设备上,默认返回值UIInterfaceOrientationMaskAllButUpSideDwon

    //iPad设备上,默认返回值是UIInterfaceOrientationMaskAll

    - (UIInterfaceOrientationMask)supportedInterfaceOrientations{

       return UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortrait;

    }

    // persent出页面时的默认方向,

    // 网上很多文章认为是进入页面时的默认方向, 这个是不对的, 这个方法只针对present出来的vc, 注意看方法名后面  ForPresentation

    - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {

        return UIInterfaceOrientationPortraitUpsideDown;

    }

    -(void)viewWillAppear:(BOOL)animated

    {

        [super viewWillAppear:animated];

        [self.navigationController setNavigationBarHidden:YES animated:animated];

        //在视图出现的时候,将allowRotate改为1

         AppDelegate * delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;

         delegate.allowRotate = 1;

    }

    到此为止,屏幕就可以根据你设置支持的方向进行旋转了

    //当发生转屏事件时,系统的回调方法是:

    - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {

        [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

        // 即将开始转屏

        [self viewWillBeginTransitionWithSize:size];

        WS(weakSelf)

        [coordinator animateAlongsideTransition:nil completion:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {

            [weakSelf viewDidEndTransitionWithSize:size];

        }];

    }

    /// 子视图即将开始旋转

    - (void)viewWillBeginTransitionWithSize:(CGSize)size {

        if (size.width > size.height) { // 横屏

            // 横屏布局 balabala

       [self.view.layer setNeedsLayout];

        [self.view.layer layoutIfNeeded];

        } else {

            // 竖屏布局 balabala

       [self.view.layer setNeedsLayout];

        [self.view.layer layoutIfNeeded];

        }

    }

    /// 子视图旋转完成

    - (void)viewDidEndTransitionWithSize:(CGSize)size {

        if (size.width > size.height) { // 横屏

            // 横屏布局 balabala

         [self.view.layer setNeedsLayout];

         [self.view.layer layoutIfNeeded];

        } else {

            // 竖屏布局 balabala

      [self.view.layer setNeedsLayout];

        [self.view.layer layoutIfNeeded];

        }

    }

    //最好刷新下view

      [self.view.layer setNeedsLayout];

       [self.view.layer layoutIfNeeded];

    我项目里用的是监听的方法,监听屏幕发声变化的时候

    //在viewDidLoad 监听屏幕变化,但是这个方法不能判断屏幕到底向左还是向右,如果支持多个方向的话,遇到刘海屏还得适配,不然刘海屏有可能遮住UI,还有一个方法监听屏幕方向的

     //屏幕方向通知

        [[NSNotificationCenter defaultCenter] addObserver:self

                                                 selector:@selector(onDeviceOrientationDidChange) name:UIDeviceOrientationDidChangeNotification

                                                   object:nil];

    //屏幕尺寸变化的时候

        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(videoListdetectOrientation) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];

    #pragma mark - Notification:

    - (void)videoListdetectOrientation{

        [self.view.layer setNeedsLayout];

        [self.view.layer layoutIfNeeded];

       if(self.view.frame.size.width > self.view.frame.size.height){

          //横屏

      }else{


      }

    }

    #pragma mark - 屏幕方向通知

    - (BOOL)onDeviceOrientationDidChange{

        //获取当前设备Device

        UIDevice *device = [UIDevice currentDevice];

        //识别当前设备的旋转方向

        switch (device.orientation) {

            case UIDeviceOrientationFaceUp:

                DLog(@"屏幕幕朝上平躺");

               

                break;

                

            case UIDeviceOrientationFaceDown:

                DLog(@"屏幕朝下平躺");

              

                break;

            case UIDeviceOrientationUnknown:

                //系统当前无法识别设备朝向,可能是倾斜

                DLog(@"未知方向");

              

                break;

                

            case UIDeviceOrientationLandscapeLeft:{

                

                DLog(@"屏幕向左橫置"); //只支持的方向

                break;

            }

            case UIDeviceOrientationLandscapeRight:

                DLog(@"屏幕向右橫置");

                break;

                

            case UIDeviceOrientationPortrait:{

                DLog(@"屏幕直立");            

                break;

            }

            case UIDeviceOrientationPortraitUpsideDown:

                DLog(@"屏幕直立,上下顛倒");

                break;

                

            default:

                DLog(@"無法识别");

                break;

        }

        return YES;

    }

    //屏幕适配问题,横屏的时候获取不到状态栏高度,如果竖屏的时候self.view.layer layoutIfNeeded 不刷新view也获取不到状态栏高度,所以最好是竖屏的时候先用个属性赋值下,用Masonry 和 frame 都没切换 的时候都没问题,横屏的时候在调横屏子view的约束,一开始可以在-(instancetype)initWithFrame:(CGRect)frame

    {

        if (self = [super initWithFrame:frame]) {

        

            [self initsubviews];

        }

        return self;

    }

    只初始化添加,而不加约束

    5、重点,竖屏的时候点击按钮push跳转没问题,横屏的时候push跳转过去之后,下个页面布局错乱

    解决办法,一定要在跳转之前先把横屏变成竖屏在跳转。

    注意点:如果只是写在-(void)viewWillDisappear:(BOOL)animated 方法里是不管用的,因为他会先执行下个页面的viewDidLoad 在执行旋转,这个时候下个页面的view的宽高是横屏状态,导致页面错乱,显示的是竖屏的样式,实际宽高是横屏

    - (void)orientationPortrait{

           AppDelegate * delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;

           delegate.allowRotate = 0;

       

        if (@available(iOS 16.0, *)) {

            // iOS 16新增加了一个方法setNeedsUpdateOfSupportedInterfaceOrientations 方法是 UIViewController 的方法。这和更新状态栏的方法有点像,简单点说就是你想转屏可以,需要通知UIViewController 你已经准备好要转屏的方向了,然后再调用转屏方法即可(转屏方法后面会讲到)

            [self setNeedsUpdateOfSupportedInterfaceOrientations];

            NSArray *array = [[[UIApplication sharedApplication] connectedScenes] allObjects];

            UIWindowScene *scene = [array firstObject];

            // 屏幕方向

            UIInterfaceOrientationMaskorientation =  UIInterfaceOrientationMaskPortrait;

            UIWindowSceneGeometryPreferencesIOS *geometryPreferencesIOS = [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:orientation];

            // 开始切换

            [scenerequestGeometryUpdateWithPreferences:geometryPreferencesIOS errorHandler:^(NSError * _Nonnull error) {

               

            }];

        }else{

            

            //这个方法只有在- (BOOL)shouldAutorotate( return YES; )时,才会生效。并且请注意使用的枚举值的不同。

             if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {

                    SEL selector = NSSelectorFromString(@"setOrientation:");

                    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];

                    [invocationsetSelector:selector];

                    [invocationsetTarget:[UIDevice currentDevice]];

                    int val = UIInterfaceOrientationPortrait;

                    [invocationsetArgument:&val atIndex:2];

                    [invocationinvoke];

                }

            

               //会强制系统尝试将界面旋转到新的方向(必须加,不然横屏的时候跳到下个页面,下个页面会错乱)

               [UIViewController attemptRotationToDeviceOrientation];

            

        }

    相关文章

      网友评论

          本文标题:iOS 横屏竖屏切换问题

          本文链接:https://www.haomeiwen.com/subject/axutodtx.html