美文网首页
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