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>标签来使用的,嗯呢,废话不多说,开始本节内容吧!
本节正文:
1.一个简单的例子引入<merge>
一个简单的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>标签了!
2)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>
没错,就是这么简单,从上面我们就可以看出,merge的作用是:
!!代替一层FrameLayout,如果是其他布局的话,他就没作用了哦!
除了上面这种应用情况外,我们更多的时候是跟这个include组合使用的
3)include结合merge:
这里找了网上的一个经典例子给大家体会下:
先看下层次图:
接下来就贴代码咯
编写流程:
①创建按钮布局文件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" />
okcancelbar.xml
- <?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>
attrs.xml
- <?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>
OkCancelBar.java:
- 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();
- }
- }
activity_main.xml:
- <?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);
获取里面两个属性的值!接下来的就自己想咯!
4)merge的一些注意事项:
①merge标签只能作为xml文件的根节点,就是最外层的那个
②merge只能合并FrameLayout哦,如果根节点为LinearLayout或者其他,再使用<merge>标签
就会报错哦!
③使用LayoutInflater的inflate方法加载<merge>标签的布局文件时,需要为他指定一个父容器控件,
并且设置attachToRoot属性为true!!!
最后说两句:
关于merge合并布局就写到这里,如果后续有什么新的发现,会补上...
本节demo下载:MergeTest
参考资料:
http://bbs.51cto.com/thread-969619-1.html