[分享干货晒技术]NGUI HUD屏幕适配
发表于2015-07-29
NGUI使用UIPanel和UIAnchor来管理UI元素,对屏幕适配已经支持得相当不错。但是由于屏幕尺寸的千奇百怪,开发过程中或多或少会碰到一些屏幕适配的问题。
微岛的HUD是基于iPhone 4的分辨率进行开发的,即限定了UIRoot上的UIPanel的Scaling Style为FixedSize, Manual Height为640。在做适配其他设备时还算比较顺利,主要碰到了一些小问题,在此谈谈。
先来看看市场上移动设备的分辨率情况,下面是友盟2014年7月份数据。
Android设备分辨率
分辨率 | 长宽比 | 长宽比 | 市场占有率 |
1280*720 | 16/9 | 1.78 | 20.50% |
960*540 | 16/9 | 1.78 | 9.70% |
1920*1080 | 16/9 | 1.78 | 7.80% |
854*480 | ~7/4 | 1.75 | 12.60% |
800*480 | 5/3 | 1.67 | 27.50% |
1184*720 | ~5/3 | 1.67 | 1.40% |
1280*800 | 8/5 | 1.6 | 1.20% |
480*320 | 3/2 | 1.5 | 9.90% |
800*600 | 4/3 | 1.33 | 0.70% |
iOS设备分辨率
分辨率 | 长宽比 | 长宽比 | 市场占有率 |
1136*640 | ~7/4 | 1.75 | 41.9% |
960*640 | 3/2 | 1.5 | 37.7% |
480*320 | 3/2 | 1.5 | 0.2% |
2048*1536 | 4/3 | 1.33 | 12.0% |
1024*768 | 4/3 | 1.33 | 8.2% |
从数据可以看出,市场主流设备的长宽比最小的在1.33(即4/3),最大的在1.78(即16/9),围绕着这两个数值,就有许多可能会发生。
问题归类一:
1、部分高度为640的大窗口的长宽比达到1.5,超过了最小的1.33,导致在iPad等小比例设备上无法显示完整;
2、小比例设备上,左上角和右上角的UI在屏幕上方叠加在一起;
解决方案:
1、先试试能否加大窗口长宽比,方便适应
2、根据最小支持的长宽比值,适当加大UIPanel的Manual Height,达到总体缩小Panel元素的目的;
- const int PANEL_HEIGHT_DEFAULT = 640;
- const float ADAPTE_ASPECTRATIO_MIN = 1.5f; //窗口支持的最小长宽比
- //UIPanel使用此值做为Manual Height
- public static int GetPanelHeight()
- {
- int panelHeight = PANEL_HEIGHT_DEFAULT;
- float aspectRation = Screen.width * 1.0f / Screen.height;
- if (aspectRation < ADAPTE_ASPECTRATIO_MIN)
- {
- int minWidth = (int)(Screen.height * ADAPTE_ASPECTRATIO_MIN);
- panelHeight = PANEL_HEIGHT_DEFAULT * minWidth / Screen.width;
- }
- return panelHeight;
- }
- public static int GetPanelWidth()
- {
- return GetPanelHeight() * Screen.width / Screen.height;
- }
问题归类二:
3、一张底图做背景的场景(如启动界面、登录背景等),会出现显示不全或者有空白的地方;
解决方法:
1、准备三张图,尺寸分别为960x640, 1136x640,1024x768,即分别为iPhone4, iPhone5, iPad 1的,放到Resources/Texture目录下,分别命名为splash_4to3@ldpi.png, splash_3to2@xhdpi.png和splash_16to9@xhdpi.png;
2、根据屏幕长宽比动态调节UIPanel和UI2DSprite的宽度和高度,代码如下;
- const float ADAPTE_ASPECTRATIO_4TO3 = 1.334f;
- const float ADAPTE_ASPECTRATIO_3TO2 = 1.5f;
- const float ADAPTE_ASPECTRATIO_16TO9 = 1.77f;
- public UI2DSprite splashSprite;
- int width = Screen.width;
- int height = Screen.height;
- float aspectRation = Screen.width * 1.0f / Screen.height;
- string splashTextureName = null;
- if (aspectRation <= ADAPTE_ASPECTRATIO_4TO3)
- {
- splashTextureName = @"Textures/splash_4to3@ldpi";
- }
- else if (aspectRation <= ADAPTE_ASPECTRATIO_3TO2)
- {
- splashTextureName = @"Textures/splash_3to2@xhdpi";
- }
- else if (aspectRation <= ADAPTE_ASPECTRATIO_16TO9)
- {
- splashTextureName = @"Textures/splash_16to9@xhdpi";
- }
- else
- {
- splashTextureName = @"Textures/splash_16to9@xhdpi";
- }
- Sprite splashTexture = (Sprite)Resources.Load(splashTextureName, typeof(Sprite));
- if(splashTexture != null)
- {
- int textureWidth = (int)splashTexture.textureRect.width;
- int textureHeight = (int)splashTexture.textureRect.height;
- splashSprite.sprite2D = splashTexture;
- if(Screen.height < textureHeight)
- {
- textureWidth = textureWidth * Screen.height / textureHeight;
- textureHeight = Screen.height;
- }
- if (aspectRation > ADAPTE_ASPECTRATIO_16TO9)
- {
- textureWidth = Screen.width;
- textureHeight = textureWidth * 640 / 1136;
- }
- root.manualHeight = textureHeight;
- splashSprite.width = textureWidth;
- splashSprite.height = textureHeight;
- }
- else
- {
- Debug.LogWarning(string.Format("No Sprite At Resource Path {0} Found!", splashTextureName));
- }
问题归类三:
4、部分遮罩不能覆盖住整个屏幕:
解决方法:使用问题一的解决方法,用GetPanelHeight()和GetPanelWidth()返回的值 来设置遮罩的长宽值;