通过标记重复使用布局
在Android开发中,通常需要重复使用特殊布局的大型组件,比如标题栏。
创建一个可重复使用的布局include_toolbar.xml包含一个Toolbar,Toolbar里面包含了一个TextView。
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
android:background="@color/colorPrimary">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="标题"/>
</androidx.appcompat.widget.Toolbar>
</FrameLayout>
现在在activity_main里面使用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
android:id="@+id/include"
layout="@layout/include_toolbar"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"/>
</LinearLayout>
现在就在activity_main里面插入了include_toolbar这个布局。
使用include标签有几个比较需要注意的点
1.include标签上的id属性会替换掉include布局的跟节点的id属性
2.include标签上的layout_*属性会替换掉include布局的根节点的layout_*属性
3.在约束布局中使用include标签,要想include标签上的约束条件生效,include标签必须具有 layout_width 和 layout_height 属性
使用<merge>标签来减少布局层次
如果我们使用include添加视图时,主布局是一个垂直的LinearLayout,而我们include标签内的跟视图也是一个垂直的LinearLayout。就会导致一个include时,垂直的LinearLayout里面会包含另一个垂直的LinearLayout。嵌套的LinearLayout除了降低性能外,没有任何实际的意义。
在这种情况下,可以使用merge标签来作为include视图的跟节点
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="添加"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="删除"/>
</merge>
现在,将此视图添加到其他布局中,系统会忽略merge标签并在布局中直接放置两个按钮
使用ViewStub延迟加载布局
有时候我们的布局可能在一开始的时候用不到或者很少使用。我们可以在需要使用的时候才加载这些布局,我们在activity的布局里使用ViewStub标签来延迟加载这些布局。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/btn1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="显示ViewStub"
android:textAllCaps="false"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/include"/>
<ViewStub
android:id="@+id/view_stub"
android:inflatedId="@+id/error_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout="@layout/stub_network_error"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
加载ViewStub布局
加载ViewSub指定的布局可以使用setVisibility(View.VISIBLE)或者调用inflate()
val errorView = findViewById<ViewStub>(R.id.view_stub).inflate()
值得注意的是,inflate()只能被调用一次。调用后ViewStub将不在是视图层次的一部分。它会被替换为layout里面的布局。该布局的跟视图的id就是android:inflatedId属性指定的id,为ViewStub指定的id只在布局可见之前有效。