本章节讲述布局优化时三种标签的详解
一.include标签
include标签常用于将布局中的公共部分提取出来供其他layout使用,以实现布局模块化。
代码
1.公共Layout
<?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="80dp"
android:background="@color/app_color"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_marginTop="20dp"
android:layout_height="60dp">
<RelativeLayout
android:id="@+id/apptoplayout_onlyback_backlayout"
android:layout_width="60dp"
android:layout_height="match_parent"
android:layout_alignParentLeft="true">
<ImageView
android:id="@+id/apptoplayout_onlyback_imageview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:scaleType="fitCenter"
android:background="@mipmap/back" />
</RelativeLayout>
<TextView
android:id="@+id/apptoplayout_onlyback_titletextview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginTop="20dp"
android:layout_alignParentRight="true"
android:layout_marginRight="60dp"
android:layout_toRightOf="@+id/apptoplayout_onlyback_backlayout"
android:gravity="center"
android:singleLine="true"
android:ellipsize="end"
android:textColor="@color/whilecolor"
android:textSize="16sp" />
</RelativeLayout>
</LinearLayout>
2.引入使用页面的Layout
<?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/apptoplayout_onlyback" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/appbackground_color"
android:scrollbars="none">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
......
</LinearLayout>
</ScrollView>
</LinearLayout>
即:
<include layout="@layout/apptoplayout_onlyback" />
3.引入使用的Activity
titletextview= (TextView) findViewById(R.id.apptoplayout_onlyback_titletextview);
这样就可以了。
注意:被引入的模块布局父布局要确定宽高(尤其是高)然后直接引入即可。如果不确定宽高都是(match_parent)就要在引入的时候确定宽高
多个布局
4.layout1
<?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/includelayout1_button"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="10dp"
android:background="@color/btn_answer_normal"
android:text="布局一按钮"
android:textColor="#FFFFFF" />
</LinearLayout>
5.layout2
<?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="100dp"
android:orientation="vertical">
<Button
android:id="@+id/includelayout2_button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/btn_gray_pressed"
android:text="布局二按钮"
android:layout_marginTop="10dp"
android:textColor="#FFFFFF" />
</LinearLayout>
6.layout3
<?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="100dp"
android:orientation="vertical">
<Button
android:id="@+id/includelayout3_button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/btn_logout_normal"
android:text="布局三按钮"
android:layout_marginTop="10dp"
android:textColor="#FFFFFF" />
</LinearLayout>
7.主页面布局
<?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/includelayout1"
android:layout_width="match_parent"
android:layout_height="100dp" />
<include layout="@layout/includelayout2" />
<include layout="@layout/includelayout3" />
</LinearLayout>
8.主页面效果
9.主页面使用
package wjn.com.imwithdemo.activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import wjn.com.imwithdemo.R;
public class IncludeDemoActivity extends AppCompatActivity {
private Button button1;
private Button button2;
private Button button3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_includedemo);
button1=findViewById(R.id.includelayout1_button);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(IncludeDemoActivity.this,"按钮一被点击!",Toast.LENGTH_LONG).show();
}
});
button2=findViewById(R.id.includelayout2_button);
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(IncludeDemoActivity.this,"按钮二被点击!",Toast.LENGTH_LONG).show();
}
});
button3=findViewById(R.id.includelayout3_button);
button3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(IncludeDemoActivity.this,"按钮三被点击!",Toast.LENGTH_LONG).show();
}
});
}
}
附:include官方文档
https://developer.android.google.cn/training/improving-layouts/reusing-layouts
二.merge标签
merge用于消除视图层次结构中的冗余视图,例如根布局是Linearlayout,那么我们又include一个LinerLayout布局就没意义了,反而会减慢UI加载速度。又或者根布局是FrameLayout且不需要设置background或padding等属性,可以用merge代替,因为Activity的ContentView父元素就是FrameLayout,所以可以用merge消除只剩一个。
代码
1.被引入的布局
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:id="@+id/includelayout1_button1"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="10dp"
android:background="@color/btn_answer_normal"
android:text="布局一按钮一"
android:textColor="#FFFFFF" />
<Button
android:id="@+id/includelayout1_button2"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="10dp"
android:background="@color/btn_green_pressed"
android:text="布局一按钮二"/>
</merge>
2.主页面layout
<?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/includelayout1" />
</LinearLayout>
3.主页面效果
4.主页面代码
package wjn.com.imwithdemo.activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import wjn.com.imwithdemo.R;
public class IncludeDemoActivity extends AppCompatActivity {
private Button button1;
private Button button2;
private Button button3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_includedemo);
button1=findViewById(R.id.includelayout1_button1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(IncludeDemoActivity.this,"按钮一被点击!",Toast.LENGTH_LONG).show();
}
});
button2=findViewById(R.id.includelayout1_button2);
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(IncludeDemoActivity.this,"按钮二被点击!",Toast.LENGTH_LONG).show();
}
});
}
}
主页面父布局是LinearLayout且垂直排布,要引入的布局父布局也是LinearLayout且垂直排布。这样的话被引入的布局父布局完全可以修改成merge。这样系统忽略<merge />节点并且直接添加两个Button。
附:merge官方文档
https://developer.android.google.cn/training/improving-layouts/reusing-layouts
三.ViewStub标签
ViewStub 标签最大的优点是当你需要时才会加载,使用他并不会影响UI初始化时的性能。各种不常用的布局比如进度条、显示错误消息等可以使用<ViewStub />标签,以减少内存使用量,加快渲染速度。
ViewStub的使用有几个注意事项。
<1> ViewStub对象只可以inflate一次,之后ViewStub对象会被置为空。
<2> ViewStub不支持merge,不能引入包含merge标签的布局到ViewStub中。否则会报错
can be used only with a valid ViewGroup root and attachToRoot=true
代码
1.要引入的textview布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/textview_layout_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/textview_layout_textview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary"
android:gravity="center"
android:text="我是TextView"
android:textColor="#FFFFFF"
android:textSize="25dp" />
</LinearLayout>
2.主页面layout
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary"
tools:context=".MainActivity">
<ViewStub
android:id="@+id/activity_main_viewstub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inflatedId="@+id/textview_layout_layout"
android:layout="@layout/textview_layout">
</ViewStub>
</androidx.constraintlayout.widget.ConstraintLayout>
注意:
<1> 使用id activity_main_viewstub获取ViewStub,ViewStub在加载布局之后,ViewStub本身消失。其中设置的
android:inflatedId="@+id/textview_layout_layout"
指定加载后布局ID,这里加载后是要引入的textview布局,其父布局id
android:id="@+id/textview_layout_layout"
两者一致。
3.主页面代码
package com.example.test;
import android.os.Bundle;
import android.view.View;
import android.view.ViewStub;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private ViewStub viewStub;
private View view;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewStub = findViewById(R.id.activity_main_viewstub);
if (null == view) {
if (viewStub != null) {
view = viewStub.inflate();
}
}
//执行了viewStub.inflate();之后 布局就引入成功,要引入的布局中的View使用和普通ViewfindViewById一样
textView = findViewById(R.id.textview_layout_textview);
textView.setText("引入后动态设置TextView字符串");
}
}
注意:
<1> 由于ViewStub第一次inflate的时候,就已经将需要显示的布局替换掉自己了,所以第二次inflate的时候,getParent()是null,所以就会报异常。解决方法是inflate()的时候将view保存起来,然后下次判断这个View是否为null,如果是null就inflate()。否则就直接使用这个view。
<2> 也可通过以下方式获取
findViewById(R.id.activity_viewstubdemo_viewstub2).setVisibility(View.VISIBLE);
附:ViewStub官方文档
https://developer.android.google.cn/training/improving-layouts/loading-ondemand