iOS横竖屏旋转内容总结

2025-05-29 0 72

一、前言

swift版本 4.0

xcode版本 9.2

以前接触到的项目需求中,几乎都是全竖屏展现界面,所以我也来得省事,直接在targets中的界面方向选项中只勾选竖屏,这样就满足了需求。

iOS横竖屏旋转内容总结

但最近的项目中,产品突然增加了一个需求,需要部分界面支持旋转,这才来研究了一下屏幕旋转的问题!

需要紧急解决问题的道友直接看3.3

二、屏幕旋转相关知识

2.1 三个方向的理解和联系

uideviceorientation: 设备方向

?

1

2

3

4

5

6

7

8

9
public enum uideviceorientation : int {

case unknown

case portrait // 设备vertically方向, home键在下方

case portraitupsidedown // 设备vertically方向, home键在上方

case landscapeleft // 设备horizontally方向, home键在右方

case landscaperight // 设备horizontally方向, home键在左方

case faceup // 设备flat方向, 屏幕朝上

case facedown // 设备flat方向, 屏幕朝下

}

从设备方向的命名就能看出来这个枚举的含义,这里指的是物理设备(即iphone)的方向。

uiinterfaceorientation: 界面方向

?

1

2

3

4

5

6

7
public enum uiinterfaceorientation : int {

case unknown

case portrait

case portraitupsidedown

case landscapeleft

case landscaperight

}

而界面方向指屏幕中显示内容的方向,它的方向和home键的方向是一致的。仔细观察一下屏幕旋转就能理解uideviceorientation和uiinterfaceorientation了,我们把手机转向左边,可以看到界面随之才转向右边。

uiinterfaceorientationmask: 是用来控制允许转向的方向,对应uiinterfaceorientation

?

1

2

3

4

5

6

7

8

9

10
public struct uiinterfaceorientationmask : optionset {

public init(rawvalue: uint)

public static var portrait: uiinterfaceorientationmask { get }

public static var landscapeleft: uiinterfaceorientationmask { get }

public static var landscaperight: uiinterfaceorientationmask { get }

public static var portraitupsidedown: uiinterfaceorientationmask { get }

public static var landscape: uiinterfaceorientationmask { get }

public static var all: uiinterfaceorientationmask { get }

public static var allbutupsidedown: uiinterfaceorientationmask { get }

}

2.2 观察屏幕旋转并作出响应

2.2.1 观察设备方向并响应

?

1

2

3

4

5

6

7

8

9
// 没有生成通知

if !uidevice.current.isgeneratingdeviceorientationnotifications {

// 生成通知

uidevice.current.begingeneratingdeviceorientationnotifications()

}

// 锁定竖屏,依然有效,例如faceup.

notificationcenter.default.addobserver(self,

selector: #selector(handledeviceorientationchange(notification:)), name:nsnotification.name.uideviceorientationdidchange,

object: nil)

?

1

2

3

4

5

6

7

8

9

10

11
@objc private func handledeviceorientationchange(notification: notification) {

// 获取设备方向

let orientation = uidevice.current.orientation

switch orientation {

case .landscaperight:

// ios8之后,横屏uiscreen.main.bounds.width等于竖屏时的uiscreen.main.bounds.height

print(uiscreen.main.bounds.width)

print("landscaperight")

default: break

}

}

注销

?

1

2

3

4
deinit {

notificationcenter.default.removeobserver(self)

uidevice.current.endgeneratingdeviceorientationnotifications()

}

2.2.2 观察界面方向并响应

和上面类似不过观察的name为

?

1

2

3
// 锁定竖屏,无效,通知方法不会触发

nsnotification.name.uiapplicationwillchangestatusbarorientation

nsnotification.name.uiapplicationdidchangestatusbarorientation

获取界面方向

?

1
let statusbarorientation = uiapplication.shared.statusbarorientation

2.2.3 建议

这里建议监听界面方向,原因有二:

监听设备方向,会返回多个方向,例如portrait和faceup不冲突。

监听设备方向,上面提到,先是设备旋转,随之界面旋转,这里就有一个问题,我们操作界面时,可能界面还没有旋转。

三、问题解决实战

需要实现部分界面可旋转,部分界面锁定竖屏,首先我们需要配置targets中的device orientation,这里是总开关,默认勾选了如图方向:

iOS横竖屏旋转内容总结

如果你确定整个项目只有竖屏,直接只勾选protrait完事,不过像我现在这样,可能突然一个需求改变就不得不继续适配,哈哈。

这里的配置不要和代码控制的方向相冲突,不然会引发奔溃。

3.1 控制屏幕旋转的函数

?

1

2

3

