Android自适应屏幕与动态加载不同的子View
此文所涉及内容网上资源比较多,大部分内容都是引用别人的东西做个归类总结,最后简单实现个demo。
一、自适应分辨率 1.google官方提供的自适应分辨率相关文档 一个笑话:IPhone5出来当天,IOS程序员一上班立马找到Android工程师,说:“哥们,你得帮帮我!”Android工程师大惑:平时都趾高气扬的,今天怎么低声下气。问:“啥事?”IOS程序员笑道:“如何适配不同分辨率的屏幕?”Android工程师丢给他一链接,说:“自己看!” http://t.cn/zlvCVz1“
笑话归笑话,Android系统支持多分辨率,产品泛滥,用户爽了,但开发人员就特别蛋疼。google官方也提供了很多关于多分辨率支持相关文章: 1). 《 Supporting Multiple Screens》 2). 《 Supporting Different Screens》 3). 《D esigning for Multiple Screens》
《Supporting Multiple Screens》文中提到一些相关的术语,部分译文如下:
术语和概念
屏幕尺寸
屏幕的物理尺寸,以屏幕的对角线长度作为依据(比如2.8寸,3.5寸)。
简而言之,Android把所有的屏幕尺寸简化为四类:超大、大、正常、小。(small,normal,large,andextralarge.)
程序可以针对这四种尺寸的屏幕提供三种不同的布局方案,然后系统会负责把你的布局方案以合适的方式渲染到对应的屏幕上,这个过程是不需要程序员用代码来干预的。
屏幕密度
物理屏幕上的像素总数。与尺寸类似,也有四种:低、中、高、超高。(low,medium,high,andextrahigh.)密度较低的屏幕,在长和宽方向都只有比较少的像素,而高密度的屏幕通常则会有很多——甚至会非常非常多——像素排列在同一区域。屏幕的密度是非常重要的,举个例子,长宽以像素为单位定义的界面元素(比如一个按钮),在低密度的屏幕上会显得很大,但在高密度的屏幕上则会显得很小。
屏幕长宽比
屏幕的物理长度与物理宽度的比例。程序可以为制定长宽比的屏幕提供制定的素材,只需要用系统提供的资源分类符long和notlong。
分辨率
屏幕上拥有的像素的总数。注意,虽然大部分情况下分辨率都被表示为“宽度×长度”,但分辨率并不意味着屏幕长宽比。在Android系统中,程序一般并不直接处理分辨率。
密度无关的像素(DIP)
指一个抽象意义上的像素,程序用它来定义界面元素。它作为一个与实际密度无关的单位,帮助程序员构建一个布局方案(界面元素的宽度,高度,位置)。
一个与密度无关的像素,在逻辑尺寸上,与一个位于像素密度为160DPI的屏幕上的像素是一致的,这也是Android平台所假定的默认显示设备。在运行的时候,平台会以目标屏幕的密度作为基准,“透明地”处理所有需要的DIP缩放操作。要把密度无关像素转换为屏幕像素,可以用这样一个简单的公式:pixels=dips*(density/160)。举个例子,在DPI为240的屏幕上,1个DIP等于1.5个物理像素。我们强烈推荐你用DIP来定义你程序的界面布局,因为这样可以保证你的UI在各种分辨率的屏幕上都可以正常显示。
支持的屏幕分辨率范围
1.5及更早版本的Android系统,在设计的时候假定系统只会运行在一种分辨率的设备上——HVGA(320×480)分辨率,尺寸为3.2寸。由于系统只能工作在一种屏幕上,开发人员就可以针对那个屏幕来编写自己的程序,而无需去考虑程序在其他屏幕上的显示问题。
但自从Android1.6以来,系统引入了对多种尺寸、多种分辨率屏幕的支持,以此满足拥有各种配置的新平台的运行需求。这就意味着开发人员在针对Android1.6或更新版系统开发程序的时候,需要为自己的程序在多种分辨率的屏幕上良好显示作出额外的设计。
为了简化程序员面在对各种分辨率时的困扰,也为了具备各种分辨率的平台都可以直接运行这些程序,Android平台将所有的屏幕以密度和分辨率为分类方式,各自分成了四类:
·四种主要的尺寸:超大、大,正常,小;
·四种不同的密度:超高、高(hdpi),中(mdpi)和低(ldpi)。
如果需要的话,程序可以为各种尺寸的屏幕提供不同的资源(主要是布局),也可以为各种密度的屏幕提供不同的资源(主要是位图)。除此以外,程序不需要针对屏幕的尺寸或者密度作出任何额外的处理。在执行的时候,平台会根据屏幕本身的尺寸与密度特性,自动载入对应的资源,并把它们从逻辑像素(DIP,用于定义界面布局)转换成屏幕上的物理像素。
下表列出了Android平台支持的屏幕中一些比较常用的型号,并显示了系统是如何把它们分类到不同的屏幕配置里的。有些屏幕分辨率并不在下面的列表上,但系统仍会把它们归入下列的某一个类型中。
Figure 1.Illustration of how Android roughly maps actual sizes and densities to generalized sizes and densities (figures are not exact).
Low density (120),ldpi | Medium density (160),mdpi | High density (240),hdpi | Extra high density (320),xhdpi | |
---|---|---|---|---|
Smallscreen | QVGA (240x320) | 480x640 | ||
Normalscreen | WQVGA400 (240x400) WQVGA432 (240x432) | HVGA (320x480) | WVGA800 (480x800) WVGA854 (480x854) 600x1024 | 640x960 |
Largescreen | WVGA800** (480x800) WVGA854** (480x854) | WVGA800* (480x800) WVGA854* (480x854) 600x1024 | ||
Extra Largescreen | 1024x600 | WXGA (1280x800)† 1024x768 1280x768 | 1536x1152 1920x1152 1920x1200 | 2048x1536 2560x1536 2560x1600 |
2.自适应分辨率常用方法 在《 android:屏幕自适应》一文中介绍了几种技巧,几种方法归纳如下: 1) 权重法:利用layout_weight来控制各个结构的权重 2) 自定义尺寸法:根据values-WxH的自适应方式,创建不同分辨率的dimens.xml(此方法使用defaults.xml文档也是可行的,defaults.xml文件中可以定义int,String等基本配置信息) 3) 代码设置法:在java中动态获取屏幕宽高,再对布局控件进行设置位置和宽高 4) 多布局:此法是最常用的方式也是最笨的方法,为多个布局适配不一样的布局文件,在资源文件夹中可以有各种自动适配的命名方式,如:drawable-hdpi、drawable-ldpi、drawable-800x480、drawable-hdpi-854x480、values-land(横屏)、values-port(竖屏)、values-1024x768等等,包括上边提到的values-WxH
3.其它布局技术 1)采用HTML设计软件界面,此种方式需要用HTML设计好界面和相关界面上的Javascript响应逻辑操作,如果需要反馈信息就比较麻烦了。这种方法比较适合有网页开发经验的程序员使用,详细见《 android软件开发之webView.addJavascriptInterface循环渐进》一文。
2)jQuery Mobile是 jQuery 在手机和平板设备上的版本,用于创建针对智能手机和平板电脑的跨设备Web应用。详细见《 jQuery Mobile 1.1.0发布》
二、动态加载子View 有时候需要重用同一个View或者动态切换子View的话,比较好的解决方式是使用LayoutInflater来实例化XML布局为View对象,然后通过ViewGroup的addView方式加载新的View。简单用法如下:
private LayoutInflater mLayoutInflater = null;private FrameLayout dynamicChangesView = null;private View newViewOne = null;……mLayoutInflater = (LayoutInflater) mContext.getSystemService(LAYOUT_INFLATER_SERVICE);newViewOne = mLayoutInflater.inflate(R.layout.view_one, null,false);dynamicChangesView.addView(newViewOne);
关于LayoutInflater,比较常见的地方是在1)ListView的Adapter中、 2)Dialog或 PopupWindow自定义布局、3)动态加载子View 。
相关用法见google提供APIs。
三、本文例子
1.例子部分界面
2.布局文件及资源文件 1)defaults.xml
<?xml version="1.0" encoding="utf-8"?><resources> <integer name="layout_weight_left">8</integer> <integer name="layout_weight_right">17</integer> <integer name="layout_weight_one">1</integer> <integer name="layout_weight_two">2</integer> <integer name="layout_weight_three">3</integer> <integer name="layout_weight_four">4</integer></resources>
2)styles.xml
<resources> </style> <!-- 全屏幕拉伸 --> <style name="layout_full"> <item name="android:layout_width">fill_parent</item> <item name="android:layout_height">fill_parent</item> </style> <!-- 固定自身大小 --> <style name="layout_wrap"> <item name="android:layout_width">wrap_content</item> <item name="android:layout_height">wrap_content</item> </style> <!-- 横向分布 --> <style name="layout_horizontal" parent="layout_full"> <item name="android:layout_width">0px</item> </style> <!-- 纵向分布 --> <style name="layout_vertical" parent="layout_full"> <item name="android:layout_height">0px</item> </style> </resources>
3)activity_view_group.xml
<LinearLayout 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" android:baselineAligned="false" android:orientation="horizontal" > <LinearLayout android:id="@+id/optionsView" style="@style/layout_horizontal" android:layout_weight="@integer/layout_weight_left" android:orientation="vertical" > <Button android:id="@+id/selectViewOneBtn" style="@style/layout_vertical" android:layout_weight="@integer/layout_weight_one" android:background="@color/color_btn_one" android:text="@string/view_one" /> <Button android:id="@+id/selectViewTwoBtn" style="@style/layout_vertical" android:layout_weight="@integer/layout_weight_one" android:background="@color/color_btn_two" android:text="@string/view_two" /> <Button android:id="@+id/selectViewThreeBtn" style="@style/layout_vertical" android:layout_weight="@integer/layout_weight_one" android:background="@color/color_btn_three" android:text="@string/view_three" /> </LinearLayout> <FrameLayout android:id="@+id/dynamicChangesView" style="@style/layout_horizontal" android:layout_weight="@integer/layout_weight_right" /></LinearLayout>
4)view_one.xml
<?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 style="@style/layout_vertical" android:layout_weight="@integer/layout_weight_one" android:background="@color/color_one" /> <TextView style="@style/layout_vertical" android:layout_weight="@integer/layout_weight_two" android:background="@color/color_two" /> <TextView style="@style/layout_vertical" android:layout_weight="@integer/layout_weight_three" android:background="@color/color_three" /> <TextView style="@style/layout_vertical" android:layout_weight="@integer/layout_weight_four" android:background="@color/color_four" /></LinearLayout>
5)view_three.xml
<?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" > <LinearLayout style="@style/layout_vertical" android:layout_weight="@integer/layout_weight_three" > <include layout="@layout/view_one" /> </LinearLayout> <LinearLayout style="@style/layout_vertical" android:layout_weight="@integer/layout_weight_three" > <include layout="@layout/view_two" /> </LinearLayout> <LinearLayout style="@style/layout_vertical" android:layout_weight="@integer/layout_weight_one" android:orientation="horizontal" > <Button android:id="@+id/display_button" style="@style/layout_horizontal" android:layout_weight="@integer/layout_weight_one" android:background="@color/color_btn_display" android:text="@string/display_button" /> <Button android:id="@+id/hide_button" style="@style/layout_horizontal" android:layout_weight="@integer/layout_weight_one" android:background="@color/color_btn_hide" android:text="@string/hide_button" /> </LinearLayout></LinearLayout>
3.java实现代码 1)DynamicChangesView.java
public class DynamicChangesView extends Activity { private Button selectViewOneBtn = null; private Button selectViewTwoBtn = null; private Button selectViewThreeBtn = null; private LayoutInflater mLayoutInflater = null; public LinearLayout optionsView = null; private FrameLayout dynamicChangesView = null; private View newViewOne = null; private View newViewTwo = null; private View newViewThree = null; private Context mContext = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initData(); } private void initData() { mContext = this; setContentView(R.layout.activity_view_group); selectViewOneBtn = (Button) findViewById(R.id.selectViewOneBtn); selectViewTwoBtn = (Button) findViewById(R.id.selectViewTwoBtn); selectViewThreeBtn = (Button) findViewById(R.id.selectViewThreeBtn); optionsView = (LinearLayout) findViewById(R.id.optionsView); dynamicChangesView = (FrameLayout) findViewById(R.id.dynamicChangesView); selectViewOneBtn.setOnClickListener(mOnClickListener); selectViewTwoBtn.setOnClickListener(mOnClickListener); selectViewThreeBtn.setOnClickListener(mOnClickListener); dynamicChangesView.setOnClickListener(mOnClickListener); mLayoutInflater = (LayoutInflater) mContext .getSystemService(LAYOUT_INFLATER_SERVICE); newViewOne = mLayoutInflater.inflate(R.layout.view_one, null,false); newViewTwo = mLayoutInflater.inflate(R.layout.view_two, null,false); // newViewThree = mLayoutInflater.inflate(R.layout.view_three, null,false); newViewThree = new ViewThree(mContext); dynamicChangesView.addView(newViewOne); } private OnClickListener mOnClickListener = new OnClickListener() { @Override public void onClick(View v) { if(v == selectViewOneBtn){ dynamicChangesView.removeAllViews(); Log.v("", "-----------> selectViewOneBtn"); dynamicChangesView.addView(newViewOne); }else if(v == selectViewTwoBtn){ dynamicChangesView.removeAllViews(); Log.v("", "-----------> selectViewTwoBtn"); dynamicChangesView.addView(newViewTwo); }else if(v == selectViewThreeBtn){ dynamicChangesView.removeAllViews(); Log.v("", "-----------> selectViewThreeBtn"); dynamicChangesView.addView(newViewThree); }else if(v == dynamicChangesView){ if(optionsView.getVisibility() == View.GONE) optionsView.setVisibility(View.VISIBLE); else optionsView.setVisibility(View.GONE); } } };}
2).ViewThree.java (此处实现耦合不好)
public class ViewThree extends FrameLayout{ private LayoutInflater mLayoutInflater = null; private Button displayButton = null; private Button hideButton = null; private DynamicChangesView mActivity = null; public ViewThree(Context context) { super(context); mActivity = (DynamicChangesView)context; mLayoutInflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); this.addView(mLayoutInflater.inflate(R.layout.view_three, null,false)); displayButton = (Button) findViewById(R.id.display_button); hideButton = (Button) findViewById(R.id.hide_button); displayButton.setOnClickListener(mOnClickListener); hideButton.setOnClickListener(mOnClickListener); } public ViewThree(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public ViewThree(Context context, AttributeSet attrs) { super(context, attrs); } private OnClickListener mOnClickListener = new OnClickListener() { @Override public void onClick(View v) { if(v == displayButton){ mActivity.optionsView.setVisibility(View.VISIBLE); }else if(v == hideButton){ mActivity.optionsView.setVisibility(View.GONE); } } }; }
参考引用:
1.《android多分辨率支持[最新版,包括Extra Large screen]》 2.《 android:屏幕自适应 》 3.《 android软件开发之webView.addJavascriptInterface循环渐进 》 4.《 jQuery Mobile 1.1.0发布 》 5. Google APIs LayoutInflater 6. Google APIs ViewGroup
7. Google APIs FrameLayout 8.《 Android杂谈--LayoutInflater和MenuInflater用法 》
更多相关文章
- 移动应用界面设计的尺寸规范
- android分辨率(屏幕适配)
- Android(安卓)屏幕的适配
- Android实现截屏与截长图功能
- Android之sp和dip的区别
- Android屏幕相关知识
- Android(安卓)- 小功能 - Android中dp和px之间进行转换
- 监听android屏幕亮、暗、锁和关闭系统动作
- 第九章 多语言环境的支持和多屏幕的适配(2)