Android 屏幕适配

来源:互联网 发布:以下哪件商品淘宝禁售 编辑:程序博客网 时间:2024/06/05 18:14

一、适配方式之dp

名词解释

分辨率:480*800,1280*720。表示物理屏幕区域内像素点的总和。(切记:跟屏幕适配没有任何关系)

因为我们既可以把1280*720 的分辨率做到4.0 的手机上面。我也可以把1280*720 的分辨率做到5.0 英寸的手机上面,如果分辨率相同,手机屏幕越小清晰。

px:pixels 的意思,像素,就是屏幕中最小的一个显示单元,是屏幕的物理像素点,与密度相关,密度大了,单位面积上的px 会比较多。

sp:与刻度无关的单位,同dip/dp 相似,会根据用户的字体大小偏好来缩放,主要用于设置字体的大小

dpi:dpi :dots per inch,像素密度,即每英寸屏幕所拥有的像素数,像素密度越大,显示画面细节就越丰富。常见取值120,160,240,320,480

=2+2/

注意:屏幕尺寸单位为英寸,例:分辨率为1280*720 屏幕宽度为6 英寸计算所得像素密度约等于245,屏幕尺寸指屏幕对角线的长度

在Android 手机中dpi 分类:

dpi 说明 ldpi Resources for low-density (ldpi) screens (~120dpi) mdpi Resources for medium-density (mdpi) screens (~160dpi). (This is the baseline density.) hdpi Resources for high-density (hdpi) screens (~240dpi). xhdpi Resources for extra high-density (xhdpi) screens (~320dpi).


在我们的Android 工程目录中有如下drawable-*dpi 目录,这些目录是用来适配不同分辨率手机的。

这里写图片描述

Android 应用在查找图片资源时会根据其分辨率自动从不同的文件目录下查找(这本身就是Android 系统的适配策略),如果在低分辨的文件目录中比如drawable-mdpi 中没有图片资源,其他目录中都有,当我们将该应用部署到mdpi 分辨率的手机上时,那么该应用会查找分辨率较高目录下的资源文件,如果较高分辨率目录下也没有资源则只好找较低目录中的资源了。

常见手机屏幕像素及对应分别率级别:

  • ldpi:320*240
  • mdpi:480*320
  • hdpi:800*480
  • xhdpi:1280*720
  • xxhdpi:1920*1080

dp 和px 之间的简单换算关系:

  • ldpi 的手机:1dp=0.75px
  • mdpi 的手机:1dp=1.0px
  • hdpi 的手机:1dp=1.5px
  • xhdpi 的手机:1dp=2.0px
  • xxhdpi 的手机:1dp=3.0px

这里写图片描述

Tips:根据上面的描述我们得出如下结论,对于mdpi 的手机,我们的布局通过dp 单位可以达到适配效果

dp 和px 之间的关系

Android 官方定义dip 等价于160dpi 屏幕下的一个物理像素点,即1dip=1px。转换公式如下:

dip =(dpi/(160 像素/英寸))px = density px

举例来说,在240 dpi 的屏幕上,1dip 等于1.5px

density :直接翻译的话也叫密度,但是他在Android 中特指dp 和px 的比例关系。常见取值1.5 ,1.0

dp:是dip(Density independent pixels) 的简写,指密度无关的像素。指一个抽象意义上的像素,程序用它来定义界面元素。一个与密度无关的,在逻辑尺寸上,与一个位于像素密度为160dpi 的屏幕上的像素是一致的。要把密度无关像素转换为屏幕像素,可以用这样一个简单的公式:

pixels=dips*(density/160)

举个例子,在DPI 为240 的屏幕上,1 个DIP 等于1.5 个物理像素。

布局时最好使用dp 来定义我们程序的界面,因为这样可以保证我们的UI 在各种分辨率的屏幕上都可以正常显示。

