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

关于Android屏幕适配应该知道的一些知识

2016-05-24 16:28 911 查看
转载请注明出处,谢谢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文件

<LinearLayout xmlns:android="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" >

<TextView
android:id="@+id/tv1"
android:layout_width="@dimen/m180"
android:layout_height="@dimen/m180"
android:background="@android:color/holo_blue_bright"
android:textSize="@dimen/text_s26" />

<TextView
android:id="@+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">180dp</dimen>
<dimen name="m60">60dp</dimen>
<dimen name="text_s26">26sp</dimen>

</resources>


values-sw360dp/dimens下的内容如下所示:

<resources>

<dimen name="m180">138dp</dimen>
<dimen name="m60">46dp</dimen>
<dimen name="text_s26">20sp</dimen>

</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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息