⑴ android 布局优化之 ViewStub、 include、merge
文章、布局优化神器 include 、merge、ViewStub 标签详解
Tips:
include 标签使用:
//include_test.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"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@string/textview"
android:textSize="24sp"/>
<EditText
android:id="@+id/editText"
android:hint="@string/divide"
android:layout_width="300dp"
android:layout_height="wrap_content"/>
</LinearLayout>---------------------------------------------------------------
//include_text_relative
<?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"
android:gravity="center_horizontal"
>
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="TextView_Relative"
android:textSize="24sp"/>
<EditText
android:id="@+id/editText"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_below="@+id/textView"
android:hint="@string/divide"/>
</RelativeLayout>
---------------------------------------------------------------
//include_toolbar.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/tb_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#00f"
app:theme="@style/AppTheme"
app:title="这是一个 ToolBar"app:titleTextColor="@android:color/white"/>
<?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"
>
<!--测试 layout 和<include>都设置 ID 的情况-->
<include
android:id="@+id/tb_toolbar"
layout="@layout/include_toolbar"/>
<!--如果只有单个 include 这样写就可以,加载的布局的子 View,直接 findViewByID 就能找
到-->
<include layout="@layout/include_text"/>
<!--如果有多个 include,需要添加 ID 属性-->
<include
android:id="@+id/include_text1"
layout="@layout/include_text"/>
<!--这个 layout 用 RelativeLayout 实现-->
<!--如果要使用 layout_margin 这样的属性,要同时加上 layout_w/h 属性,不然没反应-->
<include
android:id="@+id/include_text2"
layout="@layout/include_text_relative"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="50dp"/>
</LinearLayout>
private void initView() {
//如果 include 布局根容器和 include 标签中的 id 设置的是不同的值,这里获取的
mToolbar 值将为 nullToolbar mToolbar = (Toolbar) findViewById(R.id.tb_toolbar);
setSupportActionBar(mToolbar);
//普通 include 标签用法,直接拿子 View 属性实现
TextView textView = (TextView) findViewById(R.id.textView);
textView.setText("不加 ID 实现的 include 标签");
//多个 include 标签用法,添加 ID,findViewByID 找到 layout,再找子控件
View view_include = findViewById(R.id.include_text1);
TextView view_include_textView = (TextView) view_include.findViewById(R.id.textView);
view_include_textView.setText("加了 ID 实现的 include 标签");
//多个 include 标签用法,添加 ID,findViewByID 找到 layout,再找子控件
View view_include_Relative = findViewById(R.id.include_text2);
TextView view_textView_relative =(TextView) view_include_Relative.findViewById(R.id.textView);
view_textView_relative.setText("加了 ID 实现的 include 标签(RelaviteLayout)");
}
include 标签 Demo 效果图
==include 使用注意==
merge标签主要用于辅助include标签,在使用include后可能导致布局嵌套过
多,多余的 layout 节点或导致解析变慢(可通过 hierarchy viewer 工具查看布
局的嵌套情况)官方文档说明:merge 用于消除视图层次结构中的冗余视图,例如根布局是
Linearlayout,那么我们又 include 一个 LinerLayout 布局就没意义了,反而会
减慢 UI 加载速度
merge 标签常用场景: .
根布局是 FrameLayout 且不需要设置 background 或 padding 等属性,可
以用merge代替,因为 Activity的 ContentView 父元素就是FrameLayout,
所以可以用 merge 消除只剩一个.
.某布局作为子布局被其他布局include时,使用merge当作该布局的顶节点,
这样在被引入时顶结点会自动被忽略,而将其子节点全部合并到主布局中.
.自定义 View 如果继承 LinearLayout(ViewGroup),建议让自定义 View 的
布局文件根布局设置成 merge,这样能少一层结点.
.merge 标签使用:
在 XML 布局文件的根布局如 RelativeLayout 直接改成 merge 即可
merge 标签使用前后 Hierarchy Viewer 截图
FrameLayout 替换 merge 前
FrameLayout 替换 merge 后
include 标签对应 layout 根布局 替换 merge 前
include 标签对应 layout 根布局 替换 merge 后
==merge 使用注意==
ViewStub 标签最大的优点是当你需要时才会加载,使用它并不会影响 UI 初始
化时的性能.各种不常用的布局像进度条、显示错误消息等可以使用 ViewStub
标签,以减少内存使用量,加快渲染速度.ViewStub 是一个不可见的,实际上是把
宽高设置为 0 的 View.效果有点类似普通的 view.setVisible(),但性能体验提高
不少
第一次初始化时,初始化的是 ViewStub View,当我们调用 inflate()或
setVisibility()后会被 remove 掉,然后在将其中的 layout 加到当前 view
hierarchy 中
ViewStub 官方文档链接
//官方例子
<ViewStub
android:id="@+id/stub_import"
<!--android:inflateId:重写 ViewStub 的父布局控件的 Id-->
android:inflatedId="@+id/panel_import"
< <!--android:layout:设置 ViewStub 被 inflate 的布局-->
android:layout="@layout/progress_overlay"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom" />
-------------------------------------------------//当你想加载布局时,可以使用下面其中一种方法:
((ViewStub)
findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);
// or
View importPanel = ((ViewStub)
findViewById(R.id.stub_import)).inflate();
判断 ViewStub(做单例)是否已经加载过:
1. 如果通过 setVisibility 来加载,那么通过判断可见性即可;
2. 如果通过 inflate()来加载,判断 ViewStub 的 ID 是否为 null 来判断
(findViewById(…))
public class ViewStubActivity extends AppCompatActivity
implements View.OnClickListener, ViewStub.OnInflateListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);setContentView(R.layout.activity_view_stub);
}
private View networkErrorView;
private void showNetError() {
// not repeated infalte
if (networkErrorView != null) {
//setVisibility()方式加载布局,加载次数不限
networkErrorView.setVisibility(View.VISIBLE);
return;
}
//inflate()方式加载布局,只能加载一次
ViewStub stub = (ViewStub)
findViewById(R.id.network_error_layout);
stub.setOnInflateListener(this);networkErrorView = stub.inflate();
Button networkSetting = (Button)
networkErrorView.findViewById(R.id.network_miss);
networkSetting.setOnClickListener(this);
Button refresh = (Button)
findViewById(R.id.network_refresh);
refresh.setOnClickListener(this);
}
private void showNormal() {
if (networkErrorView != null) {
networkErrorView.setVisibility(View.GONE);
}
}
public void show(View view) {showNetError();
}
public void refresh(View view) {
showNormal();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.network_miss:
Toast.makeText(this, "network_miss",
Toast.LENGTH_SHORT).show();
break;
case R.id.network_refresh:
Toast.makeText(this, "network_refresh",
Toast.LENGTH_SHORT).show();break;
}
}
/**
*
* @param stub 当前待 inflate 的 ViewStub 控件
* @param inflated 当前被 inflate 的 View 视图
*/
@Override
public void onInflate(ViewStub stub, View inflated) {
}
}
ViewStub 标签 Demo 效果图:
ViewStub 标签使用前后 Hierarchy Viewer 截图
ViewStub 标签使用前:
ViewStub 标签使用后:
==ViewStub 标签使用注意==
扩展:
Space 组件
在 ConstraintLayout 出来前,我们写布局都会使用到大量的 margin 或
padding,但是这种方式可读性会很差,加一个布局嵌套又会损耗性能
鉴于这种情况,我们可以使用space,使用方式和View一样,不过主要用来占位置,
不会有任何显示效果
⑵ Android-ConstraintSet进阶-不同显示效果
在Android应用开发中,页面的动态显示效果是提高用户体验的关键。为了实现页面中不同部分基于用户状态的显示,通常有多种布局策略。本文将探讨如何利用ConstraintSet进行高级布局以实现不同显示效果。
首先,介绍两种常见的布局策略:
1. 使用相对布局(RelativeLayout)和visibility属性来控制元素的显示和隐藏。这种方法直接通过代码实现元素的可见性管理,易于理解和操作,但缺点是布局文件与代码耦合度高。
2. 定义多套布局文件,并利用include方式动态添加到主布局中。这种方法使布局更灵活,但也增加了文件管理和维护的复杂性。
然而,随着技术的发展,ConstraintLayout提供了更强大的布局管理工具,尤其是ConstraintSet。它允许我们为布局中的元素创建复杂的约束关系,从而实现更动态和灵活的布局效果。
以按钮为例,利用ConstraintSet可以实现以下效果:
1. 显示两个按钮时,它们与左上角图标的对齐以及两个按钮之间的间距可以通过设置约束来实现。
2. 当需要隐藏左侧按钮时,右侧按钮可以自动靠左边显示,并保持与左边的间距。
在布局中,通过设置按钮间的marginLeft代替marginRight,可以在隐藏左侧按钮时保持右侧按钮与左侧的间距。这种布局方式比直接使用marginRight更为灵活。
面对布局设计时的间距问题,尤其是高度内容包裹的布局,设置间距不生效的情况,关键在于布局约束的完整性。通常,为避免这种问题,应确保布局中的所有元素都具有上下左右的约束。这不仅提高了布局的可预测性和一致性,还有助于避免布局内部的控件受到干扰。
使用ConstraintSet时,要确保约束的全面性。当布局中包含高度内容时,确保所有元素都有上下约束,同时避免遗漏。否则,布局渲染时可能会因缺少参考而出现问题。
总的来说,通过ConstraintSet,开发者能够更高效地管理复杂的布局约束,实现动态的显示效果。它不仅提高了布局的灵活性,也简化了代码的维护。当然,针对具体问题,开发者还需要根据实际情况灵活应用各种布局策略,以实现最佳的用户体验。
⑶ Android布局优化的几种方式
1. include/merge
布局优化中常常用到include/merge标签,include的含义类似C代码中的include,意思是直接把指定布局片段包含进当前的布局文件。include适用于多个布局文件中存在相同的xml片段,比如说相同的标题栏、相同的广告栏、相同的进度栏等等。
2. ViewStub
在一个页面上根据不同条件展示不同的控件,我们常常会设置控件的可视属性,比如调用指定控件的setVisibility方法,若需展示则设置View.VISIBLE,若需隐藏则设置View.GONE。不过gone的控件只是看不到罢了,实际UI渲染时还是会被加载。要想事先不加载,在条件符合时才加载,就得用到标签ViewStub。
3. style样式
样式在res/values/styles.xml中定义,它适用于下面几种情况:
1、布局文件中存在多个具有相同风格的控件,比如说统一的文本框TextView,都是白底黑字、中号字体、居中显示,这时我们便可在styles.xml定义一种文本样式,然后在各文本框处声明它的style属性。好处一个是减少了布局文件的大小,另一个是方便以后统一修改风格。
2、某些控件在代码中声明时需要手工指定style,例如自定义对话框需要在构造函数中指定样式;另一个例子是弹窗PopupWindow在设置伸缩动画方法setAnimationStyle时需要指定动画样式。
3、定义页面的主题风格,然后应用到Activity页面。代码中设置主题可通过“setTheme(R.style.)”完成,布局中设置可在AndroidManifest.xml的activity节点下添加theme属性,如“android:theme=”@style/“”。
4. Theme主题
主题是一种特殊的样式,主题专用于页面,而样式一般运用于控件。主题定义一般放在themes.xml,样式定义一般放在styles.xml。
Android定义了一些系统主题,完整定义的参见sdk自带的themes.xml,常用的几种说明如下:
Theme.NoTitleBar : 不显示标题栏,即隐藏ActionBar
Theme.Light : 白色背景
Theme.Holo : 浅灰背景
Theme.Black : 黑色背景
Theme.Wallpaper : 壁纸
Theme.Translucent : 透明背景
Theme.Dialog : 对话框
Theme.Panel : 平板
Theme.InputMethod : 输入法
Theme.SearchBar : 搜索框