您的位置:首页 > 移动开发 > Android开发

android 屏幕适配问题

2013-05-27 18:09 267 查看
Eclipse运行项目报错(Error):Conversion to Dalvik format failed with error 1

ADT在线安装

android 屏幕适配问题

2012-11-09 16:13:42| 分类:

Android | 标签:android
屏幕适配
分辨率
|字号大中小
订阅



如何将一个应用程序适配在不同的手机上,虽然这不算是一个技术问题,但是对于刚刚做屏幕的开发人员来说,还真不是一件多么简单的事情。

首先:你需要在AndroidManifest.xml文件的<manifest>元素如下添加子元素
<supports-screens android:largeScreens="true"
android:normalScreens="true" android:anyDensity="true"
android:smallScreens="true"></supports-screens>

名如其意,以上是为我们的屏幕设置多分辨率支持(更准确的说是适配大、中、小三种密度)。android:anyDensity="true" ,这一句对整个的屏幕都起着十分重要的作用,值为true,我们的应用程序当安装在不同密度的手机上时,程序会分别加载hdpi,mdpi,ldpi文件夹中的资源。
相反,如果值设置为false,即使我们在hdpi,mdpi,ldpi文件夹下拥有同一种资源,那么应用也不会自动地去相应文件夹下寻找资源,这种情况都是出现在高密度,以及低密度的手机上,比如说一部240×320像素的手机,如果设置android:anyDensity="false",Android系统会将240 x 320(低密度)转换为 320×480(中密度),这样的话,应用就会在小密度手机上加载mdpi文件中的资源。

2.细心的人会发现自android2.0开始之后drawable文件被三个文件夹drawable-hdpi,drawable-mdpi,drawable-ldpi三个文件夹所取代,有些编程人员为了让应用程序默认地加载某些图片,他们会特意地去在android2.0之后的应用程序中重新创建drawable文件夹,其实这样做完全没有必要,通过第一段的分析我们得知,android:anyDensity="false",则应用会将大小密度转变成中密度,从而去加载mdpi中的资源。这里同样,当android:anyDensity="false",则应用会去加载mdpi中的资源。
总结一下:
第一:android:anyDensity="true",系统会依据屏幕密度,自动去找对应的文件夹
第二:android:anyDensity="false",
(1) 如果drawable-hdpi,drawable-mdpi,drawable-ldpi三个文件夹中有同一张图片资源的不同密度表示,那么系统会去加载drawable_mdpi文件夹中的资源
(2) 如果drawable-hpdi中有高密度图片,其它两个文件夹中没有对应图片资源,那么系统会去加载drawable-hdpi中的资源。
(3) 如果drawable-hdpi,drawable-mdpi中有图片资源,drawable-ldpi中没有对应的图片资源,那么系统会加载drawable-mdpi文件夹中的资源

3. 注意上图各种文件夹的不同表示。
drawable-hdpi 该图片即适用于横屏,也适用于竖屏
drawable-land-hdpi,当屏幕为横屏,且为高密度时,加载此文件夹中的资源
drawable-port-hdpi,当屏幕为竖屏,且为高密度时,加载此文件夹中的资源

3. 有时候会根据需要在代码中动态地设置某个值,比如地图,地图的pin和地图的地址提示框的相对偏移量在不同密度的手机上是不同的。这时候可以通过以下方法求出屏幕密度:

DisplayMetrics metric = new DisplayMetrics();

getWindowManager().getDefaultDisplay().getMetrics(metric);
int densityDpi = metric.densityDpi;
// 屏幕密度DPI(120 / 160 / 240)

然后可以在代码中为这几种密度分别设置便宜量

但是这种方法最好不要使用,最好的方式是在xml文件中不同密度的手机进行分别设置。
这里地图的偏移量可以在values-hpdi,values-mdpi,values-ldpi三种文件夹中的dimens.xml文件进行设置
值得一提的是:
<dimen name="bitmap_common_topoffset">40dp</dimen>
<dimen name="bitmap_common_bottomoffset">-14dp</dimen>
这里的负数是完全起作用的,系统会认为它是一个负值