/**     * 根据手机的分辨率从px(像素) 的单位转成为dp     */    public static int px2dip(Context context, float pxValue) {        final float scale = context.getResources().getDisplayMetrics().density;        return (int) (pxValue / scale + 0.5f);    }    /**     * 根据手机的分辨率从dip 的单位转成为px(像素)     */    public static int dip2px(Context context, float dpValue) {        final float scale = context.getResources().getDisplayMetrics().density;        return (int) (dpValue * scale + 0.5f);    }

二、适配方式之dimens

跟drawable 目录类似的,在Android 工程的res 目录下有values 目录,这个是默认的目录,同时为了适配不同尺寸手机我们可以创建一个values-1280x720 的文件夹,同时将dimens.xml 文件拷贝到该目录下

这里写图片描述

在dimens.xml 中定义一个尺寸,如下所示

<resources>    <dimen name="width">160dp</dimen></resources>

在values-1280x720 目录中的dimens.xml 中定义同样的尺寸名称,但是使用不同的尺寸,如下所示

<resources>    <dimen name="width">180dp</dimen></resources>

当我们在布局文件中使用长或者宽度单位时,比如下图所示,应该使用@dimen/width 来灵活的定义宽度

<?xml version="1.0" encoding="utf-8"?><LinearLayout    xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">    <TextView        android:layout_width="@dimen/width"        android:layout_height="wrap_content"/></LinearLayout>

Tips:在values-1280x720 中, 中间的是大写字母X 的小写形式x , 而不是加减乘除的乘号。如果我们在values-1280x720 中放置了dimens 常量,一定记得也将该常量的对应值在values 目录下的dimens.xml 中放一份,因为该文件是默认配置,当用户的手机不是1280*720 的情况下系统应用使用的是默认values 目录中的dimens.xml

三、适配方式之layout

跟values 一样,在Android 工程目录中layout 目录也支持类似values 目录一样的适配,在layout 中我们可以针对不同手机的分辨率制定不同的布局,如下图所示

这里写图片描述

四、适配方式之java 代码适配

为了演示用java 代码控制适配的效果,因此假设有这样的需求,让一个TextView 控件的宽和高分别为屏幕的宽和高的一半。

我们新创建一个Android 工程,修改main_activity.xml,布局文件清单如下:

<RelativeLayout    xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent">    <!-- 当前控件宽高为屏幕宽度的各50% -->    <TextView        android:id="@+id/tv"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:background="#000000"        android:text="@string/hello_world"/></RelativeLayout>

在MainActivity.java 类中完成用java 代码控制TextView 的布局效果,其代码清单如下:

public class MainActivity extends Activity {        private static final String tag = null;        @Override        protected void onCreate(Bundle savedInstanceState) {            super.onCreate(savedInstanceState);            //去掉title            requestWindowFeature(Window.FEATURE_NO_TITLE);            setContentView(R.layout.activity_main);            //获取TextView 控件            TextView tv = (TextView) findViewById(R.id.tv);            //找到当前控件的夫控件(父控件上给当前的子控件去设定一个规则)            DisplayMetrics metrics = new DisplayMetrics();            //给当前metrics 去设置当前屏幕信息(宽(像素)高(像素))            getWindowManager().getDefaultDisplay().getMetrics(metrics);            //获取屏幕的高度和宽度            Constant.srceenHeight = metrics.heightPixels;            Constant.srceenWidth = metrics.widthPixels;            //日志输出屏幕的高度和宽度            Log.i(tag, "Constant.srceenHeight = "+Constant.srceenHeight);            Log.i(tag, "Constant.srceenWidth = "+Constant.srceenWidth);            //宽高各50%            RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(                    //数学角度上四舍五入                    (int)(Constant.srceenWidth*0.5+0.5),                    (int)(Constant.srceenHeight*0.5+0.5));            //给tv 控件设置布局参数            tv.setLayoutParams(layoutParams);        }    }

其中Constant 类是一个常量类,很简单,只有两个常量用来记录屏幕的宽和高,其代码清单如下:

public class Constant {    public static int srceenHeight;    public static int srceenWidth;}

五、适配方式之weight 权重适配

在控件中使用属性android:layout_weight=”1”可以起到适配效果,但是该属性的使用有如下规则:

  • 只能用在线性控件中,比如LinearLayout。
  • 竖直方向上使用权重的控件高度必须为0dp(Google 官方的推荐用法)
  • 水平方向上使用权重的控件宽度必须为0dp(Google 官方的推荐用法)

六、屏幕适配的处理技巧

手机自适应主要分为两种情况:横屏和竖屏的切换,以及分辨率大小的不同。

横屏和竖屏的切换

Android 应用程序支持横竖屏幕的切换,Android 中每次屏幕的切换动会重启Activity,所以应该在Activity销毁(执行onPause()方法和onDestroy()方法)前保存当前活动的状态;在Activity 再次创建的时候载入配置,那样,进行中的游戏就不会自动重启了!有的程序适合从竖屏切换到横屏,或者反过来,这个时候怎么办呢?可以在配置Activity 的地方进行如下的配置android:screenOrientation=”portrait”(landscape 是横向,portrait 是纵向)。这样就可以保证是竖屏总是竖屏了。

而有的程序是适合横竖屏切换的。如何处理呢?首先要在配置Activity 的时候进行如下的配置:

android:configChanges="keyboardHidden|orientation"

另外需要重写Activity 的onConfigurationChanged ()方法。实现方式如下:

 @Override    public void onConfigurationChanged(Configuration newConfig){        super.onConfigurationChanged(newConfig);        if(this.getResources().getConfiguration().orientation==Configuration.ORIENTATION_LANDSCAPE){            //TODO        }else        if(this.getResources().getConfiguration().orientation==Configuration.ORIENTATION_PORTRAIT){            //TODO        }    }

分辨率大小不同

对于分辨率问题,官方给的解决办法是创建不同的layout 文件夹,这就需要对每种分辨率的手机都要写一个布局文件,虽然看似解决了分辨率的问题,但是如果其中一处或多处有修改了,就要每个布局文件都要做出修改,这样就造成很大的麻烦。那么可以通过以下几种方式解决:

1、使用layout_weight

目前最为推荐的Android 多屏幕自适应解决方案。

该属性的作用是决定控件在其父布局中的显示权重,一般用于线性布局中。其值越小,则对应的layout_width或layout_height 的优先级就越高(一般到100 作用就不太明显了);一般横向布局中,决定的是layout_width 的优先级;纵向布局中,决定的是layout_height 的优先级。

传统的layout_weight 使用方法是将当前控件的layout_width 和layout_height 都设置成fill_parent,这样就可以把控件的显示比例完全交给layout_weight;这样使用的话,就出现了layout_weight 越小,显示比例越大的情况(即权重越大,显示所占的效果越小)。不过对于2 个控件还好,如果控件过多,且显示比例也不相同的时候,控制起来就比较麻烦了,毕竟反比不是那么好确定的。于是就有了现在最为流行的0px 设值法。看似让人难以理解的layout_height=0px 的写法,结合layout_weight,却可以使控件成正比例显示,轻松解决了当前Android 开发最为头疼的碎片化问题之一。

2、清单文件配置

不建议使用这种方式,需要对不同的界面写不同的布局

需要在AndroidManifest.xml 文件的元素如下添加子元素

<supports-screens         android:largeScreens="true"        android:normalScreens="true"        android:anyDensity="true"        android:smallScreens="true"        android:xlargeScreens="true">    </supports-screens>

以上是为我们的屏幕设置多分辨率支持(更准确的说是适配大、中、小三种密度)。

Android:anyDensity="true"

这一句对整个的屏幕都起着十分重要的作用,值为true,我们的应用程序当安装在不同密度的手机上时,程序会分别加载hdpi,mdpi,ldpi 文件夹中的资源。相反,如果值设置为false,即使我们在hdpi,mdpi,ldpi,xdpi 文件夹下拥有同一种资源,那么应用也不会自动地去相应文件夹下寻找资源。而是会在大密度和小密度手机上加载中密度mdpi 文件中的资源。

有时候会根据需要在代码中动态地设置某个值,可以在代码中为这几种密度分别设置偏移量,但是这种方法最好不要使用,最好的方式是在xml 文件中不同密度的手机进行分别设置。这里地图的偏移量可以在values-xpdi,values-hpdi,values-mdpi,values-ldpi 四种文件夹中的dimens.xml 文件进行设置。

其他

说明:

  • 在不同分辨率的手机模拟器下,控件显示的位置会稍有不同
  • 通过在layout 中定义的布局设置的参数,使用dp(dip),会根据不同的屏幕分辨率进行适配
  • 但是在代码中的各个参数值,都是使用的像素(px)为单位的

技巧:

1、尽量使用线性布局,相对布局,如果屏幕放不下了,可以使用ScrollView(可以上下拖动)

ScrowView 使用的注意:

在不同的屏幕上显示内容不同的情况,其实这个问题我们往往是用滚动视图来解决的,也就是ScrowView;需要注意的是ScrowView 中使用layout_weight 是无效的,既然使用ScrowView 了,就把它里面的控件的大小都设成固定的吧。

2、指定宽高的时候,采用dip 的单位,dp 单位动态匹配

3、由于android 代码中写的单位都是像素,所有需要通过工具类进行转化

4、尽量使用9-patch 图,可以自动的依据图片上面显示的内容被拉伸和收缩。其中在编辑的时候,灰色区域是被拉伸的,上下两个点控制水平方向的拉伸,左右两点控制垂直方向的拉伸

百分比布局

百分比布局github 地址

支持百分比设置的布局有百分比相对布局PercentRelativeLayout、百分比线性布局PercentLinearLayout、
百分比帧布局PercentFrameLayout,它们的使用与之前的常用布局使用类似。

百分比相对布局PercentRelativeLayout 中包含了3 个view 控件,前2 个view 是显示在第三个view 上面,第一个view 设置了父控件高度的百分之二十,父控件宽度的百分之七十,第二个view 显示在第一个view 的右边并设置了父控件高度的百分之二十,父控件宽度的百分之三十。这样前2个view 的刚好显示整个屏幕的宽度,屏幕高度的百分之二十。第三个view 设置了父控件高度的百分之八十,宽度为整个屏幕。这样百分比就设置好了,运行效果如图所示。

因为百分比支持库是随着Android Support Library 23 一起的,如果要使用请确保你已经在SDKManager 中的Android Support Library 更新了最新的版本。然后在build.gradle 文件中添加下面这样的依赖:

compile 'com.android.support:percent:23.0.0'

布局文件

<android.support.percent.PercentRelativeLayout    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent">    <View        android:id="@+id/top_left"        android:layout_width="0dp"        android:layout_height="0dp"        android:layout_alignParentTop="true"        android:background="#ff44aacc"        app:layout_heightPercent="20%"        app:layout_widthPercent="70%" />    <View        android:id="@+id/top_right"        android:layout_width="0dp"        android:layout_height="0dp"        android:layout_alignParentTop="true"        android:layout_toRightOf="@+id/top_left"        android:background="#ffe40000"        app:layout_heightPercent="20%"        app:layout_widthPercent="30%" />    <View        android:id="@+id/bottom"        android:layout_width="match_parent"        android:layout_height="0dp"        android:layout_below="@+id/top_left"        android:background="#ff00ff22"        app:layout_heightPercent="80%" /></android.support.percent.PercentRelativeLayout>

屏幕适配

屏幕适配

  1. Android 屏幕适配方案
  2. Android 百分比布局库(percent-support-lib) 解析与扩展
  3. Android 增强版百分比布局库 为了适配而扩展
  4. Android AutoLayout全新的适配方式 堪称适配终结者
0 0
原创粉丝点击