1、布局原则
1.1、使用RelativeLayout和LinearLayout
尽量多使用RelativeLayout和LinearLayout。
在布局层次一样的情况下,建议使用LinearLayout代替RelativeLayout(因为LinearLayout性能要稍高一点);
在结构层次复杂的时候建议使用RelativeLayout(因为RelativeLayout能简单实现LinearLayout嵌套才能实现的布局)。
1.2、使用include标签
将布局中公用的部分抽取出来并通过include标签引用;
开发中会遇到一些共用的UI组件,比如带返回按钮的导航栏,如果为每一个xml文件都设置这部分布局,一是重复的工作量大,二是如果有变更,那么每一个xml文件都得修改。因此我们可以将这些共用的组件抽取出来单独放到一个xml文件中,然后使用include标签导入共用布局。
下面在一个布局main.xml中用include引入另一个布局titlebar.xml为例。
//titlebar.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/mmtitle_bg_alpha" > <Button android:id="@+id/button" android:layout_width="75.0dip" android:layout_height="40dp" android:layout_centerVertical="true" android:layout_marginLeft="2dip" android:text="返回" /> <TextView android:id="@+id/text" android:textColor="#ffffff" android:layout_alignBaseline="@id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:gravity="center_vertical" android:text="@string/app_name" android:textSize="20dp" /> </RelativeLayout>
以上定义公用布局titlebar,然后在需要引入标题栏的布局main.xml中通过include导入这个共用布局:
//main.xml <FrameLayout 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" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/hello_world" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" > <include layout="@layout/titlebar" /> </RelativeLayout> </FrameLayout>
1.3、使用ViewStub标签
viewstub标签同include标签一样可以用来引入一个外部布局,但viewstub引入的布局默认不会扩张,即既不会占用显示也不会占用位置,从而在解析layout时节省cpu和内存。
viewstub常用来引入那些默认不会显示,只在特殊情况下显示的布局,如进度布局、网络失败显示的刷新布局、信息出错出现的提示布局等。
如创建一个error的布局文件显示网络错误的提示信息,如下:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:background="@android:color/white" android:padding="10dip" android:text="Message" android:textColor="@android:color/black" /> </RelativeLayout>
然后在main.xml里面加入ViewStub的标签引入上面的布局,修改main.xml文件如下:
<merge 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" > <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/hello_world" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" > <include layout="@layout/titlebar" /> </RelativeLayout> <ViewStub android:id="@+id/error_layout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout="@layout/error" /> </FrameLayout> </merge>
在java代码中通过(ViewStub)findViewById(id)找到ViewStub,通过stub.inflate()展开ViewStub,然后得到子View,如下:
private View errorView; private void showError() { // not repeated infalte if (errorView != null) { errorView.setVisibility(View.VISIBLE); return; } ViewStub stub = (ViewStub) findViewById(R.id.error_layout); errorView = stub.inflate(); } private void showContent() { if (errorView != null) { errorView.setVisibility(View.GONE); } }
1.4、使用merge标签
merge标签的作用是合并UI布局,使用该标签能降低UI布局的嵌套层次。merge标签可用于两种典型情况:
1)布局根结点是FrameLayout且不需要设置background或padding等属性,可以用merge代替,因为Activity内容布局的parent view就是个FrameLayout,所以可以用merge消除只剩一个,这一点可以从上图中看到。
//main.xml <merge 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" > <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/hello_world" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" > <include layout="@layout/titlebar" /> </RelativeLayout> </FrameLayout> </merge>
2)某布局作为子布局被其他布局include时,使用merge当作该布局的顶节点,这样在被引入时顶结点会自动被忽略,而将其子节点全部合并到主布局中。
如:foot.xml布局文件中,将原本是RelativeLayout改成merge
<merge xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="@dimen/dp_40" android:layout_above="@+id/text"/> <TextView android:id="@+id/text" android:layout_width="match_parent" android:layout_height="@dimen/dp_40" android:layout_alignParentBottom="true" android:text="@string/app_name" /> </merge>
然后布局main.xml中使用include标签引用再引用该foot.xml布局,如下:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <ListView android:id="@+id/simple_list_view" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="@dimen/dp_80" /> <include layout="@layout/foot.xml" /> </RelativeLayout>
这样,main.xml文件中就不会有多余的Relativelayout布局了,而是直接将foot布局中的button和textview直接加入根布局中。