4. 各大手机厂商对于Android操作系统都有或多或少的改动,当然这些改动会对我们应用程序产生某些影响
比如:

(1)系统源代码中连接music服务的aidl文件所在包名:com.android.music

(2)LG则可能将该aidl文件修改所在的包(例如修改为 com.android.music.player),并且修改其中的文件内容(增加一个方法,或者减少几个方法,或者修改方法名称)那么我们的应用要想在LG的手机上发布,那么我们就必须改变所要连接的aidl文件,必须跟LG厂商修改的完全一致。

5. 国际化问题.
有时候在xml中设置了相应的语言,但是为什么当我们更改语言之后,UI显示仍然不起作用?
不要怀疑是系统出了问题,这与我们在代码中引用values/string.xml中字符串的方式有关。
错误的方式:
1. 声明全局变量 private static String tempStr;
2. 在onCreate方法中对该变量赋值 tempStr = context.getString(R.string.test);
3. 在更新UI的方法(非onCreate方法)中引用该变量。 textView.setText(tempStr);
原因是由于,当修改本地语言时,onCreate不会再被执行一遍. 变量tempStr 依然会使用页面刚启动时加载的默认英语。

正确的方式:
直接进行第三步:textView.setText(context.getString(R.string.test));

Android 获取屏幕尺寸与密度

    遇到一个问题,我的地图浮标图片在WVGA手机上正好,在QVGA上就显的太大,所以我要根据屏幕的不同调整浮标的大小使其在QVGA大小合适。有的同事提出了依据分辨率来区分不同的屏幕,但是单WVGA就支持好几种不同的分辨率,QVGA又支持好几种。。。而且更神奇的时候,有时候,通过代码获取屏幕分辨率竟然得到了
320 x 427 ,Android文档是不支持这种分辨率的,所以依据分辨率来区分不同的屏幕是行不通的。

    还好通过仔细研读文档,“各种VGA的density是不同的,(hdpi: 240 , ldpi: 120 , mdpi: 160 , xhdpi: 320)”,所以只要求出不同屏幕的density,就可以知道该手机属于的屏幕类型。

首先是几个基本概念:
1.屏幕尺寸Screen size
即显示屏幕的实际大小,按照屏幕的对角线进行测量。
为简单起见,Android把所有的屏幕大小分为四种尺寸:小,普通,大,超大(分别对应:small, normal, large, and extra large).
应用程序可以为这四种尺寸分别提供不同的自定义屏幕布局-平台将根据屏幕实际尺寸选择对应布局进行渲染,这种选择对于程序侧是透明的。
2.屏幕长宽比Aspect ratio
长宽比是屏幕的物理宽度与物理高度的比例关系。应用程序可以通过使用限定的资源来为指定的长宽比提供屏幕布局资源。
3.屏幕分辨率Resolution
在屏幕上显示的物理像素总和。需要注意的是:尽管分辨率通常用宽x高表示,但分辨率并不意味着具体的屏幕长宽比。
在Andorid系统中,应用程序不直接使用分辨率。
4.密度Density
根据像素分辨率,在屏幕指定物理宽高范围内能显示的像素数量。
在同样的宽高区域,低密度的显示屏能显示的像素较少,而高密度的显示屏则能显示更多的像素。
屏幕密度非常重要,因为其它条件不变的情况下,一共宽高固定的UI组件(比如一个按钮)在在低密度的显示屏上显得很大, 而在高密度显示屏上看起来就很小。
为简单起见,Android把所有的屏幕分辨率也分为四种尺寸:小,普通,大,超大(分别对应:small, normal, large, and extra large).
应用程序可以为这四种尺寸分别提供不同的资源-平台将透明的对资源进行缩放以适配指定的屏幕分辨率。

