Android 布局优化的几个技巧

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。这将是恶性循环。

<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自带分割线

一般我们的设置页面都会有很多条目,每个条目之间都是有一根分割线的,一般很多的人做法是用一个view来占据空间,其实我们可以用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>

效果图:


其中divider.xml如下:
<?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源码如下,其实它在draw中未绘制任何东西,所以性能是几乎没有影响的,大可放心使用。
/**
 * 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>

效果:


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值