使用include、merge、ViewStub优化布局

在布局优化中,Androi的官方提到了这三种布局include、merge、ViewStub下面我们对这三种布局的使用和注意事项进行说明:

include 标签

include标签是xml布局重用的利器,假设我们在做标题栏的时候,每个页面都会使用如下样式的标题栏:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content">

    <TextView  android:id="@+id/tvTitle" android:layout_width="match_parent" android:layout_height="72dp" android:gravity="center" android:background="@android:color/holo_blue_dark" android:textColor="@android:color/white" android:textSize="18sp" android:text="Title"/>

</RelativeLayout>

效果如下:

假设我们有10个页面,那我们就要重复写十遍这样的代码?如果更改标题栏的样式呢?我们还要每个页面都修改一次?想想太可怕了。放心,include标签不会让你这么做的。接下来我们使用include标签来试试这个需求。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">

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

    <LinearLayout  android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/holo_red_dark">

    </LinearLayout>
</LinearLayout>

我们在Activity的布局中使用include标签来引用了title_layout,效果如下:

使用include、merge、ViewStub优化布局_第1张图片

使用include注意事项:

  • include标签使用layout属性来指定要引用的布局,而不是android:layout属性。
  • 在include标签中所有的android:layout_*都是有效的,前提是必须要写layout_width和layout_height两个属性。
  • 可以使用其他属性。include 标签若指定了ID属性,而你的layout也定义了ID,则你的layout的ID会被覆盖
  • 布局中可以包含两个相同的include标签,引用时可以使用如下方法解决
View include1 = findViewById(R.id.include1);
View include2 = findViewById(R.id.include2);

TextView textView1 = (TextView) include1.findViewById(R.id.tvTitle);
TextView textView2 = (TextView) include2.findViewById(R.id.tvTitle);

textView1.setText("textView1");
textView2.setText("textView2");

merge 标签

merge标签在UI的结构优化中起着非常重要的作用,它可以删减多余的层级,优化UI。merge多用于替换FrameLayout或者当一个布局包含另一个时,merge标签消除视图层次结构中多余的视图组。例如你的主布局文件是垂直布局,引入了一个垂直布局的include,这是如果include布局使用的LinearLayout就没意义了,使用的话反而减慢你的UI表现。这时可以使用merge标签优化。

我们通过代码来演示一下:

layout_merge.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">

        <TextView  android:layout_width="match_parent" android:layout_height="wrap_content" android:text="11111111111"/>

        <TextView  android:layout_width="match_parent" android:layout_height="wrap_content" android:text="11111111111"/>

</LinearLayout>

这是一个垂直的LinearLayout布局,这个布局将会被include引用到另外一个布局中。

activity_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">

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

</LinearLayout>

同样是一个垂直的LinearLayout布局,在这其中使用include标签引用了layout_merge布局,我们运行之后通过Hierarchy Viewer看一下布局的层次。

使用include、merge、ViewStub优化布局_第2张图片

从图中我们看到,两个LinearLayout明显是冗余的,这个时候我们就可以使用merge标签来优化了。我们来具体操作一下。

我们只需要将layout_merge.xml的根布局LinearLayout改成merge即可,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">

        <TextView  android:layout_width="match_parent" android:layout_height="wrap_content" android:text="11111111111"/>

        <TextView  android:layout_width="match_parent" android:layout_height="wrap_content" android:text="11111111111"/>

</merge>

运行后,使用Hierarchy Viewer来查看布局层次如下:

使用include、merge、ViewStub优化布局_第3张图片

我们可以看到少了一个LinearLayout。这就是merge的作用。

当使用include标签来添加一个根布局为merge标签的布局时,系统会忽略merge结点,并将其中的内容直接添加到include标签所在的布局中。

注意事项:
1.merge标签只能是一个文件的根结点,然后使用include标签在其他文件中引用带有merge标签的文件。
2.如果是activity的布局,并且根结点是FrameLayout的布局,也可以使用merge来替代FrameLayout。(因为我们activity的布局会被系统添加到id为content的FrameLayout中去)

ViewStud 标签

ViewStub标签最大的优点是当你需要时才会加载,使用他并不会影响UI初始化时的性能。各种不常用的布局想进度条、显示错误消息等可以使用ViewStub标签,以减少内存使用量,加快渲染速度。ViewStub 是一个不可见的,大小为0的View。ViewStub 标签使用如下:

我们这里使用上面的layout_merge.xml进行演示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">

    <TextView  android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="11111111111" />

    <TextView  android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="22222222" />

</LinearLayout>

我们看到这儿LinearLayout中有两个TextView,在看看如何使用ViewStub:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">

    <Button  android:id="@+id/btnShowViewStub" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="显示viewStub"/>

    <ViewStub  android:id="@+id/viewStub" android:layout_width="match_parent" android:layout_height="match_parent" android:inflatedId="@+id/layoutViewStub" android:layout="@layout/layout_merge"/>

</LinearLayout>

这里有一个button和一个ViewStub,ViewStub标签使用android:layout属性来引用要延迟加载的布局。这里指定了inflatedId为layoutViewStub。

其中inflatedId就是新加载进来的view的id,如果需要获取这个view,就要用这个inflatedId,原来的id已经被取代了

在看看Java代码中的操作。

ViewStub viewStub;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_layout);

    viewStub = (ViewStub) findViewById(R.id.viewStub);

    findViewById(R.id.btnShowViewStub).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // 加载(显示)viewStub对应的布局,并接受返回的View对象
            View view = viewStub.inflate();
            // 获取返回View对象中的TextView1控件
            TextView textView = (TextView) view.findViewById(R.id.textView1);
            // 修改TextView文本
            textView.setText("修改TextView1");
            // 显示ViewStub中的内容,但是不会反回View对象
            // viewStub.setVisibility(View.VISIBLE);
        }
    });

}

当调用inflate()函数的时候,ViewStub被引用的资源替代,并且返回引用的view。 这样程序可以直接得到引用的view而不用再次调用函数findViewById()来查找了。

需要注意的是ViewStub只能inflate一次,反复的inflate会报错:java.lang.IllegalStateException:ViewStub must have a non-null ViewGroup viewParent。

你可能感兴趣的:(android,优化,ViewStub,include,merge)