温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

merge、include、ViewStub的作用及分析

发布时间:2020-09-03 20:46:36 来源:网络 阅读:2142 作者:一剑围城 栏目:移动开发

include:
方便复杂布局的重用,使得布局模块化。最常使用到的地方如在每个Activity中加入统一的状态栏。

merge:
减少include之后的布局层级。

ViewStub:
提高布局初次加载性能。常用于网络加载失败页,按需加载View等。

include、merge结合使用:
官方对<merge />的介绍中使用vertical的LinearLayout。当需要include的Layout也是vertical的LinearLayout时,会出现两个vertical的LinearLayout相互嵌套的情况,这除了降低UI性能之外没有其他作用。这时候可以把需要include的Layout的LinearLayout换成<merge />标签。这样在编译完成后TextView和两个Button就是同级的,不会再多一层。

注意:在include中如果需要重写layout_xxx属性,则必须同时重写layout_width和Layout_height。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/app_bg"
    android:gravity="center_horizontal">

    <include layout="@layout/titlebar"/>

    <TextView 
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:text="@string/hello"
              android:padding="10dp" />
</LinearLayout>

需要include的layout:
这里的LinearLayout和TextView同一层级。两个Button是其下一层子View。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal">

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/add"/>

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/delete"/>

</LinearLayout>

把root视图LinearLayout换成merge:
这里两个Button和TextView同一层级,LinearLayout在include后已经不存在了。

<merge xmlns:android="http://schemas.android.com/apk/res/android">

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/add"/>

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/delete"/>

</merge>

merge适用于哪些布局类型:
试验后<merge />适用于我们常用的FrameLayout、LinearLayout、RelativeLayout等。但从官方的介绍中只见到FrameLayout和相同orientation的LinearLayout。因为这两种情况下需要的include的View和原布局没有耦合性,也就是没关系。
而RelativeLayout使用<merge />需要知道两者布局的情况,比如toRightof的对象是谁等,这反而增加了两个布局之间的耦合性,而include的作用不就是解耦合么。故此,RelativeLayout不适用。
而如果只用到centerInParent、alignParentTop之类的RelativeLayout的属性,面对这种低程度的耦合,merge似乎还行。但这时候通常可以考虑更优的方案了。

对于FrameLayout来说,无论嵌套多少层,显示效果是一样的,但UI性能更差,对于相同orientation的LinearLayout来说,嵌套多层,显示效果也是一样的,但UI性能也是更差。

The <merge /> tag helps eliminate redundant view groups in your view hierarchy when including one layout within another.
译:merge标签帮助消除在一个布局中include进另外一个布局后,造成的View层级中冗余的view groups。

为什么会造成冗余:
之所以会造成View层级的冗余嵌套,是因为系统规定了每一个独立的布局文件都必须只有一个root view。而这个root view与内部的子View不一定存在必须的关系(例如,引用root view的id的情况),可能只是提供一个父布局让子类的layout_width等layout_xxxxx属性起作用而已。这个作用可以由include后的再上一层布局提供。这时root view就没用了。

代码中加载根标签为merge的布局文件:
由于merge在加载后就不存在了。就好像岳父拉着女朋友的手交给你,他就走了。这个过程是在inflate中完成的。而merge在子view找到新parent后就安心离开,如果没找到就不会放手,可怜×××。所以我们需要使用三个参数的inflate方法,在inflate的时候就指定新的parent,并attach。而root不需要再addView。
LayoutInflater.from(this).inflate(R.layout.titlebar, root, true);
不然会报错:
<merge /> can be used only with a valid ViewGroup root and attachToRoot=true.

tools:showIn="@layout/activity_main"
在merge标签中加入此属性,方便在编辑时查看本Layout在布局activity_main中include完成后的模样,所见即所得,方便修改。

ViewStub如何提高加载性能:
对于一般的View来说,只要在布局文件中声明了,那么在加载布局文件的时候,该View就会被加载进内存。并非布局中所有的View在首次加载时都需要,可以把首次不需要的放在ViewStub中。
ViewStub是一个不可见的、宽高为0、draw方法为空的轻量级的View,用于在运行时再加载指定布局资源从而优化布局加载速度。只有当setVisibility(Visible/InVisible)或inflate()方法被调用,才会加载布局资源替换自身在父布局中的位置,并使用ViewStub的布局参数。

ViewStub和include的对比:
都是用于引入其他的布局,和直接在布局文件中写入View相比,使用include的方式没有性能上的优势,反而可能降低性能。而使用ViewStub则能提高加载性能,例如,把一个复杂布局放在ViewStub中加载,则在该复杂布局不需要加载的时候,开销变成了加载ViewStub的轻量开销。

ViewStub注意:
1、ViewStub只能被加载一次,然后被inflate的layout所替换掉
2、不支持<merge />标签

不要使用ViewStub的对象,使用inflate返回的布局对象:

if (inflatedView == null) {
      ViewStub viewStub = findViewById(R.id.stub);
      inflatedView = viewStub.inflate();
}
TextView text = inflatedView.findViewById(R.id.text);
向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI