Android布局优化:include,merge,viewStub总结

inlucde

为了解决重复定义的布局问题,可以多处复用布局

用法以及注意点

1.一个xml布局文件有多个include标签需要设置ID,才能找到相应子View的控件,否则只能找到第一个include的layout布局,以及该布局的控件
2.当include布局设置了id的同时,导入的布局也设置了id,此时应该用导入的布局设置的id,否则会报空指针,通过查看源码知道,导入的布局文件都会调用LayoutInflater的inflate方法,此方法中可以清楚看到一个TAG_INCLUDEDE的标签

        else if (TAG_INCLUDE.equals(name)) {
            if (parser.getDepth() == 0) {
                throw new InflateException("<include /> cannot be the root element");
            }
            parseInclude(parser, context, parent, attrs);
        }

再来看看parseInclude的代码

        if (TAG_MERGE.equals(childName)) {
            // The <merge> tag doesn't support android:theme, so
            // nothing special to do here.
            rInflate(childParser, parent, context, childAttrs, false);
        } else {
            final View view = createViewFromTag(parent, childName,
                    context, childAttrs, hasThemeOverride);
            final ViewGroup group = (ViewGroup) parent;

            final TypedArray a = context.obtainStyledAttributes(
                    attrs, R.styleable.Include);
            final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
            final int visibility = a.getInt(R.styleable.Include_visibility, -1);
            a.recycle();

            // We try to load the layout params set in the <include /> tag.
            // If the parent can't generate layout params (ex. missing width
            // or height for the framework ViewGroups, though this is not
            // necessarily true of all ViewGroups) then we expect it to throw
            // a runtime exception.
            // We catch this exception and set localParams accordingly: true
            // means we successfully loaded layout params from the <include>
            // tag, false means we need to rely on the included layout params.
            ViewGroup.LayoutParams params = null;
            try {
                params = group.generateLayoutParams(attrs);
            } catch (RuntimeException e) {
                // Ignore, just fail over to child attrs.
            }
            if (params == null) {
                params = group.generateLayoutParams(childAttrs);
            }
            view.setLayoutParams(params);

            // Inflate all children.
            rInflateChildren(childParser, view, childAttrs, true);
			//这个位置,如果include设置了id的话,直接用设置的id
            if (id != View.NO_ID) {
                view.setId(id);
            }
        }

通过以上源码可以知道,标签若指定了ID属性,而你的layout也定义了ID,则你的layout的ID会被覆盖,拿的时候应该拿标签指定的id

merge

当一个layout包含另外一个layout时,merge标签是用来帮助在视图树中减少重复布局的

用法以及注意点

不使用情况下
layout1.xml

<FrameLayout>
   <include layout="@layout/layout2"/>
</FrameLayout>

layout2.xml

<FrameLayout>
   <TextView />
</FrameLayout>

实际效果

<FrameLayout>
   <FrameLayout>
      <TextView />
   </FrameLayout>
</FrameLayout>

使用merge
layout1.xml不变,layout2.xml

<merge>
   <TextView />
</merge>

实际效果:

<FrameLayout>
   <TextView />
</FrameLayout>

注意点:
1.根布局是FrameLayout且不需要设置background或padding等属性,可以用merge代替,因为Activity的ContentView父元素就是FrameLayout,所以可以用merge消除只剩一个

2.因为merge标签并不是View,所以在通过LayoutInflate.inflate()方法渲染的时候,第二个参数必须指定一个父容器,且第三个参数必须为true,也就是必须为merge下的视图指定一个父亲节点.由于merge不是View所以对merge标签设置的所有属性都是无效的,源码体现:

public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
	......
    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);
    }
}

ViewStub

官方介绍: A ViewStub is an invisible, zero-sized View that can be used to lazily inflate layout resources at runtime. When a ViewStub is made visible, or when inflate() is invoked, the layout resource is inflated. The ViewStub then replaces itself in its parent with the inflated View or Views. Therefore, the ViewStub exists in the view hierarchy until setVisibility(int) or inflate() is invoked. The inflated View is added to the ViewStub’s parent with the ViewStub’s layout parameters. Similarly, you can define/override the inflate View’s id by using the ViewStub’s inflatedId property
意识就是说,ViewStub默认不可见,通过调用setVisibility函数或者Inflate函数才会将其要装载的目标布局给加载出来,从而达到懒加载的效果,这个要被加载的布局通过android:layout属性来设置,各种不常用的布局想进度条、显示错误消息等可以使用标签,以减少内存使用量,加快渲染速度。

((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE); 

用法以及注意点

1.ViewStub只能Inflate一次,之后ViewStub对象会被置为空。按句话说,某个被ViewStub指定的布局被Inflate后,就不会够再通过ViewStub来控制它了。
2.ViewStub只能用来Inflate一个布局文件,而不是某个具体的View

总结

使用include标签重用布局
使用merge标签避免冗余的布局嵌套
使用ViewStub实现按需加载

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值