[b]密度无关的像素( DIP )

指一个抽象意义上的像素,程序用它来定义界面元素。它作为一个与实际密度无关的单位,帮助程序员构建一个布局方案(界面元素的宽度,高度,位置)。

一个与密度无关的像素,在逻辑尺寸上,与一个位于像素密度为 160DPI的屏幕上的像素是一致的,这也是Android平台所假定的默认显示设备。在运行的时候,平台会以目标屏幕的密度作为基准,“透明地”处理所 有需要的DIP缩放操作。要把密度无关像素转换为屏幕像素,可以用这样一个简单的公式: pixels = dips * (density / 160)。举个例子,在 DPI为 240的屏幕上, 1个 DIP等于 1.5个物理像素。我们强烈推荐你用 DIP来定义你程序的界面布局,因为这样可以保证你的 UI在各种分辨率的屏幕上都可以正常显示[/b]


在一个Activity的onCreate方法中,写入如下代码:


DisplayMetrics metric = new DisplayMetrics();

getWindowManager().getDefaultDisplay().getMetrics(metric);

int width = metric.widthPixels;
// 屏幕宽度(像素)

int height = metric.heightPixels;
// 屏幕高度(像素)

float density = metric.density;
// 屏幕密度(0.75 / 1.0 / 1.5)

int densityDpi = metric.densityDpi;
// 屏幕密度DPI(120 / 160 / 240)

但是,需要注意的是,在一个低密度的小屏手机上,仅靠上面的代码是不能获取正确的尺寸的。比如说,一部240x320像素的低密度手机,如果运行上述代码,获取到的屏幕尺寸是320x427。因此,研究之后发现,若没有设定多分辨率支持的话,Android系统会将240x320的低密度(120)尺寸转换为中等密度(160)对应的尺寸,这样的话就大大影响了程序的编码。所以,需要在工程的AndroidManifest.xml文件中,加入supports-screens节点,具体的内容如下:

<supports-screens

android:smallScreens="true"

android:normalScreens="true"

android:largeScreens="true"

android:resizeable="true"

android:anyDensity="true"/>

这样的话,当前的Android程序就支持了多种分辨率,那么就可以得到正确的物理尺寸了。

// 获取屏幕密度(方法1)
int screenWidth = getWindowManager().getDefaultDisplay().getWidth();
// 屏幕宽(像素,如:480px)
int screenHeight = getWindowManager().getDefaultDisplay().getHeight();
// 屏幕高(像素,如:800p)

Log.e(TAG + " getDefaultDisplay",
"screenWidth=" + screenWidth + "; screenHeight=" + screenHeight);

// 获取屏幕密度(方法2)
DisplayMetrics dm = new DisplayMetrics();

dm = getResources().getDisplayMetrics();

float density = dm.density;
// 屏幕密度(像素比例:0.75/1.0/1.5/2.0)
int densityDPI = dm.densityDpi;
// 屏幕密度(每寸像素:120/160/240/320)
float xdpi = dm.xdpi;
float ydpi = dm.ydpi;

Log.e(TAG + " DisplayMetrics",
"xdpi=" + xdpi + "; ydpi=" + ydpi);
Log.e(TAG + " DisplayMetrics",
"density=" + density + "; densityDPI=" + densityDPI);

screenWidth = dm.widthPixels; // 屏幕宽(像素,如:480px)

screenHeight = dm.heightPixels; // 屏幕高(像素,如:800px)

Log.e(TAG + " DisplayMetrics(111)",
"screenWidth=" + screenWidth + "; screenHeight=" + screenHeight);

// 获取屏幕密度(方法3)
dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);

density = dm.density; // 屏幕密度(像素比例:0.75/1.0/1.5/2.0)

densityDPI = dm.densityDpi; // 屏幕密度(每寸像素:120/160/240/320)

xdpi = dm.xdpi;
ydpi = dm.ydpi;

