Android布局优化:include 、merge、ViewStub详细总结
1.include的用法
- include.xml
<LinearLayout 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"
android:background="@android:color/white"
android:orientation="vertical">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="100dp"
android:layout_marginRight="20dp"
android:hint="请输入用户名" />
<include layout="@layout/include_login" />
</LinearLayout>
- include_login.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="wrap_content">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:text="登录按钮" />
</LinearLayout>
层级关系如下图:

image.png
2.merge的用法
include标签存在着一个不好的地方,可能会导致产生多余的布局嵌套。merge标签存在的意义就是帮助include标签排除多余的一层ViewGroup容器,减少View的层级结构,提升UI渲染的性能。
- merge.xml
<LinearLayout 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"
android:orientation="vertical"
android:background="@android:color/white">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="100dp"
android:hint="请输入用户名" />
<include layout="@layout/merge_login" />
</LinearLayout>
- merge_login.xml
<?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:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:text="登录按钮" />
</merge>
使用merge标签优化后的层级关系如下图:

image.png
注意:根布局是FrameLayout且不需要设置background或padding等属性时,可以用merge代替,因为Activity的contentView父元素就是FrameLayout,所以可以用merge消除。
3.ViewStub用法
ViewStub也可以用来加载布局文件,但与include标签完全不同。ViewStub是一个不可见的View类,用于在运行时按需懒加载资源,只有在代码中调用了viewStub.inflate()或者viewStub.setVisible(View.visible)方法时才内容才变得可见.
- view_stub.xml
<LinearLayout 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"
android:background="@android:color/white"
android:orientation="vertical" >
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="40dp"
android:hint="请输入用户名" />
<ViewStub
android:id="@+id/viewstub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/view_stub_info" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="showViewStub"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="10dp"
android:text="显示" />
</LinearLayout>
- view_stub_info.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content" >
<EditText
android:id="@+id/weichat_id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="10dp"
android:hint="请输入微信号" />
<EditText
android:id="@+id/address_id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="10dp"
android:hint="请输入家庭住址" />
</LinearLayout>
- showViewStub()方法显示ViewStub
public void showViewStub(){
ViewStub stub = ((ViewStub) findViewById(R.id.viewstub));
if(stub!=null){
View stubView=stub.inflate();
EditText address = (EditText) stubView.findViewById(R.id.address_id);
EditText wechatId = (EditText) stubView.findViewById(R.id.weichat_id);
}
}
三.ConstraintLayout
1.基线布局

image.png
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:textSize="50sp"
android:textStyle="bold"
android:text="20"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="¥"
android:textSize="25sp"
app:layout_constraintLeft_toRightOf="@id/tv_1"
app:layout_constraintBaseline_toBaselineOf="@id/tv_1"/>
</androidx.constraintlayout.widget.ConstraintLayout>
2.角度约束
- layout_constraintCircle 指定一个视图作为圆形约束的中心点
- layout_constraintCircleRadius 中心点到视图的距离【约束半径】
- layout_constraintCircleAngle 约束角度

image.png

image.png
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_android"
android:layout_width="180dp"
android:layout_height="180dp"
android:src="@mipmap/ic_launcher"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<ImageView
android:id="@+id/jetpack"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@mipmap/demo_device_android"
android:background="@color/btn_pressed_green_solid"
app:layout_constraintCircle="@+id/iv_android"
app:layout_constraintCircleRadius="90dp"
app:layout_constraintCircleAngle="45"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>
3.红包树
- layout_constraintVertical_bias 控制视图在竖直方向上的偏移量(0.0--1.0之间),必须保证视图在竖直方向上居中,才能使用该属性.
0.0 靠近顶部约束
0.5 竖直居中
1.0 靠近底部约束
//竖直居中
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
- layout_constraintHorizontal_bias 控制视图在水平方向上的偏移量(0.0--1.0之间),必须保证视图在水平方向上居中,才能使用该属性.
0.0 靠近左边约束
0.5 水平居中
1.0 靠近右边约束
//水平居中
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"

