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

转载请注明出处,谢谢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

猜你喜欢

转载自blog.csdn.net/HarryWeasley/article/details/51463232