本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处!
Android适配需要考虑方方面面,主要是图片字体大小和API,但也要考虑其他场景下的一些问题。
先熟悉一下Android设备的dpi(dots per inch),设计上叫ppi(pixel per inch),即1inch中有多少个像素
1、考虑横竖屏幕,注意屏幕布局资源的替换和页面数据的保存和重加载,配合onSaveInstance和onRestoreInstance使用
以及适配的屏幕尺寸,通过在主配置文件的Application处,设计supports-screen,normal、large、xlarge等
以下摘抄自Google官方:https://developer.android.com/guide/practices/screens_support.html
- 屏幕尺寸
-
按屏幕对角测量的实际物理尺寸。
为简便起见,Android 将所有实际屏幕尺寸分组为四种通用尺寸:小、 正常、大和超大。
- 屏幕密度
-
屏幕物理区域中的像素量;通常称为 dpi(每英寸 点数)。例如, 与“正常”或“高”密度屏幕相比,“低”密度屏幕在给定物理区域的像素较少。
为简便起见,Android 将所有屏幕密度分组为六种通用密度: 低、中、高、超高、超超高和超超超高。
- 方向
- 从用户视角看屏幕的方向,即横屏还是 竖屏,分别表示屏幕的纵横比是宽还是高。请注意, 不仅不同的设备默认以不同的方向操作,而且 方向在运行时可随着用户旋转设备而改变。
- 分辨率
- 屏幕上物理像素的总数。添加对多种屏幕的支持时, 应用不会直接使用分辨率;而只应关注通用尺寸和密度组指定的屏幕 尺寸及密度。
- 密度无关像素 (dp)
-
在定义 UI 布局时应使用的虚拟像素单位,用于以密度无关方式表示布局维度 或位置。
密度无关像素等于 160 dpi 屏幕上的一个物理像素,这是 系统为“中”密度屏幕假设的基线密度。在运行时,系统 根据使用中屏幕的实际密度按需要以透明方式处理 dp 单位的任何缩放 。dp 单位转换为屏幕像素很简单:
px = dp * (dpi / 160)
支持的屏幕范围
从 Android 1.6(API 级别 4)开始,Android 支持多种屏幕尺寸和密度,反映设备可能具有的多种不同屏幕配置。 您可以使用 Android 系统的功能优化应用在各种屏幕配置下的用户界面 ,确保应用不仅正常渲染,而且在每个屏幕上提供 最佳的用户体验。
为简化您为多种屏幕设计用户界面的方式,Android 将实际屏幕尺寸和密度的范围 分为:
-
四种通用 尺寸: 小、 正常、 大 和 超大
注:从 Android 3.2(API 级别 13)开始,这些尺寸组 已弃用,而采用根据可用屏幕宽度管理屏幕尺寸的 新技术。如果为 Android 3.2 和更高版本开发,请参阅声明适用于 Android 3.2 的平板电脑布局以了解更多信息。
-
六种通用的 密度:
- ldpi(低)~120dpi ~density=0.75
- mdpi(中)~160dpi ~density=1
- hdpi(高)~240dpi ~density=1.5
- xhdpi(超高)~320dpi ~density=2
- xxhdpi(超超高)~480dpi ~density=3
- xxxhdpi(超超超高)~640dpi ~density=4
以上是对屏幕密度的描述,希望大家明白一点:分辨率越高的手机,指的是密度越高,即单位区域内像素越多。
从 Android 3.2(API 级别 13)开始,以上尺寸组已弃用,您 应改为使用 sw<N>dp
配置限定符来定义布局资源 可用的最小宽度。例如,如果多窗格平板电脑布局 需要至少 600dp 的屏幕宽度,应将其放在 layout-sw600dp/
中。声明适用于 Android 3.2 的平板电脑布局一节将进一步讨论如何使用新技术声明布局资源。
如果未配置到相应尺寸,则高分辨率的会向高配置的资源扩展,低分辨率的会向低配置的资源扩展。举个栗子:只有hdpi、xhdpi三种资源,则mdpi的手机默认使用hdpi,而xxhdpi使用xhdpi,以实现屏幕的最佳显示效果。
关于图片、布局和密度,根据上述参数可以做如下配置
上面是对大体的尺寸做适配,而安卓的厂商不要太多,各家规范又不太一致,因此可以对具体的尺寸做适配。
以上即对图片、布局,甚至具体尺寸做的适配。
适配的部分代码
switch (unit) {
case COMPLEX_UNIT_PX:
return value;
case COMPLEX_UNIT_DIP:
return value * metrics.density;
case COMPLEX_UNIT_SP:
return value * metrics.scaledDensity;
case COMPLEX_UNIT_PT:
return value * metrics.xdpi * (1.0f/72);
case COMPLEX_UNIT_IN:
return value * metrics.xdpi;
case COMPLEX_UNIT_MM:
return value * metrics.xdpi * (1.0f/25.4f);
}
return 0;
2、字体、布局大小
字体尽量用sp,间距和尺寸尽量用dp,理解density就可以明白,这样字体、间距和尺寸就会随着屏幕密度而自动改变为px
3、不同系统API不同-如setBackground,碎片化问题
举个栗子:不同系统对从webView本地拿图片方法不一样
public void openFileChooser(ValueCallback<Uri> uploadMsg) { listener.showConfirmDialog(uploadMsg); } // For Android 3.0+ public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) { listener.showConfirmDialog(uploadMsg); } // For Android 4.1 listener.showConfirmDialog(uploadMsg); }
更多详见:http://blog.csdn.net/reboot123/article/details/52461897
4、Cpu不同-如arm、mips、x86
一般不同手机,会适配不同硬件,而选择合适的cpu是驱动不同硬件达到完美状态的关键,arm是主流。厂商会根据不同功能如拍照美颜、视频流畅度选择不同cpu,有的比较放松如Nexus,有的比较严格如Oppo;严格的结果就是,如果你没有适配它的so包,则相关功能就不可用,银联3.2.5版本即是如此。
一般情况下只适配arm-v7a即可,x86会自动转译,mips几乎可以忽略
更多关于cpu的介绍:http://blog.csdn.net/reboot123/article/details/51601368
5、状态栏、导航栏、菜单栏的长度
比如:http://blog.csdn.net/u010156024/article/details/48321485
6、横竖屏切换,且各生命周期不再重新调用
1)Activity设置 android:configChanges="keyboard|screenSize|orientation|layoutDirection"
2)在Activity中实现onConfigurationChanged方法,重新布局和初始化数据(注意全局变量数据依然存在)
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mScreenChanged.set(true);//记录横竖屏发生过变化
if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
//land
setContentView(R.layout.activity_land);
initLand();//初始化横屏数据
} else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
//port
setContentView(R.layout.activity_port);
initPort();//初始化竖屏数据
}
}
3)在点击事件,强制执行横竖屏操作
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.iv_close:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//强制为竖屏
break;
case R.id.iv_stretch:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);//强制为横屏
break;
}
}
7、图片等比例缩放,需要maxWidth、maxHeight和adjustViewBounds设置为true同时进行才可以
注意,maxWidth和maxHeight不能直接设为屏幕宽高,否则等比例缩放会失败,因为某一方达到最大值,则另一方也会执行同样操作
photo = new ImageView(mContext);
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
photo.setLayoutParams(lp);
photo.setMaxWidth((int) (screenWidth * 0.99));
photo.setMaxHeight((int) (screenHeight * 0.99));
photo.setScaleType(ImageView.ScaleType.FIT_CENTER);
photo.setAdjustViewBounds(true);
如果需要左右滑动、拉伸缩放,做图片预览,那么可以用下面的资源:
http://download.csdn.net/detail/liuxian13183/9846522
ImageView的绘画,先后执行顺序为:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}
@Override
public void onGlobalLayout() {
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
前三个可能执行多次,最后一个仅执行一次。
8、H5调试方案:https://segmentfault.com/a/1190000009240637
更多技巧:http://blog.csdn.net/reboot123/article/details/46127797