Android中的机型适配
在软件开发的过程中,为了让软件在不同的场景下都可以使用,所以机型适配是不可或缺并且非常重要耗时的一个环节.
1,Android的版本
2.手机厂商
3.屏幕的尺寸
4.网络的制式
5.语言
6.国家
7.硬件设备
8.运行商
…………………
关于现在要考虑的机型适配的问题,就目前来说,我还只能解决一些方面…嘿嘿….
1.在Android的工程下的res目录下进行设备性能支持的适配.
我们通过在res目录下新建不同的文件夹,设定不同的布局/字符串/图片/语言等等,来适配不同的机型.
1.图片适配屏幕
2.界面横竖屏切换屏幕
3.屏幕宽高度大小适配
4.语言的适配
2.. Android提供了自动的设备检测功能,能够根据当前设备的一些参数信息,进行动态的资源的加载,从而实现机型适配;
在Android的工程目录下,我们可以看到有不同的文件夹hdpi mdpi xdpi xxhdpi xxxhdpi,存放着相同的图片,他是在不同的屏幕的分辨率下,显示不同的图片.
涉及到的知识点:
1.密度dpi越大,同一个像素尺寸的图片显示的越小;
2.手机的屏幕密度越小(分辨率却低),同一个图片显示的就大了。
3.高密度手机使用大图片;低密度手机用小图片;
4.dpi的计算 .
dp/sp的概念:
dp/dip:Android中,定义一套单位dp,以mdpi为标准,进行自动
运算的像素数值;
例如:5dp, 在mdpi的手机上,就是5px
在xhdpi的手机上,就是15px
sp: scalable pixel 可缩放的px, 用于文本的处理.运算规则
和dp相似
px = dp * (dpi / 160) 已知dp求px
已知px 求dp, dp = px / (dpi / 160)
有关三者之间的关系:
http://www.jianshu.com/p/913943d25829
5.以mdpi为基准,进行尺寸的缩放;
缩放规则:
mdpi 1 原始尺寸
ldpi 0.75倍 尺寸
hdpi 1.5倍 尺寸
xhdpi 2倍 尺寸
xxhdpi 3倍
xxxhdpi 4倍
6.目前建议,采用高清大图进行设计,分辨率低的会自动缩小,图片缩小不会失真.
我们可以在res目录下,新建values文件,进行不同屏幕尺寸的适配(small/nomal/large/xlarge),我们可以新建layout-small文件夹,设计不同的布局,我们也可以在values-small文件下,新建不同的values资源文件,在不同的屏幕尺寸下显示不同的资源.
新建不同的values语言文件,适配不同种语言的Android系统.
1).在android3.0之后出现了一套新的屏幕尺寸适配规则: swXXXdp, wXXXdp, hXXXdp
2).可以控制的程度更细,能够精确适配;可以覆盖指定数值以及更大的尺寸
swxxxdp :表示屏幕的最短边是xxxdp的屏幕,都适配.
wxxxdp:表示平行于地面的边的宽度,在表示的范围内,将会进行布局适配;
如: w240dp; w320dp,w480dp,w600dp; 表示的大小:
[240,320),…[600,………..)
hxxxdp:与sxxxxdp同样的道理.
sw比w/h的优先级高
// 获取屏幕的高宽,dp,px
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = (TextView) findViewById(R.id.device_text);
// DisplayMetrics中存储的是有关屏幕的相关参数
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int w = dm.widthPixels; // 屏幕宽度
int h = dm.heightPixels; // 屏幕高度
int densityDpi = dm.densityDpi; // 屏幕dpi()
float xdpi = dm.xdpi; // x dpi
float ydpi = dm.ydpi; // y dpi
// px = dp * (dpi / 160) 已知dp求px
// 已知px 求dp, dp = px / (dpi / 160)
// 已知dm.density = dpi / 160
float wDp = w / dm.density;
Log.d("TAG", "onCreate: w " + wDp + "dp");
textView.setText(Float.toString(wDp));
}
1.使用 wrap_content, match_parent 或者 dp单位尺寸
wrap_content,match_parent以及dp尺寸均会进行缩放,如 100dp 对应 medium dpi,那么对于hdpi就会放到1.5倍,字体必须使用 sp 单位,因为能够缩放.
2.不要在代码中硬编码尺寸
因为性能和简单要求,Android系统内部均使用像素进行维护,例如在一个设备上执行 View.getWidth()返回10像素,不要将这个数值作为硬编码的常数,因为可能在高密度的设备上,返回的值可能会是15.
案例:
/**
* 在代码中使用尺寸的方式
* 需要进行代码适配
*/
public class CodeSizeActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_code_size);
ViewGroup group = (ViewGroup) findViewById(R.id.my_layout);
TextView textView = new TextView(this);
// LayoutParams 所有的Android标准容器,都有自己的LayoutParams
// 控件添加到哪种容器类型,就使用这个类型的LayoutParams
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
(int) dp2px(this, 200), // 直接写数值 属于硬编码
(int) dp2px(this, 50) // 数字都是 像素单位,!!! 像素单位不支持机型适配;
);
textView.setLayoutParams(lp);
textView.setText("Hello World by Zhang sir");
textView.setBackgroundColor(0xFFb99393);
group.addView(textView);
}
/**
* 实现机型适配,可以指定数值, 根据手机屏幕密度,
* 生成像素单位, 用于代码中的尺寸设置
*/
public static float dp2px(Context context, int dp) {
DisplayMetrics outMetrics = new DisplayMetrics();
// 版本适配
if (Build.VERSION.SDK_INT >= 17) {
DisplayManager displayManager =
(DisplayManager) context.getSystemService(
Context.DISPLAY_SERVICE
);
displayManager.getDisplay(0).getMetrics(outMetrics);
} else {
WindowManager manager =
(WindowManager) context.getSystemService(WINDOW_SERVICE);
manager.getDefaultDisplay().getMetrics(outMetrics);
}
float px = dp * outMetrics.density;
return px;
}
}
3.不使用绝对布局
4.使用修饰符定位尺寸和密度资源
5.代码中对像素进行缩放
6*.利用尺寸资源来优化layout布局
建议将layout中的尺寸数值,放到独立的尺寸资源文件dimens.xml中,这样就可以利用密度、尺寸来进行屏幕尺寸适配而不用创建多个layout.
/**
* 可以把这个当做工具类.
* 实现机型适配,可以指定数值,根据手机屏幕密度
* 生成像素单位,用于代码中的尺寸设置
*/
public static float dp2Px(Context context, int dp) {
DisplayMetrics metrics = new DisplayMetrics();
if (Build.VERSION.SDK_INT >= 17) {
DisplayManager manager = (DisplayManager) context.getSystemService(context.DISPLAY_SERVICE);
manager.getDisplay(0).getMetrics(metrics);
} else {
WindowManager manager = ((WindowManager) context.getSystemService(WINDOW_SERVICE));
manager.getDefaultDisplay().getMetrics(metrics);
}
float px = dp * metrics.density;
return px;
}
1. 机型适配中的版本适配,使用数字来进行判断的.
因为在SDK中是有些错误的地方
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {
}
会直接崩溃
Build.VERSION_CODES.N:在AndroidAPI1出现的,在Android5.0的手机会找不到这个变量.因为Android5.0找不到这个变量
2.if (Build.VERSION.SDK_INT >= 24) {
android.icu.text.SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
} else {
java.text.SimpleDateFormat format = new java.text.SimpleDateFormat("yyyy年MM月dd日");
}
java中采用堆栈的方式来存储类,在加载类之前,会检查所有的类是否存在;所以对于程序,如果有上述代码,会直接崩溃
Android中不会检查所有的类,会执行到 if (Build.VERSION.SDK_INT >= 24) 再去加载类
在清单文件中使用
生命硬件所需要的权限
一般只对你的APP发布在GooglePlay的时候其作用,它协助GooglePlay来过滤您的应用程序,比如你明确的在你的程序清单中描述了你的程序必须使用哪些硬件或者软件相关的功能,则如果某些设备在GooglePlay上搜索应用时或者在某个程序的详情页上就会过滤掉不支持你的设备的程序。
要区别
,你声明了一个
并不代表你就可以不写
权限说明了,我在第1点其实已经说了,
其实是供GooglePlay用的,而
是供你的Android系统使用的,你想使用某个硬件设备或者软件功能就必须申请这个权限。