Android 布局优化:include-、merge,android 开发入门与实战作者
xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="{activityClass}" >
<includeandroid:layout_width="match_parent"android:layout_height="40dp"layout="@layout/titlebar" />
<Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"a
ndroid:layout_centerVertical="true"android:onClick="click"android:text="点我。。。" />
</RelativeLayout>
include 标签使用还是很简单的,主要通过 layout 属性声明要引入的布局即可。运行程序界面如下:
include 标签使用注意点:
1,<include>标签当中,可以重写所有 layout 属性的,如上面 include 中指定的 layout 属性将会覆盖掉 titlebar 中指定的 layout 属性。而非 layout 属性则无法在<include>标签当中进行覆写。另外需要注意的是,如果我们想要在<include>标签当中覆写 layout 属性,必须要将 layout_width 和 layout_height 这两个属性也进行覆写,否则覆写效果将不会生效 2,一个 xml 布局文件有多个 include 标签需要设置 ID,才能找到相应子 View 的控件,否则只能找到第一个 include 的 layout 布局,以及该布局的控件。3,如果我们给 include 所加载的 layout 布局的根容器设置了 id 属性,也在 include 标签中设置了 id 属性,同时需要在代码中获取根容器的控件对象时,最好将这两个 id 设置相同的名称!否则,可能获取不到根容器对象,即为 null。
二、merge 的用法以及注意点
merge
标签存在的意义是帮助include
标签排除多余的一层 ViewGroup 容器,减少 view hierarchy 的结构,提升 UI 渲染的性能。include 标签存在着一个不好的地方,可能会导致产生多余的布局嵌套。同样通过一个小 demo 来说明:
比如项目中有一个公共的登录按钮布局,如下:
login.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="wrap_content"android:orientation="vertical" >
<Buttonandroid:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:text="登录按钮" />
</LinearLayout>
很简单,就是一个登录的 Button。
项目中有登录功能的 UI 界面如下:
activity_login.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:orientation="vertical"android:background="@android:color/holo_blue_light">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="40dp"
android:hint="请输入用户名" />
<include layout="@layout/login" />
</LinearLayout>
同样非常简单,运行程序,如下:
看起来没什么问题,其实不知不觉中我们多嵌套了一层布局。我们用工具查看一下此时布局结构:
除去系统布局,我们自己布局最外层是 LinearLayout,然后两个并列布局 EditText 与 LinearLayout,在 LinearLayout 里面是 Button 登录按钮。
其实这种情况下:在主界面中,<include>
标签的 parent ViewGroup 与包含的 layout 根容器 ViewGroup 是相同的类型,这里都是 LinearLayout,那么则可以将包含的 layout 根容器 ViewGroup 使用<merge>
标签代替,从而减少一层 ViewGroup 的嵌套,提升 UI 渲染性能。
这里我们把 activity_login.xml 修改如下:
<?xml version="1.0" encoding="utf-8"?><merge xmlns:android="http://schemas.android.com/apk/res/android">
<Buttonandroid:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:text="登录按钮" />
</merge>
重新运行程序 UI 和上面一样效果,通过工具再次查看布局结构;
看到了吧,我们自己布局减少了一层嵌套,从而提升了 UI 的渲染速度。
merge 标签使用注意点:
1,根布局是 FrameLayout 且不需要设置 background 或 padding 等属性,可以用 merge 代替,因为 Activity 的 ContentView 父元素就是 FrameLayout,所以可以用 merge 消除只剩一个.
2,因为 merge 标签并不是 View,所以在通过 LayoutInflate.inflate()方法渲染的时候,第二个参数必须指定一个父容器,且第三个参数必须为 true,也就是必须为 merge 下的视图指定一个父亲节点.由于 merge 不是 View 所以****对 merge 标签设置的所有属性都是无效的.
LayoutInflate 中源码体现:
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {synchronized (mConstructorArgs) {
...
if (TAG_MERGE.equals(name)) {if (root == null || !attachToRoot) {throw new InflateException("<merge /> can be used only with a valid "
"ViewGroup root and attachToRoot=true");}
rInflate(parser, root, inflaterContext, attrs, false);}...}}
3,merge 标签必须使用在根布局,并且 ViewStub 标签中的 layout 布局不能使用 merge 标签.
###三、ViewStub 的用法以及注意点
ViewStub 也可以用来加载布局文件,但与 include 标签完全不同。ViewStub 是一个不可见的 View 类,用于在运行时按需懒加载资源,只有在代码中调用了 viewStub.inflate()或者 viewStub.setVisible(View.visible)方法时才内容才变得可见。这里需要注意的一点是,当 ViewStub 被 inflate 到 parent 时,ViewStub 就被 remove 掉了,即当前 view hierarchy 中不再存在 ViewStub,而是使用对应的 layout 视图代替。
同样我们通过一个小 demo 说明一下,比如我们需要保存一个用户信息,用户名是必须保存的,但是其余信息是不必要的,这是其余信息就可以一开始不显示出来,用户想输入的时候在现实出来。
其余信息布局如下:
otherinfo.xml:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:orientation="vertical"android:layout_height="wrap_content" >
<EditTextandroid:id="@+id/weichat_id"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="20dp"android:layout_marginRight="20dp"android:layout_marginTop="10dp"android:hint="请输入微信号" />
<EditTextandroid:id="@+id/address_id"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="20dp"android:layout_marginRight="20dp"android:layout_marginTop="10dp"android:hint="请输入家庭住址" />
</LinearLayout>
很简单,没什么其余解释的,主界面布局如下:
activity_main.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:background="@android:color/holo_blue_light"android:orientation="vertical" >
评论