jjzjj

iOS:关于横竖屏切换的知识点

最后还是个农 2023-09-25 原文

iOS16横竖屏的切换有了新的方式,正好赶上新的项目要求,所以重新整理了一下项目中的横竖屏切换问题。
项目要求:

  • iPhone整体禁止屏幕旋转只能竖屏,某些特定页面强制横屏,某些页面可以自由旋转。
  • iPad整体可以自由旋转,某些页面可以强制切换横竖屏,且切换后当前页面关闭自由旋转,返回后开启自由旋转。

如何开始横竖屏切换

1、项目配置:

在Xcode中TARGETS - General - Deployment Info中设置支持的方向,例如iPhone设置只支持竖屏,iPad支持全方向,注意iPad情况下需要勾选Requires full screen,设置为全屏,不分屏,否则强制切换屏幕旋转将失效(自己发现的,没有找到相关解释,有大神也可以解释一下)。如果不配置,只通过AppDelegate中代理方法控制,会导致启动页时不能正常识别屏幕方向。

Xcode配置.jpg

2、AppDelegate中的设置

因为某些页面需要强制屏幕切换,所以通过在AppDelegate实现代理的方式控制.
AppDelegate.h

/// 通过AppDelegate是实现旋转,解决部分页面强制旋转
/// 屏幕支持的方法方向
@property (nonatomic, assign) UIInterfaceOrientationMask orientations;

AppDelegate.m

  1. application:didFinishLaunchingWithOptions:中设置默认方向
// 设置默认方向
if (isPad) {
  // ipad
  self.orientations = UIInterfaceOrientationMaskAll;
} else {
  self.orientations = UIInterfaceOrientationMaskPortrait;
}
  1. 实现代理方法
/// 切换横竖屏:返回支持方向
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
    return self.orientations;
}
  1. 强制切换方向,且切换后禁止旋转
    例如强制横屏如下
 // AppDelegate设置横屏
    AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;

    // 当前是否横屏
    if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft || [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight) {
        // 已经横屏,AppDelegate中锁定为当前屏幕状态
        app.orientations = (1 << [UIApplication sharedApplication].statusBarOrientation);
    } else {
        // 竖屏-强制屏幕横屏
        // AppDelegate中锁定为横屏
        app.orientations = UIInterfaceOrientationMaskLandscapeRight;
        // 强制旋转
        if (@available(iOS 16.0, *)) {
#if defined(__IPHONE_16_0)
            // 避免没有更新Xcode14的同事报错
            // iOS16新API,让控制器刷新方向,新方向为上面设置的orientations
            [self setNeedsUpdateOfSupportedInterfaceOrientations];
#endif
        } else {
            // iOS16以下
            NSNumber *orientationPortrait = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight];
            [[UIDevice currentDevice] setValue:orientationPortrait forKey:@"orientation"];
        }
    }

在适当的位置记得iPhone修正方向,iPad放开旋转
        // iPhone改为竖屏,具体方式参考横屏
        // pad放开屏幕方向
        AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
        app.orientations = UIInterfaceOrientationMaskAll;
  1. 某个页面放开横竖屏切换,比如全屏视频播放时。
// 放开
AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
app.orientations = UIInterfaceOrientationMaskAll;
// 锁定
AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
app.orientations = UIInterfaceOrientationMaskPortrait;

#这种情况下,iOS16的强制横竖屏切换需要添加代码设置强制旋转,例如:
// 强制屏幕竖屏:手机
if ([UIApplication sharedApplication].statusBarOrientation != UIInterfaceOrientationPortrait) {
    if (@available(iOS 16.0, *)) {
        // iOS16新API,让控制器刷新方向,新方向为上面设置的orientations
#if defined(__IPHONE_16_0)
        [self setNeedsUpdateOfSupportedInterfaceOrientations];
        NSArray *array = [[[UIApplication sharedApplication] connectedScenes] allObjects];
        UIWindowScene *scene = [array firstObject];
        // 屏幕方向
        UIInterfaceOrientationMask orientation = UIInterfaceOrientationMaskPortrait;
        UIWindowSceneGeometryPreferencesIOS *geometryPreferencesIOS = [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:orientation];
        // 开始切换
        [scene requestGeometryUpdateWithPreferences:geometryPreferencesIOS errorHandler:^(NSError * _Nonnull error) {
            NSLog(@"强制%@错误:%@", @"横屏", error);
        }];
#endif
     } else {
          // iOS16以下
          NSNumber *orientationPortrait = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
          [[UIDevice currentDevice] setValue:orientationPortrait forKey:@"orientation"];
      }
}
  1. 关于横竖屏切换的监听
    对于屏幕旋转的监听,建议监听UIApplicationDidChangeStatusBarOrientationNotification,及状态栏的方向变化通知,这个收到这个通知的时候说明页面UI已经切换了。例如:
