iPhone和iPad的Swift5 UIView旋转行为不同

如何解决iPhone和iPad的Swift5 UIView旋转行为不同

我一直在努力应对iPhone和iPad(在模拟器以及真实设备中)在行为上的奇怪差异,尽管多次尝试访问Stackoverflow尝试了不同的诊断方法,但我仍在努力寻找根本原因。具体来说,我有一个简单的“测试”视图控制器,该控件在iPad上可以按预期执行,但相同的代码却有不同的表现,而在iPhone上却不如预期。我有一个UIImageView以纵向模式在每个设备上居中,左,右和顶部有10px的边距。当我旋转设备时,目标是在横向上调整图像大小,以使这些边距保持10px,即IE会缩放以适应新的几何形状,并且图像始终以其原始方向显示。 iPad无需大量代码即可完美地做到这一点。但是,iPhone可以正确执行缩放,但图像不会保持其原始方向...它随设备旋转而旋转。相同的代码如何产生两个不同的结果?

我可以通过检测iPhone并编写代码来旋转图像并确定新的放置位置来解决此问题,事实上,我已经做到了。但是,对于iPhone和iPad来说,让逻辑不同对我来说似乎不对。

一些详细信息:我正在使用带有IOS 14.0.1和iPad 7th Gen IOS 14.0.1的Swift 5 Xcode 12 MacOS 10.15.6 Simulator 11.5 iPhone 11

使用界面构建器最初构建布局并使用IBOutlet链接到代码,但是我使用的是translatesAutoresizingMaskIntoConstraints = false和以编程方式锚定约束来放置UIImageView。我正在使用Notification Center添加和删除观察者以触发旋转事件。我正在使用begin和endGeneratingDeviceOrientationNotifications()。我将TestAuto VC重写为true,应覆盖shouldAutorotate为true,将其全部支持,supportedInterfaceOrientationForPresentation作为肖像,并在TestDelegate中为UINavigationController和UITabBarController创建扩展以传播这些值(假设Test VC嵌入在Nav Controller中并使用标签栏)。信息plist列出了支持的界面方向的所有4种模式,并且Xcode项目的常规标签将iPhone和iPad选择为可部署,并且未为设备方向选择所有4种方向模式。

如果有帮助,我可以在此处添加代码以及屏幕截图。如果有人有类似的经验或对此有任何想法,我将不胜感激!这是TestVC的代码:

import UIKit

class Test: UIViewController {
    
    @IBOutlet weak var testImage: UIImageView!
    
    let debug = true
    let program = "TestViewController"
    var deviceSize = CGRect.zero
    var deviceWidth: CGFloat = 0
    var deviceHeight: CGFloat = 0
    let imageAsset = UIImage(named: "Cera.jpg")
    var aspectRatio: CGFloat = 0.0
    
    override var shouldAutorotate: Bool { return true }
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return UIInterfaceOrientationMask.all }
    override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { return UIInterfaceOrientation.portrait }
    
    // This routine triggered the first time this view controiller is loaded
    override func viewDidLoad() {
        super.viewDidLoad()
        let rtn = "viewDidLoad"
        top = self.view.topAnchor
        lead = self.view.leadingAnchor
        deviceSize = UIScreen.main.bounds
        deviceWidth = deviceSize.width
        deviceHeight = deviceSize.height
        
        UIDevice.current.beginGeneratingDeviceOrientationNotifications()
        NotificationCenter.default.addObserver(self,selector: #selector(deviceRotated),name: UIDevice.orientationDidChangeNotification,object: nil)
        
        if debug { print(">>> \(program): \(rtn): device width[\(deviceWidth)] device height[\(deviceHeight)]") }
        determineOrientation()
        if debug { print(">>> \(program): \(rtn): rotated device width[\(rotatedDeviceWidth)] rotated device height[\(rotatedDeviceHeight)]") }
        testImage.image = imageAsset
        let imageWidth = testImage.image!.size.width
        let imageHeight = testImage.image!.size.height
        aspectRatio = imageHeight / imageWidth
        calculateContraints()
    }
    
    // This routine triggered every time this view controller is presented
    override func viewWillAppear(_ animated: Bool) {
        let rtn = "viewWillAppear"
        if debug { print(">>> \(program): \(rtn): device width[\(deviceWidth)] device height[\(deviceHeight)]") }
        determineOrientation()
        if debug { print(">>> \(program): \(rtn): rotated device width[\(rotatedDeviceWidth)] rotated device height[\(rotatedDeviceHeight)]") }
    }
    
    // This routine added to remove observer for rotation events
    override func viewWillDisappear(_ animated: Bool) {
        NotificationCenter.default.removeObserver(self,object: nil)
        UIDevice.current.endGeneratingDeviceOrientationNotifications()
    }
    
    var orientation = "Portrait"
    var rotatedDeviceWidth: CGFloat = 0
    var rotatedDeviceHeight: CGFloat = 0
    
    // This routine called by "viewWillTransition" to determoine "orientation" value
    func determineOrientation() {
        let rtn = "determineOrientation"
        if debug { print(">>> \(program): \(rtn)") }
        if UIDevice.current.orientation == UIDeviceOrientation.portrait { orientation = "Portrait" }
        if UIDevice.current.orientation == UIDeviceOrientation.landscapeLeft { orientation = "LandscapeLeft" }
        if UIDevice.current.orientation == UIDeviceOrientation.landscapeRight { orientation = "LandscapeRight" }
        if UIDevice.current.orientation == UIDeviceOrientation.portraitUpsideDown { orientation = "PortraitUpsideDown" }
        if orientation == "Portrait" || orientation == "PortraitUpsideDown" {
            rotatedDeviceWidth = deviceWidth
            rotatedDeviceHeight = deviceHeight
        } else {
            rotatedDeviceWidth = deviceHeight
            rotatedDeviceHeight = deviceWidth
        }
    }
    
    var imageWidth: CGFloat = 0
    var imageHeight: CGFloat = 0
    var imageXpos: CGFloat = 0
    var imageYpos: CGFloat = 0
    var v: CGFloat = 0
    var h: CGFloat = 0
    var w: CGFloat = 0
    var ht: CGFloat = 0
    
    // This routine determines the position of the display object "testImage"
    func calculateContraints() {
        let rtn = "calculateContraints"
        if debug { print(">>> \(program): \(rtn): orientation[\(orientation)]") }
        if orientation == "Portrait" {
            imageWidth = deviceWidth / 2 - 20
            imageHeight = imageWidth * CGFloat(aspectRatio)
            imageXpos = 10
            imageYpos = 10
            if debug { print(">>> \(imageWidth): \(imageHeight)") }
        }
        if orientation == "LandscapeLeft" {
            imageWidth = rotatedDeviceWidth / 2 - 20
            imageHeight = imageWidth * CGFloat(aspectRatio)
            imageXpos = 10
            imageYpos = 10
            if debug { print(">>> \(imageWidth): \(imageHeight)") }
        }
        if orientation == "LandscapeRight" {
            imageWidth = rotatedDeviceWidth / 2 - 20
            imageHeight = imageWidth * CGFloat(aspectRatio)
            imageXpos = 10
            imageYpos = 10
            if debug { print(">>> \(imageWidth): \(imageHeight)") }
        }
        if orientation == "PortraitUpsideDown" {
            imageWidth = deviceWidth / 2 - 20
            imageHeight = imageWidth * CGFloat(aspectRatio)
            imageXpos = 10
            imageYpos = 10
            if debug { print(">>> \(imageWidth): \(imageHeight)") }
        }
        layoutConstraints(v: imageXpos,h: imageYpos,w: imageWidth,ht: imageHeight)
    }
    
    var testImageTopConstraint: NSLayoutConstraint!
    var testImageLeftConstraint: NSLayoutConstraint!
    var testImageWidthConstraint: NSLayoutConstraint!
    var testImageHeightConstraint: NSLayoutConstraint!
    var top: NSLayoutYAxisAnchor!
    var lead: NSLayoutXAxisAnchor!
    var trail: NSLayoutXAxisAnchor!
    var bot: NSLayoutYAxisAnchor!
    
    // This routine lays out the display object "testImage"
    func layoutConstraints(v: CGFloat,h: CGFloat,w: CGFloat,ht: CGFloat) {
        let rtn = "layoutConstraints"
        if debug { print(">>> \(program): \(rtn)") }
        testImage.translatesAutoresizingMaskIntoConstraints = false
        if testImageTopConstraint != nil { testImageTopConstraint.isActive = false }
        if testImageLeftConstraint != nil { testImageLeftConstraint.isActive = false }
        if testImageWidthConstraint != nil { testImageWidthConstraint.isActive = false }
        if testImageHeightConstraint != nil { testImageHeightConstraint.isActive = false }
        testImageTopConstraint = testImage.topAnchor.constraint(equalTo: top,constant: v)
        testImageLeftConstraint = testImage.leadingAnchor.constraint(equalTo: lead,constant: h)
        testImageWidthConstraint = testImage.widthAnchor.constraint(equalToConstant: w)
        testImageHeightConstraint = testImage.heightAnchor.constraint(equalToConstant: ht)
        testImageTopConstraint.isActive = true
        testImageLeftConstraint.isActive = true
        testImageWidthConstraint.isActive = true
        testImageHeightConstraint.isActive = true
    }
}

@objc extension Test {
    func deviceRotated(_ notification: NSNotification) {
        let device = notification.object as! UIDevice
        let deviceOrientation = device.orientation
        switch deviceOrientation {
        case .landscapeLeft: print("<<<Landscape Left>>>")
        case .landscapeRight: print("<<<Landscape Right>>>")
        case .portrait: print("<<<Portrait>>>")
        case .portraitUpsideDown: print("<<<Portrait Upside Down>>>")
        case .faceDown: print("<<<Face Down>>>")
        case .faceUp: print("<<<Face Up>>>")
        case .unknown: print("<<<Unknown>>>")
        @unknown default: print("<<<Default>>>")
        }
        let rtn = "deviceRotated2"
        determineOrientation()
        if debug { print(">>> \(program): \(rtn): Device rotated to: \(orientation)") }
        if debug { print(">>> \(program): \(rtn): rotated device width[\(rotatedDeviceWidth)] rotated device height[\(rotatedDeviceHeight)]") }
        calculateContraints()
    }
}

这是SceneDelegate.swift中的代码

extension UINavigationController {
    
    override open var shouldAutorotate: Bool {
        get {
            if let visibleVC = visibleViewController { return visibleVC.shouldAutorotate }
            return super.shouldAutorotate } }
    
    override open var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
        get {
            if let visibleVC = visibleViewController { return visibleVC.preferredInterfaceOrientationForPresentation }
            return super.preferredInterfaceOrientationForPresentation } }
    
    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        get {
            if let visibleVC = visibleViewController { return visibleVC.supportedInterfaceOrientations }
            return super.supportedInterfaceOrientations } }
}

// ===================================================================================
// UITabBarController Extension - used to manage tab bar style
//
extension UITabBarController {
    open override var childForStatusBarStyle: UIViewController? {
        return selectedViewController?.childForStatusBarStyle ?? selectedViewController
    }
}

// ===================================================================================
// UITabBarController Extension - used to manage rotation
//
extension UITabBarController {
    
    override open var shouldAutorotate: Bool {
        if let viewController = self.viewControllers?[self.selectedIndex] { return viewController.shouldAutorotate }
        return super.shouldAutorotate }
    
    override open var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
        if let viewController = self.viewControllers?[self.selectedIndex] { return viewController.preferredInterfaceOrientationForPresentation }
        return super.preferredInterfaceOrientationForPresentation }
    
    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        if let viewController = self.viewControllers?[self.selectedIndex] { return viewController.supportedInterfaceOrientations }
        return super.supportedInterfaceOrientations }
}

这是模拟器中iPhone的旋转结果: Cera rotations for iPhone

...和iPad: Cera rotations for iPad

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res