Android多分辨率专题研究

来源:互联网 发布:prohub软件下载 编辑:程序博客网 时间:2024/06/06 06:53
多分辨率的适配问题研究

什么是多分辨率适配?
Android 多机型导致多分配率适配

常用解决方案:
1.简单 做张大图,缩放

2.完善 做大中小三种图,再按照DP做三个质量的图 根据机型、分辨率决定使用哪个图 一般能在布局里自动匹配到4,5个常用的布局就不错了。

xxhdpi 144*144
xhdpi  96*96
hdpi   72*72
mdpi   48*48


通常的做法:对于Icon图片,就是做多种屏幕密度的图片尺寸,hdpi,mdpi,ldpi,xhdpi,如果横竖屏有要求的还可以针对landscape和portrait做特殊布局和图片处理,对于背景等填充型的图片,可以用.9格式的图片,,还需要根据经验,通过一些控件的属性,防止图片被拉伸变形,除此之外呢,在写布局的时候,要多用wrap_content和fill_parent等,尽量少用或者不用绝对布局.

用我之前做过的方法就是:如果你要适配N多机型的话,可以试下本来要用一张大图片的,可以用一条线来代替,在防止加载图片过多的情况下,如果你的背景比你的线宽高都大的话,线是会自动复制、自动扩充的!!!线可以是一张图片,如果你颜色值把握的好的话,可以直接写color.xml文件来实现哦...吼吼

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厂商修改的完全一致。
2. 第二种解决方案:
2、布局的适配:
在第1点中我们已经解决了资源图片的适配问题,但是图片的大小不同势必会造成布局的差异,如果使用一个统一的布局文件,可能会造成资源图片无法完整显示在屏幕内,所以对于这种问题,解决方法是建立不同的layout文件夹,对于不同屏幕的分辨率,书写其专用的.xml文件。
多个layout文件夹在命名上有相应规则,以分辨率480x854为例,需要建立480x854像素的layout文件夹,命名:layout-854x480,有两点需要注意:①大数(854)必须在前,否则会报错;②两个数字之间的符号是小写英文字母“x”,不是乘号。系统会根据机器的分辨率来分别到这几个文件夹里面去找对应的布局文件。

Android多分辨率适配
基本概念 

屏幕大小:以屏幕对角线的物理长度来衡量屏幕的大小 

分辨率:屏幕中所有物理像素点数。如320x480,就表示宽方向有320个像素,高方向有480个像素,整个屏幕有153,600个像素。

屏幕密度:dpi(dots per inch),即像素密度,每英寸面积上存在多少个像素。160dpi表示单位面积上有160个像素,240dpi表示单位面积上有240个像素。 屏幕的密度是由分辨率和屏幕大小(物理尺寸)决定的,320x480的分辨率在3寸的屏幕上与6寸的屏幕上密度是不同的。 

dp(dip, Desity-independent pixel):密度无关像素,在Android中经常使用。android将160dp作为一个标准(即单位面积上有160个像素点时),此时1dp=1px;当将1dp放到240dp的屏幕上去时,android就会自动将1dp调整为1.5px的大小。而在美工给出的高保真一般是px,要根据给出的高保真的密度,换算到dp, 公式:

px = dp * (dpi / 160)

android将所有的密度泛化为:ldpi, mdpi, hdpi。

将屏幕大小泛化为small, normal, large, xlarge(extra large)。 

多分辨率的适配需要在AndroidManifest.xml文件中添加子元素

<support-screens
    android:smallScreens="false" 
    android:normalScreens="false" 
    android:largeScreens="false" 
    android:xlargeScreens="false" 
    android:anyDensity="false" 
/>

       android:anyDensity="true" ,表示应用程序当安装在不同密度的手机上时,程序会分别加载hdpi,mdpi,ldpi文件夹中的资源。如果值为false,即使在hdpi,mdpi,ldpi文件夹下拥有同一种资源,那么应用也不会自动地去相应文件夹下寻找资源,应用会将大小密度转变成中密度,从而去加载mdpi中的资源。
总结如下:
第一:android:anyDensity="true",系统会依据屏幕密度,自动去找对应的文件夹
第二:android:anyDensity="false",
如果drawable-hdpi,drawable-mdpi,drawable-ldpi三个文件夹中有同一张图片资源的不同密度表示,那么系统会去加载drawable_mdpi文件夹中的资源
如果drawable-hpdi中有高密度图片,其它两个文件夹中没有对应图片资源,那么系统会去加载drawable-hdpi中的资源。
如果drawable-hdpi,drawable-mdpi中有图片资源,drawable-ldpi中没有对应的图片资源,那么系统会加载drawable-mdpi文件夹中的资源

常见文件夹命名
drawable-hdpi 该图片即适用于横屏,也适用于竖屏
drawable-land-hdpi,当屏幕为横屏,且为高密度时,加载此文件夹中的资源
drawable-port-hdpi,当屏幕为竖屏,且为高密度时,加载此文件夹中的资源

代码内动态设置值

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

国际化问题

   有时在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));


屏幕密度,分辨率等数据获取和转换