// 横竖屏切换通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleScreenOrientationChange:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
/// 横竖屏切换通知
- (void)handleScreenOrientationChange:(NSNotification *)noti {
    if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortrait || [UIApplication sharedApplication].statusBarOrientation == UIDeviceOrientationPortraitUpsideDown) {
        // 竖屏
    } else {
        // 横屏
    }
}
注意判断屏幕方向的时候一定要用UIInterfaceOrientation:屏幕的方向,不要错误的使用的UIDeviceOrientation:设备的方向。

暂时就这些内容。

补充一点,写代码的时候能用Autolayout就尽量用,不然突然有一天让你整个App适配横竖屏切换,在原有手机端代码基础上开发Pad,还有分屏效果,哭都没地方。

有关iOS:关于横竖屏切换的知识点的更多相关文章

  1. ruby-on-rails - Ruby on Rails with Haml - 如何从 erb 切换 - 2

    我正在从erb文件切换到HAML。我将hamlgem添加到我的系统中。我创建了app/views/layouts/application.html.haml文件。我应该只删除application.html.erb文件吗?此外,仍然有/public/index.html文件被呈现为默认页面。我想创建自己的默认index.html.haml页面。我应该把它放在哪里以及如何使系统呈现该文件而不是默认索引文件?谢谢! 最佳答案 是的,您可以删除任何已转换为HAML的View的ERB版本。至于你的另一个问题,删除public/index/h

  2. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  3. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  4. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  5. ruby - 为什么不能使用类IO的实例方法noecho? - 2

    print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上

  6. ruby-on-rails - 关于 Ruby 的一般问题 - 2

    我在我的rails应用程序中安装了来自github.com的acts_as_versioned插件,但有一段代码我不完全理解,我希望有人能帮我解决这个问题class_eval我知道block内的方法(或任何它是什么)被定义为类内的实例方法,但我在插件的任何地方都找不到定义为常量的CLASS_METHODS,而且我也不确定是什么here,并且有问题的代码从lib/acts_as_versioned.rb的第199行开始。如果有人愿意告诉我这里的内幕,我将不胜感激。谢谢-C 最佳答案 这是一个异端。http://en.wikipedia

  7. ruby - 我怎样才能更好地了解/了解更多关于 Ruby 的知识? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我最近开始学习Ruby,这是我的第一门编程语言。我对语法感到满意,并且我已经完成了许多只教授相同基础知识的教程。我已经写了一些小程序(包括我自己的数组排序方法,在有人告诉我谷歌“冒泡排序”之前我认为它非常聪明),但我觉得我需要尝试更大更难的东西来理解更多关于Ruby.关于如何执行此操作的任何想法?

  8. ruby - 关于 Ruby 中 Dir[] 和 File.join() 的混淆 - 2

    我在Ruby中遇到了一个关于Dir[]和File.join()的简单程序,blobs_dir='/path/to/dir'Dir[File.join(blobs_dir,"**","*")].eachdo|file|FileUtils.rm_rf(file)ifFile.symlink?(file)我有两个困惑:首先,File.join(@blobs_dir,"**","*")中的第二个和第三个参数是什么意思?其次,Dir[]在Ruby中有什么用?我只知道它等价于Dir.glob(),但是,我对Dir.glob()确实不是很清楚。 最佳答案

  9. elasticsearch源码关于TransportSearchAction【阶段三】 - 2

    1.回顾.TransportServicepublicclassTransportServiceextendsAbstractLifecycleComponentTransportService:方法:1publicfinalTextendsTransportResponse>voidsendRequest(finalTransport.Connectionconnection,finalStringaction,finalTransportRequestrequest,finalTransportRequestOptionsoptions,TransportResponseHandlerT>

  10. 关于Qt程序打包后运行库依赖的常见问题分析及解决方法 - 2

    目录一.大致如下常见问题:(1)找不到程序所依赖的Qt库version`Qt_5'notfound(requiredby(2)CouldnotLoadtheQtplatformplugin"xcb"in""eventhoughitwasfound(3)打包到在不同的linux系统下,或者打包到高版本的相同系统下,运行程序时,直接提示段错误即segmentationfault,或者Illegalinstruction(coredumped)非法指令(4)ldd应用程序或者库,查看运行所依赖的库时,直接报段错误二.问题逐个分析,得出解决方法:(1)找不到程序所依赖的Qt库version`Qt_5'

随机推荐