4

5

6

7

8

9

10

11

12
// 默认为true

override var shouldautorotate: bool {

return true

}

// 支持的旋转方向

override var supportedinterfaceorientations: uiinterfaceorientationmask {

return .landscapeleft

}

// 模态切换的默认方向

override var preferredinterfaceorientationforpresentation: uiinterfaceorientation {

return .landscaperight

}

这三个属性都重写的uiviewcontroller的属性。哎,看到模态切换,这里再给自己挖坑一个,以前研究了一会模态切换,只不过没写成总结,后面会写出来(:。

并且这三个方法会受到控制器层级的影响,也就是如果当前控制器配置支持旋转,如果他的导航控制器,乃至tabbar控制器不支持旋转,当前控制器的配置也不会生效。

3.2 不同根控制器情况下的解决

核心问题: 需要旋转的界面是少数,大多界面需要锁定竖屏。

3.2.1 根控制器为uiviewcontroller

对应demo配置:

iOS横竖屏旋转内容总结

这种情况的app可以说是非常少了,不过还是对后面的情况有所帮助。

设置basevc,在其中的配置锁定竖屏:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14
class basevc: uiviewcontroller {

override var shouldautorotate: bool {

return false

}

override var supportedinterfaceorientations: uiinterfaceorientationmask {

return .portrait

}

override var preferredinterfaceorientationforpresentation: uiinterfaceorientation {

return .portrait

}

override func viewdidload() {

super.viewdidload()

}

}

然后其余控制器继承basevc,需要旋转的控制器单独再次重写方法。

3.2.2 根控制器为uinavigationcontroller

对应demo配置:

iOS横竖屏旋转内容总结

我们可以获取到当前显示层级的控制器,并拿出它的属性赋给uinavigationcontroller

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14
class basenavc: uinavigationcontroller {

override var shouldautorotate: bool {

return self.viewcontrollers.last?.shouldautorotate ?? false

}

override var supportedinterfaceorientations: uiinterfaceorientationmask {

return self.viewcontrollers.last?.supportedinterfaceorientations ?? .portrait

}

override var preferredinterfaceorientationforpresentation: uiinterfaceorientation {

return self.viewcontrollers.last?.preferredinterfaceorientationforpresentation ?? .portrait

}

override func viewdidload() {

super.viewdidload()

}

}

3.2.3 根控制器为uitabbarcontroller

对应demo配置:

iOS横竖屏旋转内容总结

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17
class basetabbarc: uitabbarcontroller {

override var shouldautorotate: bool {

return self.selectedviewcontroller?.shouldautorotate ?? false

}

override var supportedinterfaceorientations: uiinterfaceorientationmask {

return self.selectedviewcontroller?.supportedinterfaceorientations ?? .portrait

}

override var preferredinterfaceorientationforpresentation: uiinterfaceorientation {

return self.selectedviewcontroller?.preferredinterfaceorientationforpresentation ?? .portrait

}

override func viewdidload() {

super.viewdidload()

}

}

同理,我们只需要获取当前选中的控制器的配置赋给uitabbarcontroller,这样一层一层就配置好了!

3.3 最简单的实现方式

对应demo配置:

iOS横竖屏旋转内容总结

在查询屏幕旋转相关资料的时候我发现屏幕旋转时会最后调用appdelegate中的:

?

1

2

3
func application(_ application: uiapplication, supportedinterfaceorientationsfor window: uiwindow?)

-> uiinterfaceorientationmask {

}

然后我立马想到一个超级简单的方法,那就是定义一个全局变量或者缓存一个bool值来进行判断,如下:

?

1

2

3

4

5

6

7

8

9
func application(_ application: uiapplication, supportedinterfaceorientationsfor window: uiwindow?)

-> uiinterfaceorientationmask {

if isallowautorotate {

return [.portrait, .landscapeleft, .landscaperight]

}

else {

return .portrait

}

}

然后默认isallowautorotate这个全局变量为false,在需要旋转的控制器中:

?

1

2

3

4

5

6

7

8

9

10
override func viewwillappear(_ animated: bool) {

super.viewwillappear(animated)

isallowautorotate = false

}

override func viewwilldisappear(_ animated: bool) {

super.viewwilldisappear(animated)

isallowautorotate = true

}

}

这样就不用麻烦的去搞那些继承什么的了!

四、后记和demo

https://github.com/swordjoy/screenrotationdemo

以上就是本次小编整理的全部内容,感谢大家的支持,如果还有任何相关问题可以在下方的留言区讨论。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 iOS横竖屏旋转内容总结 https://www.kuaiidc.com/89648.html

相关文章

发表评论
暂无评论