//DisPlayMetrics对象获取
DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics(); 
 // density比例,160dpi为1,240dpi为1.5(以160dpi为标准,240/160dpi)
displayMetrics.density;
 // 屏幕密度。160dpi,240dpi等 
displayMetrics.densityDpi;
// 字体缩放比例 

displayMetrics.scaledDensity; 
// 高上有多少个像素
displayMetrics.heightPixels;  
// 宽上有多少个像素
displayMetrics.widthPixels;  

 // 以dp值来表示的宽 
displayMetrics.xdpi;
// 以dp值来表示的高
displayMetrics.ydpi; 

以下是我对适应多屏幕的笔记,你看一下有帮助不:
对于 ldpi (low), mdpi (medium), hdpi (high), and xhdpi (extra high)
4种像素密度,先以正常 mdpi(像素密度为160)为基准做(此时密度和像素1:1),
做好后,其他的图片遵循 3:4:6:8 的比例放到各自目录(4是已经做好了的);
做界面时单位用DP和SP,要使用weight权重
注意:以上只是保证不同屏幕上的同一图片看起来物理大小一样,
并不是说按比例放大缩小。
如何解决尺寸不同造成比例不协调的问题?答:用不同的布局文件:like layout-xlarge
在不同的布局里定义不同大小的长宽dp.
xlarge 屏幕至少 960dp x 720dp(注意单位,不是像素。小米手机的是:569dpX320dp, 240dpi)
large 屏幕至少 640dp x 480dp
normal 屏幕至少 470dp x 320dp
small 屏幕至少 426dp x 320dp

简要概括:
1.drawable做3:4:6:8的比例来让不同密度屏幕上看起来物理大小一样
2.不同layout里定义不同的长宽使不同屏幕尺寸看起来比例协调
一个是密度,一个是尺寸


以下为一些屏幕参数术语,搞android的苦逼同行们,让多分辨率适配来的更猛烈些吧~

1、屏幕大小

屏幕实际的大小,通过测量屏幕对角线长度获得,通常用inch表示。Android将屏幕分为了4个档次:small、normal、large、xlarge。

2、屏幕分辨率
屏幕实际显示的像素数。

3、屏幕密度(PPI:Pixels per Inch)
屏幕每英寸的最大像素数(硬件层面的参数)。可通过公式进行计算:
W:横向最大像素数

H:纵向最大像素数

L:屏幕对角线长度(即前面说的屏幕大小)

4、屏幕密度(DPI:Dots per Inch)
屏幕每英寸实际显示的点数(或像素数)。属于软件参数,是手机厂商内部指定的。
App:Screen&System
Code:getResources().getDisplayMetrics().density * 160

5、密度无关的像素(DP:Density-independent pixel)
Android定义的逻辑长度单位,跟屏幕像素无关。跟像素转换的关系为:
dp = px * 160 / dpi。

6、字体大小
sp:Scale-independent Pixels。用于屏幕字体大小。类似于dp,是屏幕密度独立的单位。
在字体中,除了设置的sp会影响大小外,还有字体的类型也会对其有影响。

总结一下Android开发中适配性的问题,首先对于控件间距和大小最好使用屏幕密度dip去做,这样可以避免太大的差异
获取屏幕密度方法;
DisplayMetrics dm = new DisplayMetrics(); 
dm = getResources().getDisplayMetrics(); 
int screenWidth = dm.widthPixels; 
int screenHeight = dm.heightPixels; 
float density = dm.density; 
float xdpi = dm.xdpi; 
float ydpi = dm.ydpi;
下面是在manifest中设置app在不同分辨率时,是否支持多密度的方法。
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
...
<supports-screens
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:xlargeScreens="true"
android:anyDensity="true" />
</manifest>
根据google的推荐,像素统一使用dip,字体统一使用sp
对于固定屏幕大小的可以在res目录下建立多个layout文件夹,文件夹名称为layout-800x480等。需要适应那种分辨率就写成什么。
注意:
         a.   较大的数字要写在前面:比如layout-854x480而不能写layout-480x854.
         b.   两个数字之前是小写字母x,而不是乘号
对于图片缩放基本两种方法;
方法一;
 private Bitmap mBitmap;
        public ScaledBitmapView(Context context, Bitmap bitmap) {
            super(context);
            mBitmap = bitmap;
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            final DisplayMetrics metrics = getResources().getDisplayMetrics();
            setMeasuredDimension(
                    mBitmap.getScaledWidth(metrics),
                    mBitmap.getScaledHeight(metrics));
        }
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawBitmap(mBitmap, 0.0f, 0.0f, null);
        }
方法二;
 //对于不同分辨率屏幕缩放方法
private static int getValues_w(float value_x,int width)

return Math.round(value_x/480*width);
}

private static int getValues_h(float value_y,int height)
{
return Math.round(value_y/800*height);
}

dp与px转换的方法:
public static int dip2px(Context context, float dipValue){
  final float scale = context.getResources().getDisplayMetrics().density;
  return (int)(dipValue * scale +0.5f);
}
public static int px2dip(Context context, float pxValue){
  final float scale = context.getResource().getDisplayMetrics().density;
  return (int)(pxValue / scale +0.5f);

}


原创粉丝点击