1、重用< include/>
< include>标签可以在一个布局中引入另外一个布局,做到布局的重用
如下代码是项目中的一个公共的标题栏布局title_bar.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="?android:actionBarSize"
android:background="@color/common_title_background">
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:src="@drawable/ic_menu_back" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="@color/white"
android:textSize="@dimen/common_text_size_36"
tools:text="@string/app_task_title" />
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:gravity="center"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:textColor="@color/white"
android:textSize="@dimen/common_text_size_32"
tools:text="@string/filter_title" />
</RelativeLayout>
Preview:
接下来就可以在其他布局中重用这个布局了,代码如下:
<?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="match_parent">
<include
layout="@layout/title_bar"/>
</Relativelayout>
2、合并
减少嵌套
-
在不影响层级深度的情况下,使用LinearLayout而不是RelativeLayout。因为RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,才会让子View调用2次onMeasure。Measure的耗时越长那么绘制效率就低。
-
如果非要是嵌套,那么尽量避免RelativeLayout嵌套RelativeLayout。这将是恶性循环。
在不影响层级深度的情况下,使用LinearLayout而不是RelativeLayout。因为RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,才会让子View调用2次onMeasure。Measure的耗时越长那么绘制效率就低。
如果非要是嵌套,那么尽量避免RelativeLayout嵌套RelativeLayout。这将是恶性循环。
<merge/>
-
子视图不需要指定任何针对父视图的布局属性。
-
假如需要在LinearLayout里面嵌入一个布局,而这个布局的根节点也是LinearLayout,这样就多了一层没有用的嵌套,无疑这样只会拖慢程序速度。而这个时候如果我们使用merge根标签就可以避免那样的问题。
子视图不需要指定任何针对父视图的布局属性。
假如需要在LinearLayout里面嵌入一个布局,而这个布局的根节点也是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">
<include
layout="@layout/title_bar"/>
</merge>
我们可以通过Android Studio的View Hierarchy工具来查看比较这两个布局文件的区别。
3、按需载入ViewStub
每天的开发过程中经常遇到这样的情况,根据不同的条件来决定哪些View显示以及隐藏,通常我们的做法是将其加入到布局中设置其不可见,用的时候在设置可见,这样的话是会创建view的,并无形中影响了性能。
其实我们可以用ViewStub来替换,他是一个轻量级的View,不占布局的位置,而且占用的资源很小。
例如,我们有个重复的开关,默认进入是关闭的,打开后可以选择开始时间和结束时间,布局文件如下:
<?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">
<Switch
android:id="@+id/switch_repeat"
android:layout_width="match_parent"
android:layout_height="?android:actionBarSize"
android:padding="@dimen/left_margin"
android:text="@string/repeat"
android:textSize="@dimen/common_text_size_36" />
<ViewStub
android:id="@+id/view_datetime_picker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:inflatedId="@+id/view_datetime_picker"
android:layout="@layout/view_datetime_picker" />
</LinearLayout>
在activity或者fragment中的用法:
mSwitchButton.setOnCheckedChangeListener(
new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if (isChecked) {
if (datePickView == null) {
ViewStub viewStub = (ViewStub) ContactRemindSettingActivity.this
.findViewById(
R.id.view_datetime_picker);
datePickView = viewStub.inflate();
}
datePickView.setVisibility(View.VISIBLE);
} else {
if (datePickView != null) {
datePickView.setVisibility(View.GONE);
}
}
}
});
4、巧用LinearLayout自带分割线
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@drawable/divider"
android:orientation="vertical"
android:showDividers="beginning|end|middle">
<TextView
android:layout_width="match_parent"
android:layout_height="?android:actionBarSize"
android:background="@color/white"
android:drawableLeft="@drawable/ic_personal_invitation"
android:drawablePadding="@dimen/left_margin"
android:drawableRight="@drawable/icon_message_more"
android:gravity="center_vertical"
android:padding="@dimen/left_margin"
android:text="未完成事项"
android:textSize="@dimen/common_text_size_36" />
<TextView
android:layout_width="match_parent"
android:layout_height="?android:actionBarSize"
android:background="@color/white"
android:drawableLeft="@drawable/ic_personal_notice"
android:drawablePadding="@dimen/left_margin"
android:drawableRight="@drawable/icon_message_more"
android:gravity="center_vertical"
android:padding="@dimen/left_margin"
android:text="未完成事项"
android:textSize="@dimen/common_text_size_36" />
<TextView
android:layout_width="match_parent"
android:layout_height="?android:actionBarSize"
android:background="@color/white"
android:drawableLeft="@drawable/ic_personal_opinion"
android:drawablePadding="@dimen/left_margin"
android:drawableRight="@drawable/icon_message_more"
android:gravity="center_vertical"
android:padding="@dimen/left_margin"
android:text="检查更新"
android:textSize="@dimen/common_text_size_36" />
</LinearLayout>
效果图:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size
android:width="1dp"
android:height="1dp" />
<solid android:color="@color/divider_color" />
</shape>
showDividers是设置分割线的位置,有三个选项,diverPadding是给divider设置padding的
5、Space控件
上面的页面如果需要将检查更新和其他的进行分离,另成一组怎么办,这时Space就起作用了,相信很多人会用view或者设置topMatgin来实现。/**
* Space is a lightweight View subclass that may be used to create gaps between components
* in general purpose layouts.
*/
public final class Space extends View {
/**
* {@inheritDoc}
*/
public Space(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
if (getVisibility() == VISIBLE) {
setVisibility(INVISIBLE);
}
}
/**
* {@inheritDoc}
*/
public Space(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
/**
* {@inheritDoc}
*/
public Space(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
/**
* {@inheritDoc}
*/
public Space(Context context) {
//noinspection NullableProblems
this(context, null);
}
/**
* Draw nothing.
*
* @param canvas an unused parameter.
*/
@Override
public void draw(Canvas canvas) {
}
/**
* Compare to: {@link View#getDefaultSize(int, int)}
* If mode is AT_MOST, return the child size instead of the parent size
* (unless it is too big).
*/
private static int getDefaultSize2(int size, int measureSpec) {
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
result = size;
break;
case MeasureSpec.AT_MOST:
result = Math.min(size, specSize);
break;
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(
getDefaultSize2(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize2(getSuggestedMinimumHeight(), heightMeasureSpec));
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/lightgray"
android:divider="@drawable/divider"
android:orientation="vertical"
android:showDividers="beginning|end|middle">
<TextView
android:layout_width="match_parent"
android:layout_height="?android:actionBarSize"
android:background="@color/white"
android:drawableLeft="@drawable/ic_personal_invitation"
android:drawablePadding="@dimen/left_margin"
android:drawableRight="@drawable/icon_message_more"
android:gravity="center_vertical"
android:padding="@dimen/left_margin"
android:text="未完成事项"
android:textSize="@dimen/common_text_size_36" />
<TextView
android:layout_width="match_parent"
android:layout_height="?android:actionBarSize"
android:background="@color/white"
android:drawableLeft="@drawable/ic_personal_notice"
android:drawablePadding="@dimen/left_margin"
android:drawableRight="@drawable/icon_message_more"
android:gravity="center_vertical"
android:padding="@dimen/left_margin"
android:text="未完成事项"
android:textSize="@dimen/common_text_size_36" />
<Space
android:layout_width="match_parent"
android:layout_height="20dp"
android:background="@color/black" />
<TextView
android:layout_width="match_parent"
android:layout_height="?android:actionBarSize"
android:background="@color/white"
android:drawableLeft="@drawable/ic_personal_opinion"
android:drawablePadding="@dimen/left_margin"
android:drawableRight="@drawable/icon_message_more"
android:gravity="center_vertical"
android:padding="@dimen/left_margin"
android:text="检查更新"
android:textSize="@dimen/common_text_size_36" />
</LinearLayout>