转载请注明出处,谢谢http://blog.csdn.net/harryweasley/article/details/51463232
前提:之前公司里面做的是电视应用,从来没有遇到过屏幕适配问题,这几天,公司新拿了一个盒子,每个控件尺寸变大,出现了很大的适配问题,所以我们就着手解决Android屏幕适配的问题。
在做适配前,必须要了解一下屏幕密度dpi(dots per inch),屏幕密度就是每英寸有多少个显示点,可以通过如下的方式获取到:
DisplayMetrics metric = new DisplayMetrics();
metric = getResources().getDisplayMetrics();
int width = metric.widthPixels; // 屏幕宽度(像素)
int height = metric.heightPixels; // 屏幕高度(像素)
float density = metric.density; // 屏幕密度(0.75 / 1.0 / 1.5 / 2.0)
int densityDpi = metric.densityDpi; // 屏幕密度DPI(120 / 160 / 240/ 360)
Log.i("dpiIsWhat", " width=" + width + " height=" + height
+ " densiy=" + density + " densityDpi=" + densityDpi);
注意:通过上面方法得到的长度和宽度两个中有一个有时候不准确(这主要是因为硬件厂家的问题),我们要进行一下查看,这样上下对比,来估算出正确的长度或者宽度。`就比如,我现在测试的一个设备,他的宽度和高度分别是1280*692,那么这个时候,就应该对比下面的数值,得到该设备真正的宽度和高度为1280*720
/** 市场上普通屏幕宽度 */
private static final int[] screenWidth = { 3840, 2560, 1920, 1280, 960, 800, 480 };
/** 市场上普通屏幕高度 */
private static final int[] screenHeight = { 2160, 1536, 1080, 720, 540, 480, 320 };
在屏幕密度dpi为160dpi的时候,屏幕密度比为1.0,1px=1*dp;
在屏幕密度dpi为320dpi的时候,屏幕密度比为2.0,1px=2*dp;
那么,当有一个新的Android设备,他的屏幕密度比为2.0时,同样的50dp宽度,在2.0上面就显示的是100px,所以就会超出屏幕,出现适配问题。
以下的一个xml文件
"http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.textdemo.MainActivity"
android:orientation="horizontal" >
"@+id/tv1"
android:layout_width="@dimen/m180"
android:layout_height="@dimen/m180"
android:background="@android:color/holo_blue_bright"
android:textSize="@dimen/text_s26" />
"@+id/tv2"
android:layout_width="@dimen/m180"
android:layout_height="@dimen/m180"
android:layout_marginLeft="@dimen/m60"
android:background="@android:color/holo_blue_bright"
android:textSize="@dimen/text_s26" />
</LinearLayout>
注意:可以先无视textview上的文字
显示到480*800,dpi为1.0的设备上,如下图所示:
注意:可以先无视textview上的文字
显示到720*1280,dpi为2.0的设备上,如下图所示:
我们看到同一套xml文件在不同设备上,有着不同的显示效果,这是不被允许出现的。
分别是values-sw360dp和values-sw480dp。那么这个又是什么东西呢。
values-sw360dp显示的数据是屏幕分辨率长和宽中最小的那个,大于等于360dp的。sw代表small width。
所以720*1280,dpi为2.0的设备,(长度和宽度最小的是720px,除以1.0,就是360dp。)就会先去values-sw360dp寻找是否有合适的dimens。
所以480*800,dpi为1.0的设备,(长度和宽度最小的是480px,除以1.0,就是480dp。)就会先去values-sw480dp寻找是否有合适的dimens。
注意:如果这时,没有values-sw480dp.就会向下继续寻找到values-sw360dp,如果还没有,则会进入默认的values
我们现在以dpi为1.0的设备为基础,将dpi为2.0的设备适配正确。
可以看到,dpi为2.0的设备,控件长宽变宽,我们要让其变小一些,除以某个数值,那么怎么算出这个数值呢,我下面将进行一个举例。
简单解释一下上面的图的内容,Android设备,展示到界面的控件,最终都是以px为单位的,为了让肉眼看起来,ui效果一样,在480px设备上有一个占满屏幕的红色框,那么在720px的设备上,就得是720px的长度的红色框,所以就要修改dimens下的数值。
由上图可知,将values/dimens.xml下面的所有单位除以1.3就可以得到最新数值,放入valuese-sw360dp/dimens.xml中。
所以,values-sw480dp/dimens下的内容如下所示:
<resources>
<dimen name="m180">180dpdimen>
<dimen name="m60">60dpdimen>
<dimen name="text_s26">26spdimen>
resources>
values-sw360dp/dimens下的内容如下所示:
<resources>
<dimen name="m180">138dpdimen>
<dimen name="m60">46dpdimen>
<dimen name="text_s26">20spdimen>
resources>
MainActivity里的代码如下所示:
package com.example.textdemo;
import android.app.Activity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.widget.TextView;
public class MainActivity extends Activity {
private TextView tv1, tv2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DisplayMetrics metric = new DisplayMetrics();
metric = getResources().getDisplayMetrics();
int width = metric.widthPixels; // 屏幕宽度(像素)
int height = metric.heightPixels; // 屏幕高度(像素)
float density = metric.density; // 屏幕密度(0.75 / 1.0 / 1.5 / 2.0)
int densityDpi = metric.densityDpi; // 屏幕密度DPI(120 / 160 / 240/ 360)
Log.i("dpiIsWhat", " width=" + width + " height=" + height
+ " densiy=" + density + " densityDpi=" + densityDpi);
tv1 = (TextView) findViewById(R.id.tv1);
tv2 = (TextView) findViewById(R.id.tv2);
tv1.setText(getResources().getDimension(R.dimen.text_s26) + "");
tv2.setText(getResources().getDimension(R.dimen.m180) + "");
}
}
通过getResources().getDimension(R.dimen.text_s26)得到的值,是dimens下的值乘以屏幕密度比。
官方文档是这样写的:
Retrieve a dimensional for a particular resource ID. Unit conversions are based on the current DisplayMetrics associated with the resources.
所以获取一个具体的值,就应该这样写:
int dp = (int) (getResources().getDimension(R.dimen.test) / getResources().getDisplayMetrics().density)
这也就是上面的图片,textview里面的文字内容了。
最终,附上,批量操作,来更改dimens下面的数值Java文件,下载路径为http://download.csdn.net/detail/harryweasley/9528982
参考文章:http://stackoverflow.com/questions/11121028/load-dimension-value-from-res-values-dimension-xml-from-source-code