首页 > 代码库 > New UI-<merge>标签减少视图层级,让布局更高效

New UI-<merge>标签减少视图层级,让布局更高效

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=http://www.mamicode.com/"@drawable/golden_gate" />>

代码难点分析:

①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








New UI-<merge>标签减少视图层级,让布局更高效