iOS 横屏竖屏切换问题

首先系统设置只能竖屏

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];

        

    }

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容