Log.e(TAG + " DisplayMetrics",
"xdpi=" + xdpi + "; ydpi=" + ydpi);
Log.e(TAG + " DisplayMetrics",
"density=" + density + "; densityDPI=" + densityDPI);

int screenWidthDip = dm.widthPixels;
// 屏幕宽(dip,如:320dip)
int screenHeightDip = dm.heightPixels;
// 屏幕宽(dip,如:533dip)

Log.e(TAG + " DisplayMetrics(222)",
"screenWidthDip=" + screenWidthDip + "; screenHeightDip=" + screenHeightDip);

screenWidth = (int)(dm.widthPixels * density +
0.5f); // 屏幕宽(px,如:480px)

screenHeight = (int)(dm.heightPixels * density +
0.5f); // 屏幕高(px,如:800px)

Log.e(TAG + " DisplayMetrics(222)",
"screenWidth=" + screenWidth + "; screenHeight=" + screenHeight);

重中之重:
density值表示每英寸有多少个显示点,与分辨率是两个不同的概念:

Android主要有以下几种屏:

QVGA和WQVGA屏density=120;

HVGA屏density=160;

WVGA屏density=240;

下面以480dip*800dip的WVGA(density=240)为例,详细列出不同density下屏幕分辨率信息:

当density=120时 屏幕实际分辨率为240px*400px (两个点对应一个分辨率)

状态栏和标题栏高各19px或者25dip

横屏是屏幕宽度400px 或者800dip,工作区域高度211px或者480dip

竖屏时屏幕宽度240px或者480dip,工作区域高度381px或者775dip

density=160时 屏幕实际分辨率为320px*533px (3个点对应两个分辨率)

状态栏和标题栏高个25px或者25dip

横屏是屏幕宽度533px 或者800dip,工作区域高度295px或者480dip

竖屏时屏幕宽度320px或者480dip,工作区域高度508px或者775dip

density=240时 屏幕实际分辨率为480px*800px (一个点对于一个分辨率)

状态栏和标题栏高个38px或者25dip

横屏是屏幕宽度800px 或者800dip,工作区域高度442px或者480dip

竖屏时屏幕宽度480px或者480dip,工作区域高度762px或者775dip

apk的资源包中,当屏幕density=240时使用hdpi标签的资源

当屏幕density=160时,使用mdpi标签的资源

当屏幕density=120时,使用ldpi标签的资源。

不加任何标签的资源是各种分辨率情况下共用的。

建议:布局时尽量使用单位dip,少使用px。

device independent pixels(设备独立像素). 不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA、HVGA和QVGA 推荐使用这个,不依赖像素。

果想在不同型号手机对同一个应用做适配,如果你在xml中全部使用dp没有使用px,那么适配上依然很有可能出问题!



无数人存在误区,认为自己使用的都是dp,为什么在手机A上面和手机B上面看上去比例不一样,为什么在A手机上显示正好而手机B上却显示到屏幕外面

每次解释的都很累,所以写此blog

首先先明确几个概念

density值表示每英寸有多少个显示点(*)

dip/dp: device independent pixels(设备独立像素)

注意:dip与屏幕密度有关,屏幕密度与硬件有关,硬件设置不正确,有可能导致dip不能正常显示。在屏幕密度为160的显示屏上,1dip=1px

下面是一些分辨率信息

名称分辨率屏幕密度
QVGA320*240120
WQVGA400400*240120
WQVGA432432*240120
HVGA640*480160
WSVGA1024*600160
WXGA8001280*800160
WVGA800800*480240
WVGA854854*480240
WXGA7201280*720320
下面没有特殊说明的话,屏幕的宽度都指其像素数

我们在手机A上面放了一张图片,120px宽,手机屏幕240px宽,也就是说图片的宽度占了整个屏幕的一半

