FairyGUI-Unity 异形屏适配
本文中会修改到FairyGUI源代码,涉及两个文件Stage和StageCamera,需要对Unity的屏幕类了解。
在网上查找有很多的异形屏适配操作,但对于FairyGUI相关的描述操作很少,这里我贴出一下自己在实际应用中的异形屏UI适配操作。
原理
获取当前设备的屏幕安全区域并设置为UI的正常显示尺寸,通过屏幕安全区域和实际分辨率修改UI背景的位置和尺寸。注意UI在设计中将溢出处理设置为默认“可见”。
关键方法:SetXY(x,y);SetSize(width,height)
打开Stage脚本,在构造函数中找到方法:
SetSize(Screen.width, Screen.height)
通过方法可以看到默认直接设置屏幕的宽高,将其修改为屏幕安全区域的宽高,这里我做了对称处理:
var safeArea = Screen.safeArea;
int safeAreaWidth = Mathf.CeilToInt(safeArea.width - safeArea.x);
int safeAreaHeight = safeArea.height;
SetSize(safeAreaWidth, safeAreaHeight);
打开StageCamera脚本,将OnEnable方法中的默认屏幕尺寸修改为安全区域的尺寸。
OnScreenSizeChanged(Screen.width, Screen.height);
修改为:
OnScreenSizeChanged(_safeAreaWidth, _safeAreaHeight);
将Update中的屏幕分辨率检测也一同修改为安全区域分辨率检测:
if (screenWidth != Screen.width || screenHeight != Screen.height)OnScreenSizeChanged(Screen.width, Screen.height);
修改为:
if (screenWidth != _safeAreaWidth || screenHeight != _safeAreaHeight)OnScreenSizeChanged(_safeAreaWidth, _safeAreaHeight);
之后在UI界面中,将背景的位置和大小修改为屏幕实际分辨率和安全区域外的位置。
SetXY(-Screen.safeArea.x,Screen.safeArea.y)
SetSize(Screen.width,Screen.height)
完整代码参考
Stage修改后的构造方法
/// <summary>
///
/// </summary>
public Stage(): base()
{_inst = this;soundVolume = 1;_updateContext = new UpdateContext();_frameGotHitTarget = -1;_touches = new TouchInfo[5];for (int i = 0; i < _touches.Length; i++)_touches[i] = new TouchInfo();bool isOSX = Application.platform == RuntimePlatform.OSXPlayer|| Application.platform == RuntimePlatform.OSXEditor;if (Application.platform == RuntimePlatform.WindowsPlayer|| Application.platform == RuntimePlatform.WindowsEditor|| isOSX)touchScreen = false;elsetouchScreen = Input.touchSupported && SystemInfo.deviceType != DeviceType.Desktop;//在PC上,是否retina屏对输入法位置,鼠标滚轮速度都有影响,但现在没发现Unity有获得的方式。仅判断是否Mac可能不够(外接显示器的情况)。所以最好自行设置。devicePixelRatio = (isOSX && Screen.dpi > 96) ? 2 : 1;_rollOutChain = new List<DisplayObject>();_rollOverChain = new List<DisplayObject>();_focusOutChain = new List<DisplayObject>();_focusInChain = new List<DisplayObject>();_focusHistory = new List<Container>();_cursors = new Dictionary<string, CursorDef>();//根据开关修改UI实际的分辨率if (GF.Main.Inst.enableSafeArea)//加一个启用安全区的开关{var safeArea = Screen.safeArea;int safeAreaWidth = Mathf.CeilToInt(safeArea.width - safeArea.x);int safeAreaHeight = Mathf.CeilToInt(safeArea.height + safeArea.y);SetSize(safeAreaWidth, safeAreaHeight);}elseSetSize(Screen.width, Screen.height);this.cachedTransform.localScale = new Vector3(StageCamera.DefaultUnitsPerPixel, StageCamera.DefaultUnitsPerPixel, StageCamera.DefaultUnitsPerPixel);StageEngine engine = GameObject.FindObjectOfType<StageEngine>();if (engine != null)UnityEngine.Object.Destroy(engine.gameObject);this.gameObject.name = "Stage";this.gameObject.layer = LayerMask.NameToLayer(StageCamera.LayerName);this.gameObject.AddComponent<StageEngine>();this.gameObject.AddComponent<UIContentScaler>();this.gameObject.SetActive(true);UnityEngine.Object.DontDestroyOnLoad(this.gameObject);EnableSound();Timers.inst.Add(5, 0, RunTextureCollector);SceneManager.sceneLoaded += SceneManager_sceneLoaded;
}
StageCamera的修改后完整代码
private Rect _safeArea;
private int _safeAreaWidth, _safeAreaHeight;
void OnEnable()
{_safeArea = Screen.safeArea;_safeAreaWidth = Mathf.CeilToInt(_safeArea.width - _safeArea.x);_safeAreaHeight = _safeArea.height;cachedTransform = this.transform;cachedCamera = this.GetComponent<Camera>();if (this.gameObject.name == Name){main = cachedCamera;isMain = true;}if (Display.displays.Length > 1 && cachedCamera.targetDisplay != 0 && cachedCamera.targetDisplay < Display.displays.Length)_display = Display.displays[cachedCamera.targetDisplay];if (_display == null){if (GF.Main.Inst.enableSafeArea)//加一个启用安全区的开关{OnScreenSizeChanged(_safeAreaWidth, _safeAreaHeight);}elseOnScreenSizeChanged(Screen.width, Screen.height);}elseOnScreenSizeChanged(_display.renderingWidth, _display.renderingHeight);
}
void Update()
{if (_display == null){if (GF.Main.Inst.enableSafeArea)//加一个启用安全区的开关{if (screenWidth != _safeAreaWidth || screenHeight != _safeAreaHeight)OnScreenSizeChanged(_safeAreaWidth, _safeAreaHeight);}else{if (screenWidth != Screen.width || screenHeight != Screen.height)OnScreenSizeChanged(Screen.width, Screen.height);}}else{if (screenWidth != _display.renderingWidth || screenHeight != _display.renderingHeight)OnScreenSizeChanged(_display.renderingWidth, _display.renderingHeight);}
}
UI界面中设置背景组件名为“_Loader_Bg”的位置和大小。注意UI在设计中将溢出处理设置为默认“可见”。
if ( _Loader_Bg != null)
{_Loader_Bg.SetXY(-Screen.safeArea.x,Screen.safeArea.y);_Loader_Bg.SetSize(Screen.width,Screen.height);
}
以上是对FairyGUI在设计横版游戏时对异形屏的适配操作,竖版游戏也是同理操作。如果对你有帮助,那就好!有问题也可以留言指出!感谢!
相关文章:
FairyGUI-Unity 异形屏适配
本文中会修改到FairyGUI源代码,涉及两个文件Stage和StageCamera,需要对Unity的屏幕类了解。 在网上查找有很多的异形屏适配操作,但对于FairyGUI相关的描述操作很少,这里我贴出一下自己在实际应用中的异形屏UI适配操作。 原理 获…...

Oracle监听器启动出错:本地计算机上的OracleOraDb11g_home1TNSListener服务启动后又停止了解决方案
在启动oracle的服务OracleOraDb11g_home1TNSListener时,提示服务启动后又停止了。 解决方法: 修改oracle安装目录下的两个配置文件: 以上两个文件,对应的HOST的值,都改为127.0.0.1 然后再启动服务,启动成…...
Spring复习:(58)<context:annotation-config/>的作用
引入如下的BeanPostProcessor • ConfigurationClassPostProcessor • AutowiredAnnotationBeanPostProcessor • CommonAnnotationBeanPostProcessor • PersistenceAnnotationBeanPostProcessor • EventListenerMethodProcessor如果xml文件配置了bean中使用了Autowired注解…...

“东方杯”英特尔oneAPI黑客松大赛—参赛经验分享
目录 前言1、大赛要求2、oneMKL介绍3、准备 oneMKL基本使用1、下载:2、安装:3、初始化oneMKL环境:4、编译代码5、运行 所需的头文件使用oneMKL工具生成随机数使用fftw3计算FFT调用oneMKL API加速计算FFT对比两种方法的准确性输出结果结束语 前…...

win10家庭版远程桌面补丁_rdp wrapper
RDP Wrapper Library 就是可以帮你在 Windows 7、Windows 8、Windows 10 家庭版中打开远程桌面的工具。 1、把电脑上打开的安全软件与杀毒软件都关掉,因为这个远程桌面补丁会修改系统文件,所以安全软件可能会拦截。 2、下载RDP Wrapper Library补丁压缩…...
【C++设计模式】开放-封闭原则
2023年8月27日,周日下午 我觉得我的这篇博客还是写得很不错的,哈哈哈。 目录 概述举例说明用开放-封闭原则重构 概述 开放-封闭原则(Open-Closed Principle,OCP)是面向对象设计中的一个重要原则,也是许多…...

vue+file-saver+xlsx+htmlToPdf+jspdf实现本地导出PDF和Excel
页面效果如下(echarts图表按需添加,以下代码中没有) 1、安装插件 npm install xlsx --save npm install file-saver --save npm install html2canvas --save npm install jspdf --save2、main.js引入html2canvas import htmlToPdf from …...

axios 进阶
axios 进阶 接口传参方式 使用 xhr 原生技术或者是 axios 时,它的 post 传参方式是键值对的形式 keyvalue。但是在实际开发中一般是使用对象的形式定义数据,方便读取和赋值。所以当我们需要发起请求时可以通过 qs 这一款插件将对象转成键值对形式&…...

Redis限流实践:实现用户消息推送每天最多通知2次的功能
🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌,CSDN博客专家,阿里云社区专家博主,2023年6月CSDN上海赛道top4。 🏆数年电商行业从业经验,历任核心研发工程师…...
uniapp 存储base64资源为http链接图片
1. 新建一个base64.js 文件 const fsm wx.getFileSystemManager(); // base64data base64资源 // name 文件名 function base64src(base64data, name, cb) {const time new Date().getTime();const filePath ${wx.env.USER_DATA_PATH}/${name}.${time}.png;const buffer …...
列表类控件虚拟化
WPF列表控件提供的最重要的功能是UI虚拟化(WPF编程宝典说的)。所有的WPF列表控件(所有继承自ItemsControl的控件,包括ListBox、CombBox、ListView、TreeView、DataGrid)都支持UI虚拟化。 UI虚拟化的支持实际上没有被构…...
c# 多线程Task.Run 取消正在执行的多线程
c# 异步处理,上次处理没有完成,下次有紧接着处理多线程出错 在 C# 中进行异步处理时,确保处理上一个任务完成后再处理下一个任务是很重要的,特别是在涉及多线程的情况下。如果上一个任务尚未完成,而下一个任务又开始执…...
sql server 如何设置主键
开始之前 限制和局限 一个表只能包含一个 PRIMARY KEY 约束。 在 PRIMARY KEY 约束中定义的所有列都必须定义为 NOT NULL。 如果没有指定为 Null 性,则加入 PRIMARY KEY 约束的所有列的为 Null 性都将设置为 NOT NULL。 创建主键会自动创建相应的唯一群集索引、…...

【LeetCode-中等题】19. 删除链表的倒数第 N 个结点
文章目录 题目方法一:节点加入集合找索引方法二:直接计算长度,然后找出要删除的节点的前一个节点方法三:栈方法四:前后双指针 题目 这题的关键在与两个点 一定要设置一个哑结点,防止删除第一个元素时,导致空…...

Matlab图像处理-减法运算
减法运算 图像减法也称为差分方法,是一种常用于检测图像变化及运动物体的图像处理方法。常用来检测一系列相同场景图像的差异,其主要的应用在于检测同一场景下两幅图像之间的变化或是混合图像的分离。 差影法 将同一景物在不同时问拍摄的图像或同一景…...

stm32之11.USART串口通信
可以添加上拉电阻,但会增加功耗,传输距离变长 要添加库函数USART 官方参考文档说明书位置 ALT+左键可实现整体删除(如下图) 输出模式第三种模式AF ---------------------- 源码 远程控制pc端 #include <stm32f4x…...

Python实现T检验
今天来分享一下T检验的python实现方法。 01 先来上一波概念。 1.单样本t检验,又称单样本均数t检验,适用于来自正态分布的某个样本均数与已知总体均数的比较,其比较目的是检验样本均数所代表的总体均数是否与已知总体均数有差别。已知总体均数…...

校招算法题实在不会做,有没有关系?
文章目录 前言一、校招二、时间复杂度1、单层循环2、双层循环 三、空间复杂度四、数据结构五、校招算法题实在不会做,有没有关系?六、英雄算法集训 前言 英雄算法联盟八月集训 已经接近尾声,九月算法集训将于 09月01日 正式开始,目…...

Michael.W基于Foundry精读Openzeppelin第32期——SignatureChecker.sol
Michael.W基于Foundry精读Openzeppelin第32期——SignatureChecker.sol 0. 版本0.1 SignatureChecker.sol 1. 目标合约2. 代码精读2.1 isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) 0. 版本 [openzeppelin]:v4.8.3,[for…...

如何修改字符串内容?
⭐ 作者:小胡_不糊涂 🌱 作者主页:小胡_不糊涂的个人主页 📀 收录专栏:浅谈Java 💖 持续更文,关注博主少走弯路,谢谢大家支持 💖 String 1. 修改字符串2. StringBuilder和…...

Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...

基于SpringBoot在线拍卖系统的设计和实现
摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...

GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...
Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成
一个面向 Java 开发者的 Sring-Ai 示例工程项目,该项目是一个 Spring AI 快速入门的样例工程项目,旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计,每个模块都专注于特定的功能领域,便于学习和…...
【SpringBoot自动化部署】
SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一,能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时,需要添加Git仓库地址和凭证,设置构建触发器(如GitHub…...
Leetcode33( 搜索旋转排序数组)
题目表述 整数数组 nums 按升序排列,数组中的值 互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...