New UI-<merge>标签减少视图层级,让布局更高效
——转载请注明出处:coder-pig,欢迎转载,请勿用于商业用途!
小猪Android开发交流群已建立,欢迎大家加入,无论是新手,菜鸟,大神都可以,小猪一个人的
力量毕竟是有限的,写出来的东西肯定会有很多纰漏不足,欢迎大家指出,集思广益,让小猪的博文
更加的详尽,帮到更多的人,O(∩_∩)O谢谢!
小猪Android开发交流群:小猪Android开发交流群群号:421858269
新Android UI实例大全目录:http://blog.csdn.net/coder_pig/article/details/42145907
本节引言:
前面我们已经学了布局优化的两个小技巧:
①使用include简化布局,解决布局复用的;②ViewStub延时加载,加快页面加载速度
那么今天再给大家介绍一个标签<merge>,"merge"直译"合并,混合",难道是合并布局?
呵呵,没错,你猜对了,是合并布局,不过有点遗憾的是,他合并的布局只能是:FrameLayout(帧布局)
只能合并一种布局,也没想象中那么种,仅仅减少关于FrameLayout的冗余层次,从而达到优化UI
的目的,事实如此,也不必多解释什么,不过每一样都系都有自己存在的意义,可能现在界面比较简单
的时候并不能体现他的价值,以后就知道了...而<merge>通常是
搭配着<include>标签来使用的,嗯呢,废话不多说,开始本节内容吧!
本节正文:
一个简单的FrameLayout的布局中:有一个普通的TextView:
布局文件如下:
<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="com.jay.example.test.MainActivity" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:gravity="center" android:text="呵呵" android:textSize="20sp" /> </FrameLayout>
直接:LinearLayout -> FrameLayout -> TextView 么?
带着疑惑,我们打开之前教过大家的布局层次查看工具:Hierarchy Viewer
如图,竟然出现了两个FrameLayout,第一反应,这没必要吧,把第二个FrameLayout搞掉!
恩,先不急,听我娓娓道来,从图中我们可以了解到这样一个信息,布局的结构基础都是:
PhoneWindowsDecorView -> LinearLayout ->FrameLayout
接下来加载的布局资源都跟在这个FrameLayout后面就比如上面的布局
或许你还不信,我们在FrameLayout里添加上一个LinearLayout和一个TextView:
好了,上面这个图就验证了我们的说法,那么我们怎么来消除(优化)这个多余的FrameLayout呢?
就要用到今天要介绍的这个<merge>标签了!
答:超简单,直接把布局文件的外层的FrameLayout改成merge即可:
看下布局文件:
<merge xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:gravity="center" android:text="呵呵" android:textSize="20sp" /> </merge>
!!代替一层FrameLayout,如果是其他布局的话,他就没作用了哦!
除了上面这种应用情况外,我们更多的时候是跟这个include组合使用的
这里找了网上的一个经典例子给大家体会下:
先看下层次图:
接下来就贴代码咯
编写流程:
①创建按钮布局文件okcalcelbar_button.xml
②创建okcancelbar.xml的文件,通过include引入两个上面的按钮
③values目录下面创建自定义属性的文件attrs.xml
④创建OkCancelBar类继承LinearLayout
⑤创建主布局文件
详细代码:
okcalcelbar_button.xml
<?xml version="1.0" encoding="utf-8"?> <Button xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" />
<?xml version="1.0" encoding="utf-8"?> <merge xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" > <include android:id="@+id/okcancelbar_ok" layout="@layout/okcalcelbar_button" /> <include android:id="@+id/okcancelbar_cancel" layout="@layout/okcalcelbar_button" /> </merge>
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="OkCancelBar"> <attr name="okLabel" format="string"/> <attr name="cancelLabel" format="string"/> </declare-styleable> </resources>
package com.xzw.merge; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.view.Gravity; import android.view.LayoutInflater; import android.widget.Button; import android.widget.LinearLayout; public class OkCancelBar extends LinearLayout { public OkCancelBar(Context context, AttributeSet attrs) { super(context, attrs); setOrientation(HORIZONTAL); // 横排 setGravity(Gravity.CENTER); // 居中显示 setWeightSum(1.0f); LayoutInflater.from(context).inflate(R.layout.okcancelbar, this, true); // TypedArray是一个数组容器 TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.OkCancelBar, 0, 0); String text = array.getString(R.styleable.OkCancelBar_okLabel);// 这里的属性是:名字_属性名 if (text == null) text = "Ok"; ((Button) findViewById(R.id.okcancelbar_ok)).setText(text); text = array.getString(R.styleable.OkCancelBar_cancelLabel); if (text == null) text = "Cancel"; ((Button) findViewById(R.id.okcancelbar_cancel)).setText(text); array.recycle(); } }
<?xml version="1.0" encoding="utf-8"?> <merge xmlns:android="http://schemas.android.com/apk/res/android" xmlns:okCancelBar="http://schemas.android.com/apk/res/com.xzw.merge"> <ImageView android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="center" android:src="@drawable/golden_gate" /> <com.xzw.merge.OkCancelBar android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:paddingTop="8dip" android:gravity="center_horizontal" android:background="#AA000000" okCancelBar:okLabel="Save" okCancelBar:cancelLabel="Don't save" /> </merge>
代码难点分析:
①attrs.xml文件:
上面自定义属性文件中OkCancelBar就是定义在<declare-styleable name="OkCancelBar">
</declare-styleable> 里的名字,获取里面属性用 名字_ 属性 连接起来就可以.
TypedArray 通常最后调用 .recycle() 方法,为了保持以后使用该属性一致性!
②activity_main.xml文件
xmlns:okCancelBar:是我们自定义属性的命名空间前缀。
也就是下面 okCancelBar:okLabel="Save" okCancelBar:cancelLabel="Don‘t save"
用到的 "http://schemas.android.com/apk/res/com.xzw.merge"
其中com.xzw.merge 是类文件所在包名。使用自定义属性必须加上该命名空间。
ps:简单点说就是attrs.xml自定义两个属性,以及设置属性的类型,然后在使用该自定义属性的布局中,
需要添加
xmlns:"declare-styleable里的name值"="http://schemas.android.com/apk/res/自定义类文件所在包名"
然后可以通过:
TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.OkCancelBar, 0, 0);
获取里面两个属性的值!接下来的就自己想咯!
①merge标签只能作为xml文件的根节点,就是最外层的那个
②merge只能合并FrameLayout哦,如果根节点为LinearLayout或者其他,再使用<merge>标签
就会报错哦!
③使用LayoutInflater的inflate方法加载<merge>标签的布局文件时,需要为他指定一个父容器控件,
并且设置attachToRoot属性为true!!!
最后说两句:
关于merge合并布局就写到这里,如果后续有什么新的发现,会补上...
本节demo下载:MergeTest
参考资料:
http://bbs.51cto.com/thread-969619-1.html
原文地址:http://blog.csdn.net/coder_pig/article/details/43282683