如果把应用安装在手机B上,B的宽度=320px,那么我们希望图片宽度为多少呢?如果大家希望按着比例缩放,那图片宽度应该是160px,占屏幕宽度的50%

如果我们在xml中使用的单位为dp,下面看看如何保持这个比例:

px = (density/160)dp(density这里是(*)的意思)

我们把所期待的比例记为rate,baseDensity=160,屏幕的宽度(像素数)为x,屏幕密度为density

那么rate=((density/baseDensity)*dp)/x;

这里baseDensity是已知的=160,dp也是已知的,因为是你写的嘛。

未知的是density屏幕密度和屏幕宽度x

rate可以写为:

rate=(dp/baseDensity)*(density/x);

现在情况就比较明朗了,rate=K(常数)*(density/x);


如果想保持rate不变,那么需要保证density/x保持比例

给数学不好的同学多解释两句

想保持rate的话,必须要手机A的屏幕密度/屏幕宽度=手机B的屏幕密度/屏幕宽度

或者说手机A的屏幕密度/手机B的屏幕密度=手机A的屏幕宽度/手机B的屏幕宽度

同样,如果你要保持纵向也保持等比缩放,那么也同样需要保持比例。

只有这样,你的应用才能看上去是等比缩放的。

使用dp保持比例只和这些有关,和你屏幕大小半点关系都没有。

还有另一种方式来保持比例:就是直接使用比例方式定义组件大小

但是很有局限性,只有LinearLayout中可以使用android:layout_weight属性

其实很容易理解,给大家举个例子

很多人觉得,如果项目中全部使用dp,那么就可以完美移植。

我们的一个移植项目,任务是把应用从A(分辨率为WXGA720=1280*720)移植到B(分辨率WVGA800=800*480)

其中A的密度=320,B的密度为240

我们现在来看看A横向有多少个dp

A dp数=720/(320/160)=360

B dp数=480/(240/160)=320

手机A横向有360个dp,如果你的图片占用360个dp,B去哪找你多出来的40dp呢!必然它会显示在屏幕外面阿!

ps:下面是一点相关内容

下面是函数void android.util.DisplayMetrics.setToDefaults()

public void setToDefaults() {

widthPixels = 0;

heightPixels = 0;

density = DENSITY_DEVICE / (float) DENSITY_DEFAULT;

densityDpi = DENSITY_DEVICE;

scaledDensity = density;

xdpi = DENSITY_DEVICE;

ydpi = DENSITY_DEVICE;

noncompatWidthPixels = 0;

noncompatHeightPixels = 0;

}

复制代码
其中density变量注释如下

density变量注释 写道

float android.util.DisplayMetrics.density

The logical density of the display.

This is a scaling factor for the Density Independent Pixel unit, where one DIP is one pixel on an approximately 160 dpi screen (for example a 240x320, 1.5"x2" screen), providing the baseline of the system's display.

Thus on a 160dpi screen this density value will be 1; on a 120 dpi screen it would be .75; etc.

This value does not exactly follow the real screen size (as given by xdpi and ydpi, but rather is used to scale the size of the overall UI in steps based on gross changes in the display dpi.

For example, a 240x320 screen will have a density of 1 even if its width is 1.8", 1.3", etc.

However, if the screen resolution is increased to 320x480 but the screen size remained 1.5"x2" then the density would be increased (probably to 1.5).

See Also:

DENSITY_DEFAULT

复制代码
粗略的翻译了一下:

浮android.util.DisplayMetrics.density

逻辑密度的显示。

这是一个比例因子的密度独立像素单元,其中一个是一个像素上蘸一个大约160 dpi屏幕(例如240 x320,1.5 " x2 "屏幕),提供基线系统的显示。

因此在一个160 dpi屏幕这密度值是1;在一个120 dpi屏幕会。75;等等。

这个值并不完全遵循真正的屏幕大小(由xdpi和ydpi,而是用来规模大小的整体UI在步骤基于总改变显示dpi。

例如,一个240 x320屏幕将会有一个密度的1即使它的宽度为1.8”,1.3”,等等。

然而,如果屏幕分辨率是增加到320 x480,但是屏幕大小保持1.5 " x2”然后密度会增加(可能是1.5)。

参见:

密度默认

复制代码

注:如果没有指定横屏或竖屏,则上面的布局和位图都适配横竖屏。如果要指定横屏,例如:drawable-land-hdpi竖屏drawable-port-hdpi,还有关键是drawable-xlarge和layout-xlarge,对api level都要求在9之上,等于说,你用android2.2系统的平板或者手机根本不匹配layout-xlarge。因为api level是8。drawable-tvadpi这个api等级需要13以上。

其实上面的layout-large这个目录其实是个范围。当系统根据当前屏幕的大小和密度,决定程序应该匹配那个目录。你也可以单独定制某些不符合谷歌标准的山寨版layout-l024x600(中间的符合是英文下的x字母),其中1024和600的单位是dp。你可以根据你设备的分辨率和密度,来判断你的设备需要定义那个文件。

但是,官方推荐使用尺寸来表示资源layout-large,不推荐使用分辨率layout-1024*600。

建议大家多看文档,官方说明:

xlarge screens are at least 960dp x 720dp

large screens are at least 640dp x 480dp

normal screens are at least 470dp x 320dp

small screens are at least 426dp x 320dp

上面是定义广义大小布局资源适配的一个范围,大家可以根据自己的设备知道系统会匹配那个文件的布局。

如果手上有个山寨华为的卖的比较火的mediapad,大家知道分辨率1280*800 密度尺寸7寸

通过勾股定了和分辨率可以得出其密度为215.69。然后根据dp=px/(dpi/160),可以得出个范围593.471。所以这个设备系统会匹配layout-large这个资源布局文件。

严格来说,作为读者,你应该带着批判性质的眼光来看这篇文章,因为这篇文章是一个尚未通读Android官方开发资料《Supporting Multiple Screens》的纯产品人员所写,相关理解来源于零星的资料、实践以及和开发人员的沟通,此文章更多为目前盆地个人理解的总结。我会给自己定下目标,早日通读官方资料,此文中的相关错误,也请予以指正。

一、Android支持的多种屏幕

传统意义上,一般是是这么认为的:

ldpi: 对应分辨率240×320

mdpi: 对应分辨率320×480

hdpi:对应分辨率480×800或480×854

但实际上没有这么简单,直接看官方资料的下标,可以看到其实ldpi一样由480×800,甚至还有1024×600

低密度(ldpi 120)中密度(mdpi 160)高密度(hdpi 240)超高密度(320 xhdpi)
小屏幕QVGA (240×320)480×640
中屏幕WQVGA400 (240×400)

WQVGA432 (240×432)
HVGA (320×480)WVGA800 (480×800)

WVGA854 (480×854)

600×1024
640×960
大屏幕WVGA800** (480×800)

WVGA854** (480×854)
WVGA800* (480×800)

WVGA854* (480×854)

600×1024
超大屏幕1024×600WXGA (1280×800)

1024×768

1280×768
1536×1152

1920×1152

1920×1200
2048×1536

2560×1536

2560×1600

二、如何分辨是ldpi、mdpi、hdpi?

为什么要分辨率ldpi、mdpi、hdpi?我的理解,是为了要在不同的屏幕密度下取得最好的显示效果。

从上一段来看,通过分辨率来看并不是很靠谱,那怎么样才靠谱?其实,只要我们知道屏幕分辨率、屏幕尺寸(对角线长度),就可以算出相应的屏幕密度,从而根据其范围得出属于那种屏幕密度。

我们可以根据长或者根据宽来计算出dpi,计算公式为:

dpi=宽/((尺寸^2 * 宽^2)/(宽^2 + 高^2))^(1/2)

= 长/((尺寸^2 * 长^2)/(宽^2 + 高^2))^(1/2)

此计算公式可以在excel中予以计算。

大概计算方法如下,以宽为例:

1.比如分辨率为320×480,则长宽比为1:1.5

2.比如屏幕尺寸为3.6”,则根据勾股定理,”长^2+宽^2=3.6^2″,即”宽^2+2.25*宽^2=12.96″,得出”宽^2=12.96/3.25″,则”宽=(12.96/3.25)^(1/2)= 1.9969″

3.宽为320px,分布在1.9969”上,因此密度为320/1.9969=160.2467

4.因此此密度为mdpi的密度

注:

1.此部分参考文章为:http://blog.sina.com.cn/s/blog_7377a8a20100qydh.html

2.两款计算dpi的应用

https://market.android.com/details?id=appinventor.ai_wenjiun1024.DPICalculato

https://market.android.com/details?id=com.andy.dpi

三、粗略的分辨率ldpi 、mdpi、hdpi

套用老资料,其实传统意义上的通过分辨率判断手机dpi,还是比较靠谱的:

ldpi: 对应分辨率240×320

mdpi: 对应分辨率320×480

hdpi:对应分辨率480×800或480×854

为什么呢?因为ldpi如果要是320×480,则需要4.8寸的屏幕,如果是480×800,则需要7.8寸的屏幕,如果mdpi是480×800,则需要5.2寸的屏幕,一般的手机屏幕不会这么大,所以还算靠谱。

当然,如果是分辨android pad的dpi,建议还是算一下吧。

四、如何适配之9-patch?

官方资料:http://developer.android.com/guide/developing/tools/draw9patch.html

简单来说,如果你的图片资源是可以拉伸的而不会变形或者模糊的,则完全可以使用9-patch的格式,而不用为不同的dpi提供不同的图片资源。

此格式经常用在背景性质的图片资源中。

android开发包提供了9-patch的制作工具,上方的划线指明横向可以拉伸的区域,左方的划线指明纵向可以拉伸的区域,下方的划线指明水平居中的区域,右方的划线指明垂直居中的区域。

盆地的理解中,一般提供hdpi大小的图片,并制作为9-patch格式,此时的拉伸在mdpi、ldpi上基本都不会带来问题。

这部分网上有不少资料,这里就不再赘述了,上述的描述是为了盆地日后便于想起和理解。

五、如何适配指图标和其他图片

除了指明拉伸区域拉伸不变形的图片外,类似图标或者其他会变形的图片资源,最佳情况下需要分别针对不同的dpi提供不同的图片。

此处特别需要注意的是,假设不考虑xhdpi的支持,hdpi、mdpi、ldpi的支持,需要考虑相应的比例,即1.5:1:0.75,需要在相应比例关系下保持整数的像素值,否则可能会产生模糊的情况。

举个具体例子,某个图标在hdpi下大小为48×48,则mdpi和ldpi下分别为32×32和24×24,如果此图标在hdpi设定为50×50,则mdpi下50无法整除1.5,因此mdpi下图标不论图标设定为33×33还是34×34都会模糊(可能独立指定可以避免此情况,此部分不太了解)。

六、菜单图标和应用图标

这一部分在官方资料中描述的很全面,只是不少应用开发者没有按照规范来,比如桌面图标的在hdpi上分辨率虽然定义的是72×72,但实际上应该只占60×60(如果是正方形,则应该是56×56),而不少应用直接把图标设定为72×72,所以会发现android中很多图标比系统的图标大一些,就是这个缘故。

这一部分就直接参照官方文档吧,做法上也就是做三份,只是需要遵照文档来。

http://developer.android.com/guide/practices/ui_guidelines/icon_design.html

七、小结

作为产品人员,了解这个的目的,是为了向UI人员协调相应的UI资源,以及和开发保持顺畅的沟通,如果不了解这个,可能事倍功半,所以,作为产品人员,还是了解下吧。

恩,暂时就这些了,等俺通读了官方文档后,再来补充吧。上述描述中错误的地方,也请不吝赐教。

(完)

如何将一个应用程序适配在不同的手机上,虽然这不算是一个技术问题,但是对于刚刚做屏幕的开发人员来说,还真不是一件多么简单的事情。

首先:你需要在AndroidManifest.xml文件的<manifest>元素如下添加子元素

<supports-screens

android:largeScreens="true"

android:normalScreens="true"

android:anyDensity="true"

android:smallScreens="true"></supports-screens>

名如其意,以上是为我们的屏幕设置多分辨率支持(更准确的说是适配大、中、小三种密度)。android:anyDensity="true"

,这一句对整个的屏幕都起着十分重要的作用,值为true,我们的应用程序当安装在不同密度的手机上时,程序会分别加载hdpi,mdpi,ldpi文件夹中的资源。

相反,如果值设置为false,即使我们在hdpi,mdpi,ldpi文件夹下拥有同一种资源,那么应用也不会自动地去相应文件夹下寻找资源,这种情况都是出现在高密度,以及低密度的手机上,比如说一部240×320像素的手机,如果设置android:anyDensity="false",Android系统会将240
x 320(低密度)转换为

320×480(中密度),这样的话,应用就会在小密度手机上加载mdpi文件中的资源。

2.细心的人会发现自android2.0开始之后drawable文件被三个文件夹drawable-hdpi,drawable-mdpi,drawable-ldpi三个文件夹所取代,有些编程人员为了让应用程序默认地加载某些图片,他们会特意地去在android2.0之后的应用程序中重新创建drawable文件夹,其实这样做完全没有必要,通过第一段的分析我们得知,android:anyDensity="false",则应用会将大小密度转变成中密度,从而去加载mdpi中的资源。这里同样,当android:anyDensity="false",则应用会去加载mdpi中的资源。

总结一下:

第一:android:anyDensity="true",系统会依据屏幕密度,自动去找对应的文件夹

第二:android:anyDensity="false",

(1)
如果drawable-hdpi,drawable-mdpi,drawable-ldpi三个文件夹中有同一张图片资源的不同密度表示,那么系统会去加载drawable_mdpi文件夹中的资源

(2)
如果drawable-hpdi中有高密度图片,其它两个文件夹中没有对应图片资源,那么系统会去加载drawable-hdpi中的资源。

(3)
如果drawable-hdpi,drawable-mdpi中有图片资源,drawable-ldpi中没有对应的图片资源,那么系统会加载drawable-mdpi文件夹中的资源

3.

注意上图各种文件夹的不同表示。

drawable-hdpi

该图片即适用于横屏,也适用于竖屏

drawable-land-hdpi,当屏幕为横屏,且为高密度时,加载此文件夹中的资源

drawable-port-hdpi,当屏幕为竖屏,且为高密度时,加载此文件夹中的资源

3.

有时候会根据需要在代码中动态地设置某个值,比如地图,地图的pin和地图的地址提示框的相对偏移量在不同密度的手机上是不同的。这时候可以通过以下方法求出屏幕密度:

DisplayMetrics metric = new DisplayMetrics();

getWindowManager().getDefaultDisplay().getMetrics(metric);

int densityDpi = metric.densityDpi;
//
屏幕密度DPI(120
/ 160 / 240)

然后可以在代码中为这几种密度分别设置便宜量

但是这种方法最好不要使用,最好的方式是在xml文件中不同密度的手机进行分别设置。

这里地图的偏移量可以在values-hpdi,values-mdpi,values-ldpi三种文件夹中的dimens.xml文件进行设置

值得一提的是:

<dimen

name="bitmap_common_topoffset">40dp</dimen>

<dimen

name="bitmap_common_bottomoffset">-14dp</dimen>

这里的负数是完全起作用的,系统会认为它是一个负值
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: