`

开发AIR mobile应用时多设备上的显示处理

阅读更多

移动设备关于显示效果的问题尤其突出,分辨率、屏幕尺寸各异,处理起来相对比较麻烦,好在Adobe本身已进行了相关处理,它主要是根据3个DPI来进行相应处理的。(用 Google Android SDK 的 Project 中的draw 目录默认也是按 low、medium、high 区分的,所以按3个DPI处理应该是比较正确的方法啦)。

 

 

相关资料:

Android手机分辨率基础知识

手机屏幕技术浅述(TFT、SLCD、AMOLED、NOVA、IPS、ASV)

Adobe官方文 档:在一个手机应用程序中支持多个屏幕大小和 DPI 值

为多个屏幕大小创作移动 Flash 内容

Flex移动skin – 第2部分:处理不同的像素密度

Mobile Development: scaling content depending on the screen resolution

Define a mobile application and a splash screen   (适用于Flex SDK v4.6.0)

 

一、简单小结

官方给出的解决方法主要有以 下3种:(殊途同归:最终都是靠DPI定位的)

1. 使用自动缩放:(方便和确保像素精确的视觉保真度之间的一种折衷方法)

    设置 application 的 applicationDPI 属性值为某个DPI;

    只需要针对目标DPI值创建外观和组件布局;

    位图需最好要有多个版本,使用 MultiDPIBitmapSource 类进行设置;

    css中不需要使用@media。

2. 不使用自动缩放:

    需要针对3个DPI来创建外观或组件布局或支持根据DPI动态调整的外观和布局;

    在css中通过@media分别设置3套值(主要要设置字体大小、内边距)。

3. 自定义设备的DPI归类:(无论是否自动缩放均可)

    编写一个 extends RuntimeDPIProvider 的类;

    设置 application 的 runtimeDPIProvider 为该类;

    该类 override get runtimeDPI 方法,然后在该方法中可以根据Capabilities.screenDPI、Capabilities.screenResolutionY 等自定义设备的DPI 属于哪一个。

 

其他几篇文章提供的思路:

1. 尽量根据%、stage.stageWidth、stage.stageHeight 来设置组件宽度、高度;

2. 如果一定要用绝对值,则最好使用物理单位(如inch、cm),然后将该值转化为像素。

3. 使用绝对值时,在分辨率较高的屏幕上,组件会显得较小,此时可以根据分辨率计算比例来对组件进行缩放。

 

、UI设计要点

1. 图标大小:

1) 类似置于状态栏、标题栏位置的图标,比较合适的大小分别为24、32(似乎36更合适)、48px;

2) 另一套比 1) 稍大的图标大小标准分别为36、48、72px。

2. itemrenderer 的高度,查看SDK源码得知其默认被处理为44、66、88px,可以按此标准考虑应用的某些尺寸。(调试发现,实际输出高度分别为:52、72、104)


、与分辨率、DPI相关的API

Capabilities.screenResolutionX 设备的横向分辨率,在移动设备该值通常是较小的那个,如480*800的480。

Capabilities.screenResolutionY 设备的竖向分辨率。

Capabilities.screenDPI 设备的实际DPI。

FlexGlobals.topLevelApplication.runtimeDPI 设备的近似DPI,只有160、240、320这3个值。

DPIClassification.DPI_160, DPIClassification.DPI_240, DPIClassification.DPI_320 160,240,320对应的常量。

FlexGlobals.topLevelApplication.applicationDPI 应用的DPI,如未指定,其值=runtimeDPI。

 

四、实践记录(FlashBuilder4.5.1 + Flex SDK4.5.1 +AIRSDK2.7)

1. 桌面环境调试mobile应用时,Capabilities.screenResolutionX, Capabilities.screenResolutionY 返回的值是当前PC的分辨率,此时如果需要用到这2个值时只能hardcode。

 

2. 如果 view 的 actionBarVisible=true,则标题栏在3个DPI下的高度会有所不同,DPI320下会比较高,此时可能会影响到这个view最底部的元素的可见度,另外navigationContent、actionContent的宽度也与DPI有关(1024*600 DPI160时点击范围略微有些小),所以最好不要使用标题栏,若使用则需要测试下view内容是否能完整显示,要不然只能给整个view加上scroll(仅为了这一点加的话似乎不太划算)。可以考虑做个仿真的标题栏。

 

3. 实测我的应用,之前开发时未指定 applicationDPI,主要以480*800 240DPI(目前Android设备市场主流)为参考进行UI设置的,字体大小为28px,在 3.7 inch 寸设备上看起来大小比较适中。

然后分别在不同分辨率和DPI下进行测试,除了 320*480 DPI160下由于字体过大无法显示完整的整屏内容外,在其他设备上均显示良好,当然在分辨率高于480*800的设备上,原刚好一屏的内容会显得有些“营养不良” 。

指定 applicationDPI=240 之后再次测试,分辨率在 600*1024 及其以上的设备上时,由于其默认DPI被归于160,所以字体等被缩小了,显得有些过小,不太合适。

 

4. 我的应用最终所采用的方案,共有以下几点(几乎把能用的都用上了):

1) 不使用自动缩放;(自动缩放存在一些问题)

2) 自定义 extends RuntimeDPIProvider 类,改写默认的 runtimeDPI 策略;

主要改写之处:

a) 分辨率在600*1024以上的设备的DPI,默认情况下均近似为160,而这些设备的物理尺寸相对大部分手机来说是绝对够大的,所以将其改写为归于 240之列;

b) Motorola 的几款手机分辨率高于480*800,如 Atrix 4G,其分辨率为540*960,实际DPI为275,默认情况下被归于240之列,但由于其物理尺寸并未明显加大,导致应用的字体等看起来偏小,所以将其改写为归于320之列。

注:Moto Atrix 4G真机下运行测试,发现所得到的screenDPI居然是240,其桌面模拟环境是275,于是自定义的RuntimeDPIProvider 还得略作调整。

3) 位图资源按ldpi、mdpi、hdpi分别准备3套 (这个无论是否自动缩放均需要);

4) css中使用@media 设置fontsize;

5) 使用物理单位,设置时将其换算成pixels,主要用在需要固定高度的地方,如view的顶部、底部、某些item等;

6) 根据分辨率scale组件,主要用在弹出窗口的宽度设置上,当分辨率较高时适当加宽以保证较佳的显示效果;

7) 自定义style属性,将诸如高度、间距等既需要固定值又需要根据DPI调整的地方,以这种方式绑定到css中,通过@media方式设置其值。(查看SDK源码发现其对Button组件icon的处理也是采用style方式实现的 所以还是得多爬爬源码啊

8) 启动时所显示的图片,如果在应用程序mxml文件里通过 splashScreenImage 指定1个图片的话(同时通过 splashScreenScaleMode 设置拉伸方式),则在某几个分辨率下,图片拉伸后的效果是欠佳的。

Flex移动skin – 第2部分:处理不同的像素密度Dynamic Splash Screen Improvements   中提到的方法经过实践,无法通过编译,可能是SDK(版本应该是4.6.0的)不同的缘故。根据文章提供的思路,目前我采用以下方法来解决:

注:FlexSDK v4.6.0中已经添加了 SplashScreenImage、SplashScreenImageSource,以下方法仅适用于 4.5.x 版本,当运行于 4.6.0 环境时,启动界面会出现2次,第2次所显示的图片有点不正确,有空白出现这个问题MS是另外写了个首页导致的)。

a) 复制spark.preloaders.SplashScreen 为1个新类,application 的 preloader 属性设为该新类,splashScreenScaleMode 属性可用可不用(依赖于你对SplashScreen所进行的改动);

b) 新类相较于原SplashScreen类,主要改动 initialize() 方法中 if ("splashScreenImage" in info) 处,原 splashScreenImage 值是1个固定的图片source,这里要把它改成根据不同的dpi、分辨率来得到其图片source,所以我在 if ("splashScreenImage" in info) 之前增加了获取图片source的逻辑,同时对 if ("splashScreenImage" in info) 这个语句也进行了相应修改,修改后的代码片段示例如下:

public function initialize():void
{
    ...
    if (!info)
        return;

    // 以下是我增加的
    var runtimeDPIClass:Class = info["runtimeDPIProvider"];
    var runtimeDPIProvider:RuntimeDPIProvider = new runtimeDPIClass();
    buildSplashImage(runtimeDPIProvider.runtimeDPI);

    // 原if改为如下
    // if ("splashScreenImage" in info)
    if (splashImage != null)
    {
        // 注释掉以下5行
        /*var SplashImageClass:Class = info["splashScreenImage"]; 
        this.splashImage = new SplashImageClass();
        this.splashImageWidth = splashImage.width;
        this.splashImageHeight = splashImage.height;
        addChild(splashImage as DisplayObject);*/
        
        ...
}

// 根据不同的dpi获取不同的图片源
private function buildSplashImage(dpi:Number):void
{
    // 具体的图片源逻辑主要通过类 MultiDPISplashScreen 的 getImageClass 方法中进行处理,这里就不贴源码了
    var splashImageClass:Class = new MultiDPISplashScreen().getImageClass(dpi);
    splashImage = new splashImageClass();
    if (splashImage != null)
    {
        splashImageWidth = splashImage.width;
        splashImageHeight = splashImage.height;
        addChild(splashImage as DisplayObject);		
    }
}
 

 

总之,Adobe 对开发mobile应用的支持还是很不错的,本身提供的模拟器在调试UI方面比较完善,常见的设备均有,并且也可以自行添加,显示效果与真机相仿,为我们调试在不同设备的显示效果提供了良好的支持。

另外,这个模拟器虽然只是提供了一个显示屏幕和menu、back、search按钮、旋转屏幕功能,但也是因为这样使得它在PC上运行的速度较快,不像Android模拟器那样耗资源。

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics