屏幕适配方式都有哪些
适配方式之 dp
分辨率:eg:480*800,1280*720。表示物理屏幕区域内像素点的总和。(切记:跟屏幕适配没有任何关系)
因为我们既可以把 1280*720 的分辨率做到 4.0 的手机上面。我也可以把 1280*720 的分辨率做到 5.0 英寸的手机上面,如果分辨率相同,手机屏幕越小清晰。/
px(pix):像素,就是屏幕中最小的一个显示单元
dpi(像素密度):即每英寸屏幕所拥有的像素数,像素密度越大,显示画面细节就越丰富。分配给各种密度的图像文件的尺寸应该符合以下比例: 3: 4: 6: 9. 也就是要符合密度比例( 120: 160: 240: 360)
计算公式:像素密度=√(长度像素数^2+宽度像素数^2 ) / 屏幕尺寸
注:屏幕尺寸单位为英寸 例:分辨率为 1280*720 屏幕宽度为 6 英寸 计算所得像素密度约等于245,屏幕尺寸指屏幕对角线的长度。
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
根据上面的描述我们得出如下结论,对于 mdpi 的手机,我们的布局通过 dp 单位可以达到适配效果。
适配方式之 dimens
跟 drawable 目录类似的,在 Android 工程的 res 目录下有 values 目录,这个是默认的目录,同时为了适配不同尺寸手机我们可以创建一个 values-1280x720 的文件夹,同时将 dimens.xml 文件拷贝到该目录下。
在 values-1280x720 中,中间的是大写字母 X 的小写形式 x,而不是加减乘除的乘号。如果我们在 values-1280x720 中放置了 dimens 常量, 一定记得也将该常量的对应值在 values 目录下的dimens.xml 中放一份,因为该文件是默认配置,当用户的手机不是 1280*720 的情况下系统应用使用的是默认 values 目录中的 dimens.xml。
适配方式之 java 代码适配
为了演示用 java 代码控制适配的效果,因此假设有这样的需求,让一个 TextView 控件的宽和高分别为屏幕的宽和高的一半。
我们新创建一个 Android 工程,修改 main_activity.xml,布局文件清单如下:
<RelativeLayout 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"
tools:context=".MainActivity">
<!--当前控件宽高为屏幕宽度的各 50%-->
<TextView
android:id="@+id/tv"
android:background="#000000"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
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);
}
class Constant {
public static int srceenHeight;
public static int srceenWidth;
}
}
其中 Constant 类是一个常量类,很简单,只有两个常量用来记录屏幕的宽和高。
适配方式之 weight 权重适配
在控件中使用属性 android:layout_weight=”1”可以起到适配效果,但是该属性的使用有如下规则:
只能用在线性控件中,比如 LinearLayout。
竖直方向上使用权重的控件高度必须为 0dp(Google 官方的推荐用法)
水平方向上使用权重的控件宽度必须为 0dp(Google 官方的推荐用法)
其它
1、在需要的情况下,为每种尺寸的设备提供指定的layout文件。
2、在需要的情况下,为每种密度的设备提供不同的图像文件
3、不使用absoluteLayout布局
4、
屏幕适配的处理技巧都有哪些
手机自适应主要分为两种情况:横屏和竖屏的切换,以及分辨率大小的不同。
横屏和竖屏的切换
1、Android 应用程序支持横竖屏幕的切换,Android 中每次屏幕的切换动会重启 Activity,所以应该在Activity销毁 (执行onPause()方法和onDestroy()方法) 前保存当前活动的状态; 在Activity再次创建的时候载入配置, 那样, 进行中的游戏就不会自动重启了! 有的程序适合从竖屏切换到横屏,或 者 反 过 来 , 这 个 时 候 怎 么 办 呢 ? 可 以 在 配 置 Activity 的 地 方 进 行 如 下 的 配 置android:screenOrientation=”portrait”(landscape 是横向,portrait 是纵向)。这样就可以保证是竖屏总是竖屏了。
2、而有的程序是适合横竖屏切换的。如何处理呢?首先要在配置 Activity 的时候进行如下的配置:
android:configChanges=”keyboardHidden|orientation” , 另 外 需 要 重 写 Activity 的onConfigurationChanged 方法。实现方式如下:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){
}else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT){
}
}
分辨率大小不同
对于分辨率问题,官方给的解决办法是创建不同的 layout 文件夹,这就需要对每种分辨率的手机都要写一个布局文件,虽然看似解决了分辨率的问题,但是如果其中一处或多处有修改了,就要每个布局文件都要做出修改,这样就造成很大的麻烦。那么可以通过以下几种方式解决:
一)使用 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 开发最为头疼的碎片化问题之一。
二)清单文件配置:【不建议使用这种方式,需要对不同的界面写不同的布局】
需要在 AndroidManifest.xml 文件的元素如下添加子元素
<supports-screensandroid: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 图,可以自动的依据图片上面显示的内容被拉伸和收缩。其中在编辑的时候,灰色区域是被拉伸的,上下两个点控制水平方向的拉伸,左右两点控制垂直方向的拉伸
dp 和 px 之间的关系
dp:是 dip 的简写,指密度无关的像素。
指一个抽象意义上的像素,程序用它来定义界面元素。一个与密度无关的,在逻辑尺寸上,与一个位于像素密度为 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);
}