Configuration
适配各种屏幕规格,首先要取到系统对于屏幕的配置信息,这些配置可从工具类Configuration获得。Configuration对象在Activity中通过调用getResources().getConfiguration()得到,该对象的常用属性说明如下:
touchscreen : 屏幕触摸方式。有下列几种取值定义:"未定义", "不支持触摸", "专用笔触摸", "支持手指触摸"
keyboard : 物理键盘样式。有下列几种取值定义:"未定义", "无物理键盘", "全键盘", "十二格键盘"
keyboardHidden : 键盘状态。有下列几种取值定义:"未定义", "未隐藏或软键盘", "已隐藏", "软键盘"
hardKeyboardHidden : 物理键盘状态。有下列几种取值定义:"未定义", "未隐藏", "已隐藏"
navigation : 方向控制样式。有下列几种取值定义:"未定义", "无方向控制", "方向键", "轨迹球", "滚轮"
navigationHidden : 方向控制状态。有下列几种取值定义:"未定义", "未隐藏", "已隐藏"
orientation : 屏幕方向。有下列几种取值定义:"未定义", "竖屏", "横屏"
以上属性除了屏幕方向是有用的,其他的基本没什么用。
如果属性发生变化,可重写onConfigurationChanged函数监测最新的属性值。但是由屏幕旋转导致的屏幕方向变化,按照生命周期走的是原方向onDestroy然后新方向onCreate,并不触发onConfigurationChanged方法,所以该方法基本也没机会用到。
适配竖屏/横屏
上面说到,竖屏/横屏的切换走的是Activity的生命周期流程,详细介绍参见《 Android开发笔记(三十九)Activity的生命周期》。
要对一个页面分别适配竖屏与横屏,可在res目录下创建子目录“layout-land”,该目录放的是横屏时的布局文件,而原来的layout目录放的是默认即竖屏时的布局文件。app运行时,Android会根据当前的屏幕方向,自动选择对应目录下的布局。具体的代码例子参见《 Android开发笔记(六十七)嵌入页面的碎片》,这里通过操作Fragment完成屏幕方向切换的适配。
适配竖屏与横屏的另一种方法,是在布局文件中采用ViewStub标签,此时无需新建layout目录,只要在代码中判断屏幕方向,从而选择合适的ViewStub标签加以显示。其实ViewStub标签也要指向不同的布局文件完成适配,该方法与新建layout目录的区别在于,新建layout方式是把选择布局操作交给Android系统完成,而ViewStub标签方式则是在app代码中自己完成。该方式的具体例子参见《 Android开发笔记(七十四)布局文件优化》。
适配手机/平板
Android中没有明确区分手机和平板的方法,但我们可以根据某些参数来判断,具体方法如下:
1、从Configuration对象的screenLayout属性判断当前的屏幕规格,只要是大尺寸以上的都算平板;
2、从系统服务TELEPHONY_SERVICE中获得电话管理对象TelephonyManager,然后判断该对象的电话类型getPhoneType,不能打电话的都算平板(这个可能不准确,因为有的平板也能打电话;或者如果手机没插sim卡,那也不能打电话);
3、从系统服务WINDOW_SERVICE中获得窗口管理对象WindowManager,再由该对象获得屏幕的长和宽,据此算出屏幕对角线的长度,若结果大于六英寸,则认为是平板;
判断是否平板的三种实现代码示例如下:
import android.content.Context;
import android.content.res.Configuration;
import android.telephony.TelephonyManager;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.WindowManager;
public class TabletUtil {
//SCREENLAYOUT_SIZE_SMALL : 小尺寸
//SCREENLAYOUT_SIZE_NORMAL : 正常尺寸
//SCREENLAYOUT_SIZE_LARGE : 大尺寸
//SCREENLAYOUT_SIZE_XLARGE : 超大尺寸
public static boolean isTabletByLayout(Context ctx) {
boolean bTablet = false;
int sizeMode = ctx.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK;
if (sizeMode >= Configuration.SCREENLAYOUT_SIZE_LARGE) {
bTablet = true;
}
return bTablet;
}
//PHONE_TYPE_NONE : 无
//PHONE_TYPE_GSM : GSM
//PHONE_TYPE_CDMA : CDMA
//PHONE_TYPE_SIP : SIP
public static boolean isTabletByPhone(Context ctx) {
boolean bTablet = false;
TelephonyManager telephony = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
int phoneType = telephony.getPhoneType();
if (phoneType == TelephonyManager.PHONE_TYPE_NONE) {
bTablet = true;
}
return bTablet;
}
public static boolean isTabletByDisplay(Context ctx) {
WindowManager wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
DisplayMetrics dm = new DisplayMetrics();
display.getMetrics(dm);
double x = Math.pow(dm.widthPixels / dm.xdpi, 2);
double y = Math.pow(dm.heightPixels / dm.ydpi, 2);
// 屏幕尺寸
double screenInches = Math.sqrt(x + y);
// 大于6尺寸则为Pad
if (screenInches >= 6.0) {
return true;
}
return false;
}
}
适配不同屏幕尺寸
不同设备的屏幕尺寸有大有小,适配不同大小屏幕的方法也有三种:
1、在布局文件中,视图或控件的宽或高使用match_parent和wrap_content,或者设置layout_weight权重,由app自身在onMeasure测量方法中自行计算大小。测量尺寸的介绍参见《 Android开发笔记(十二)测量尺寸与下拉刷新》。
2、在代码中获得当前屏幕的分辨率,根据不同分辨率做不同处理。获取屏幕分辨率的详细说明参见《 Android开发笔记(三)屏幕分辨率》。
3、参照drawable的处理方式,不同尺寸的图片放在不同的drawable目录下,详见《 Android开发笔记(七)初识Drawable》。同样的,对于布局文件layout,我们也可以创建诸如“layout-mdpi”、“layout-hdpi”、“layout-xhdpi”等目录,分别存放中等分辨率、高分辨率、超高分辨率的布局文件,由Android在运行时自行选择最接近当前分辨率的布局。除了drawable和layout,dimens.xml中的维度定义也可区分不同的分辨率,具体做法就是创建“values-mdpi”、“values-hdpi”、“values-xhdpi”等目录,在这几个目录下分别保存已设置对应维度的dimens.xml。
点此查看Android开发笔记的完整目录