image.png
示例
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--背景底图-->
<ImageView
android:id="@+id/treebg"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:background="@mipmap/ic_tree_bg_daytime"/>
<!--黄金树-->
<ImageView
android:id="@+id/treeIv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_tree_6"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintVertical_bias="0.40" />
<!--相对于黄金树,水平偏移0.10,竖直便宜0.26-->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_red_packet_9"
app:layout_constraintTop_toTopOf="@id/treeIv"
app:layout_constraintBottom_toBottomOf="@id/treeIv"
app:layout_constraintLeft_toLeftOf="@id/treeIv"
app:layout_constraintRight_toRightOf="@id/treeIv"
app:layout_constraintHorizontal_bias="0.10"
app:layout_constraintVertical_bias="0.26" />
<!--相对于黄金树,水平偏移0.10,竖直便宜0.49-->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="@id/treeIv"
app:layout_constraintBottom_toBottomOf="@id/treeIv"
app:layout_constraintRight_toRightOf="@id/treeIv"
app:layout_constraintLeft_toLeftOf="@id/treeIv"
android:background="@mipmap/ic_red_packet_9"
app:layout_constraintHorizontal_bias="0.10"
app:layout_constraintVertical_bias="0.49"
/>
<!--相对于黄金树,水平方向偏移0.28,竖直方向偏移0.15-->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="@id/treeIv"
app:layout_constraintBottom_toBottomOf="@id/treeIv"
app:layout_constraintLeft_toLeftOf="@id/treeIv"
app:layout_constraintRight_toRightOf="@id/treeIv"
android:background="@mipmap/ic_red_packet_9"
app:layout_constraintHorizontal_bias="0.28"
app:layout_constraintVertical_bias="0.15"/>
<!--相对于黄金树,水平方向偏移0.34,竖直方向偏移0.44-->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="@id/treeIv"
app:layout_constraintBottom_toBottomOf="@id/treeIv"
app:layout_constraintLeft_toLeftOf="@id/treeIv"
app:layout_constraintRight_toRightOf="@id/treeIv"
android:background="@mipmap/ic_red_packet_9"
app:layout_constraintHorizontal_bias="0.34"
app:layout_constraintVertical_bias="0.44"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="@id/treeIv"
app:layout_constraintBottom_toBottomOf="@id/treeIv"
app:layout_constraintLeft_toLeftOf="@id/treeIv"
app:layout_constraintRight_toRightOf="@id/treeIv"
android:background="@mipmap/ic_red_packet_9"
app:layout_constraintHorizontal_bias="0.6"
app:layout_constraintVertical_bias="0.11"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="@id/treeIv"
app:layout_constraintBottom_toBottomOf="@id/treeIv"
app:layout_constraintLeft_toLeftOf="@id/treeIv"
app:layout_constraintRight_toRightOf="@id/treeIv"
app:layout_constraintHorizontal_bias="0.52"
app:layout_constraintVertical_bias="0.42"
android:background="@mipmap/ic_red_packet_9"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="@id/treeIv"
app:layout_constraintBottom_toBottomOf="@id/treeIv"
app:layout_constraintLeft_toLeftOf="@id/treeIv"
app:layout_constraintRight_toRightOf="@id/treeIv"
android:background="@mipmap/ic_red_packet_9"
app:layout_constraintHorizontal_bias="0.8"
app:layout_constraintVertical_bias="0.14"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/ic_red_packet_9"
app:layout_constraintTop_toTopOf="@id/treeIv"
app:layout_constraintBottom_toBottomOf="@id/treeIv"
app:layout_constraintRight_toRightOf="@id/treeIv"
app:layout_constraintLeft_toLeftOf="@id/treeIv"
app:layout_constraintHorizontal_bias="0.76"
app:layout_constraintVertical_bias="0.51" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="@id/treeIv"
app:layout_constraintBottom_toBottomOf="@id/treeIv"
app:layout_constraintLeft_toLeftOf="@id/treeIv"
app:layout_constraintRight_toRightOf="@id/treeIv"
app:layout_constraintHorizontal_bias="0.95"
app:layout_constraintVertical_bias="0.38"
android:background="@mipmap/ic_red_packet_9" />
</androidx.constraintlayout.widget.ConstraintLayout>