赞
踩
本篇文章基于NGUI (3.12.0)版本源码下的代码分析,如果代码和大家自己的不同,可能是版本不同。如果文章中分析有误希望大神看见指点迷津,大家好,我就是一个勤勤恳恳爱偷懒的码农,希望和大家一起学习研究。
其实之前对屏幕适配只是了解和使用,利用 anchor 设置一些对象的固定位置。直到遇到一个小问题让我思考良多,所以非常想写一篇文章记录一下,原因是因为几个3D模型通过 camera 将其渲染到一张 贴图(Texture)上,非背景的贴图还好,但是如果是作背景的 Texture 不可以设置一个固定的大小比率,因为在不同手机的分辨率下 Texture 会出问题,这个时候就要思考需要给 Texture 根据屏幕适配 size,但是会出一个问题,就是贴图比率设置不好图会变形,但是这不是我们这篇文章的重点,我们的重点是谈一谈关于 NGUI 的屏幕适配。
UIRoot 中有一个 “Scaling Style” 属性,含有三个基本的选项,如下:
flexible:的原理主要是通过,限制屏幕显示的最小高度和最大高度然后去设置屏幕中真实显示的像素范围,如图:
举个例子:
图中这个手机的分辨率是:1334*750
表示这个手机,宽度是1334,高度是750,
但是我们设置的这个高度范围是 [760,800],即最小高度是760,最大高度是800,所以这个手机实际像素比我们最小的高度760还要小,那么它就会重新计算这个显示的像素大小:
如果这个手机高度比我们设置的高度还要小,那么这个实际显示的高度就是最小高度,并且重新计算宽度。
如果这个手机高度比我们设置的高度还要大,那么这个实际显示的高度就是最大高度,并且重新计算宽度。
如果这个手机的高度在我们限制的范围内,那么这个实现显示的高度就是这个手机的高度。
比如例子中,这个手机分辨率是:1334 * 750,那么需要重新计算实际显示的宽度和高度。
实际显示的高度是:760,
实际显示的宽度计算如下:
首先计算 手机像素的 宽高比
:宽度 / 高度 = ratio
因为:实际显示的宽度 / 实际显示的高度 == radio
所以,实际显示的宽度 = 760 * radio = 760 * (1334 / 750) = 1352(四舍五入取整)
所以手机实际显示的像素大小应该是:1352 * 760
如图使用一张贴图验证一下:
Constrained 的原理就是,设置一个最小的宽度,还有一个最小的高度,然后根据是否勾选 Fit 表明是否需要适配,最后根据这些设置去重新计算实际显示的宽度和高度,如图所示:
上图中以小米8为例,分辨率是:2248 * 1080
我们设置的屏幕最小宽度是:1280,最小高度是:720
这个时候你肯定会好奇,为啥 Constrained 有一个蓝色的框,但是 Flexible 没有,没错这点非常重要,接下来会讲。
(这里我们只分析 默认 宽高都是 Fit 勾选的情况下,即都默认需要适配)
首先我们需要计算出我们设置好的适配范围的宽高比
:
1280 / 720 = 16 / 9 = 1.7778
然后我们需要计算出手机分辨率的宽高比
:
2248 / 1080 = 2.0815
开始分析:
如果 手机像素的宽高比 > 我们基础设定范围的宽高比, 那么说明手机相对我们的基础设置来讲,屏幕更宽,高度更窄,所以我们需要限制它的高度,不能超过我们设置的最低高度 720,同时需要重新计算实际显示的宽度。(会出现蓝色边框,大小范围是 1280 * 720)
如果 手机像素的宽高比 < 我们基础设定范围的宽高比,那么说明手机相对我们的基础设置来讲,屏幕更高,宽度更窄,所以我们需要限制它的宽度,不能超过我们设置的最低宽度 1280,同时需要重新计算实际显示的高度。(会出现蓝色边框,大小范围是 1280 * 720)
如果 手机像素的宽高比 == 我们基础设定范围的宽高比,正常显示,不用调整。(不会出现蓝色框)
所以小米8,实际显示的高度是:720
因为,实际显示的宽度 / 实际显示的高度 == 小米8像素宽度 / 高度
所以,实际显示的宽度 = 720 * (2248 / 1080 = 2.0815 )= 1499(四舍五入)
所以屏幕中实际显示的大小是:1499 * 720
使用一张贴图验证一下:
其实吧 UIRoot 代码很少,而且也非常简单,这里我就只粘贴最核心的重新计算实际屏幕宽高相关的代码:
[DoNotObfuscateNGUI] public enum Scaling { Flexible, Constrained, ConstrainedOnMobiles, } [DoNotObfuscateNGUI] public enum Constraint { Fit, //宽度和高度都要适配 Fill, //设计和 fit 相反 FitWidth, //只有宽度适配 FitHeight, //只有高度适配 } public Constraint constraint { get { if (fitWidth) { if (fitHeight) return Constraint.Fit; return Constraint.FitWidth; } else if (fitHeight) return Constraint.FitHeight; return Constraint.Fill; } } //核心代码 public int activeHeight { get { Scaling scaling = activeScaling; if (scaling == Scaling.Flexible) { Vector2 screen = NGUITools.screenSize; float aspect = screen.x / screen.y; //屏幕高度不在 [minimumHeight, maximumHeight] 的范围的屏幕需要重新计算它的屏幕高度和宽度 if (screen.y < minimumHeight) { screen.y = minimumHeight; screen.x = screen.y * aspect; } else if (screen.y > maximumHeight) { screen.y = maximumHeight; screen.x = screen.y * aspect; } // Portrait mode uses the maximum of width or height to shrink the UI int height = Mathf.RoundToInt((shrinkPortraitUI && screen.y > screen.x) ? screen.y / aspect : screen.y); // Adjust the final value by the DPI setting return adjustByDPI ? NGUIMath.AdjustByDPI(height) : height; } else { Constraint cons = constraint; //如果是基于高度适配,直接返回项目基础开发的默认高度 if (cons == Constraint.FitHeight) return manualHeight; Vector2 screen = NGUITools.screenSize; //计算屏幕的宽高比 float aspect = screen.x / screen.y; //计算基础开发设置的 屏幕宽高比 float initialAspect = (float)manualWidth / manualHeight; switch (cons) { case Constraint.FitWidth: { // 如果只是适配宽度,也就是说 宽度不随屏幕的宽度变化,那么就需要根据 屏幕宽高比,计算基础的高度 // 基础宽度 / 需要显示的高度 = 屏幕宽度 / 屏幕高度 ,所以计算 需要显示的高度值即可 return Mathf.RoundToInt(manualWidth / aspect); } case Constraint.Fit: { // 说明是基于宽度和高度适配,设置了需要显示的最小宽度和最小高度 // 如果 屏幕实际的宽高比 > 基础的宽高比 --> 说明屏幕比基础设计的要宽,需要对高度进行缩放,不能低于最低高度,即:宽度可以变,高度不变 // 如果 屏幕实际的宽高比 < 基础的宽高比 --> 说明屏幕比基础设计的要寨,需要对宽度进行缩放,不能低于最低宽度,即:宽度不变,高度可以变 return (initialAspect > aspect) ? Mathf.RoundToInt(manualWidth / aspect) : manualHeight; } case Constraint.Fill: { // fill 的设计思路和 fit 相反 // 如果 屏幕实际的宽高比 > 基础的宽高比 --> 宽度不变,高度可以变 // 如果 屏幕实际的宽高比 < 基础的宽高比 --> 高度不变,宽度可以变 return (initialAspect < aspect) ? Mathf.RoundToInt(manualWidth / aspect) : manualHeight; } } return manualHeight; } } }
由此可见,如果我们开发过程中,给屏幕做了适配,那么可能手机中真实看到的大小并不是手机真正的像素大小,所以对一些屏幕坐标相关的功能,就要特别注意,比如获取屏幕中左下角,右上角的坐标。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。