布局优化技巧

来源:互联网 发布:app刷榜软件 编辑:程序博客网 时间:2024/06/03 04:26

布局优化技巧

重用

< include/>

< include>标签可以在一个布局中引入另外一个布局,这个的好处显而易见。类似于我们经常用到的工具类,随用随调。便于统一修改使用。
举例说明:首先写一个公共的布局title_bar.xml,app中常用的标题栏。
activity_main.xml调用:
我们也可以在< include>标签当中重新设置宽高等layout属性

<?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>

被调用xml,公共的布局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:background="@color/background"    android:layout_height="48dp">    <ImageView        android:layout_width="wrap_content"        android:layout_height="match_parent"        android:paddingLeft="15dp"        android:paddingRight="15dp"        android:src="@drawable/icon_back"/>    <TextView        tools:text="标题"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_centerInParent="true"        android:textSize="18sp"        android:textColor="@color/white" />    <TextView        tools:text="确定"        android:layout_width="wrap_content"        android:gravity="center"        android:layout_height="match_parent"        android:layout_alignParentRight="true"        android:paddingLeft="15dp"        android:paddingRight="15dp"        android:textSize="16sp"        android:textColor="@color/white" /></RelativeLayout>

合并

减少嵌套

首先我们心中要有一个大原则:尽量保持布局层级的扁平化。在这个大原则下我们要知道:
* 在不影响层级深度的情况下,使用LinearLayout而不是RelativeLayout。因为RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,才会让子View调用2次onMeasureMeasure的耗时越长那么绘制效率就低
* 如果非要是嵌套,那么尽量避免RelativeLayout嵌套RelativeLayout。这简直就是恶性循环,丧心病狂。

< merge/>

< merge/>主要用来去除不必要的FrameLayout。它的使用最理想的情况就是你的根布局是FrameLayout,同时没有使用background等属性。这时可以直接替换。因为我们布局外层就是FrameLayout,直接“合并”
举例说明:比如上面用到的activity_main.xml文件,我们通过View Hierarchy工具看一下,如图:
这里写图片描述
可以看到,最外层是FrameLayout,下来我们修改一下。

<?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>

再次查看:
这里写图片描述
很明显少了一层RelativeLayout,当然运行效果是一样的。当然如果我们不需要title_bar.xml中的绿色背景,那么可以这样修改。

<?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">    <ImageView        android:layout_width="wrap_content"        android:layout_height="48dp"        android:paddingLeft="15dp"        android:paddingRight="15dp"        android:src="@drawable/icon_back_1"/>    <TextView        android:layout_gravity="center_horizontal"        android:text="标题"        android:gravity="center"        android:layout_width="wrap_content"        android:layout_height="48dp"        android:layout_centerInParent="true"        android:textSize="18sp"        android:textColor="@color/black" />    <TextView        android:text="确定"        android:layout_gravity="right"        android:layout_width="wrap_content"        android:gravity="center"        android:layout_height="48dp"        android:layout_alignParentRight="true"        android:paddingLeft="15dp"        android:paddingRight="15dp"        android:textSize="16sp"        android:textColor="@color/black" /></merge>

运行效果:

这里写图片描述

运行查看层级,如下图:

这里写图片描述

结果很明显。

用TextView同时显示图片和文字

这个我就不细说了,举一个我们项目中的一个例子,代码一看便知。

首先要完成的效果是如下图:

这里写图片描述

这种效果很常见,一般实现方法是这样。(貌似没人这样写吧,哈哈)

<?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">    <LinearLayout        android:orientation="horizontal"        android:background="@color/white"        android:layout_width="match_parent"        android:layout_height="50dp">        <ImageView            android:layout_marginLeft="10dp"            android:layout_width="wrap_content"            android:src="@drawable/icon_1"            android:layout_height="match_parent" />        <TextView            android:paddingLeft="10dp"            android:paddingRight="10dp"            android:textSize="16sp"            android:text="我的卡券"            android:gravity="center_vertical"            android:layout_width="0dp"            android:layout_weight="1"            android:layout_height="match_parent" />        <ImageView            android:layout_marginRight="10dp"            android:src="@drawable/icon_4"            android:layout_width="wrap_content"            android:layout_height="match_parent"/>    </LinearLayout></LinearLayout>

效果图:

这里写图片描述

那么我们优化一下:

<?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">    <TextView        android:drawableLeft="@drawable/icon_1"        android:drawableRight="@drawable/icon_4"        android:drawablePadding="10dp"        android:paddingLeft="10dp"        android:paddingRight="10dp"        android:textSize="16sp"        android:text="我的卡券"        android:background="@color/white"        android:gravity="center_vertical"        android:layout_width="match_parent"        android:layout_height="50dp" /></LinearLayout>

你没有看错,少了两个ImageView和去除嵌套LinearLayout。效果不用说一样一样的。当然EditView等也一样的,还有属性drawableBottom和drawableTop供你使用。同时利用代码setCompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom)可以让我们动态去设置图片。

使用TextView的行间距

先上我们需要实现的效果图:

这里写图片描述

效果很简单,实现代码:

<?xml version="1.0" encoding="utf-8"?><LinearLayout    xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_height="100dp"    android:background="@color/white"    android:layout_width="match_parent"    xmlns:tools="http://schemas.android.com/tools">    <ImageView        android:padding="25dp"        android:src="@drawable/kd_1"        android:layout_width="100dp"        android:layout_height="100dp"/>    <LinearLayout        android:layout_width="match_parent"        android:orientation="vertical"        android:layout_height="100dp">        <TextView            tools:text="揽件方式:上门取件"            android:gravity="center_vertical"            android:layout_width="match_parent"            android:layout_height="25dp"/>        <TextView            tools:text="快递公司:顺丰快递"            android:gravity="center_vertical"            android:layout_width="match_parent"            android:layout_height="25dp"/>        <TextView            tools:text="预约时间:9月6日 立即取件"            android:gravity="center_vertical"            android:layout_width="match_parent"            android:layout_height="25dp"/>        <TextView            tools:text="快递费用:等待称重确定价格"            android:gravity="center_vertical"            android:layout_width="match_parent"            android:layout_height="25dp"/>    </LinearLayout></LinearLayout>

这里我偷懒了多嵌套了一层LinearLayout,但。。。这不重要,我先直接修改。

优化后代码:

<?xml version="1.0" encoding="utf-8"?><LinearLayout    xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_height="100dp"    android:background="@color/white"    android:layout_width="match_parent">    <ImageView        android:padding="25dp"        android:src="@drawable/kd_1"        android:layout_width="100dp"        android:layout_height="match_parent"/>    <TextView        android:textSize="14dp"        android:lineSpacingExtra="8dp"        android:gravity="center_vertical"        android:text="揽件方式:上门取件\n快递公司:顺丰快递\n预约时间:9月6日 立即取件\n快递费用:等待称重确定价格"        android:layout_width="match_parent"        android:layout_height="match_parent" /></LinearLayout>

老规矩,效果一样一样的。可以看到我们仅仅利用android:lineSpacingExtra="8dp"这一行代码就省去了3个TextView,如果行数更多呢?是不是方便多了。

其中:lineSpacingExtra属性代表的是行间距,他默认是0,是一个绝对高度值。同时还有lineSpacingMultiplier属性,它代表行间距倍数,默认为1.0f,是一个相对高度值。我们来使用一下:

<?xml version="1.0" encoding="utf-8"?><LinearLayout    xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_height="100dp"    android:background="@color/white"    android:layout_width="match_parent">    <ImageView        android:padding="25dp"        android:src="@drawable/kd_1"        android:layout_width="100dp"        android:layout_height="100dp"/>    <TextView        android:textSize="14dp"        android:lineSpacingMultiplier="1.3"        android:gravity="center_vertical"        android:text="揽件方式:上门取件\n快递公司:顺丰快递\n预约时间:9月6日 立即取件\n快递费用:等待称重确定价格"        android:layout_width="match_parent"        android:layout_height="match_parent" /></LinearLayout>

当然了这两条属性可以同时使用,查看源码可以知道,他们的高度计算规则为mTextPaint.getFontMetricsInt(null) * 行间距倍数 + 行间距。

使用Spannable或Html.fromHtml

这里也是举例说明,比如下图效果:

这里写图片描述

如果实现上图红框中的效果,笨办法就是写三个TextView,“¥”,“价格”,“门市价”分别实现,其实用一个TextVIew就可以实现,类似如下代码:

 String text = String.format("¥%1$s  门市价:¥%2$s", 18.6, 22); int z = text.lastIndexOf("门"); SpannableStringBuilder style = new SpannableStringBuilder(text); style.setSpan(new AbsoluteSizeSpan(DisplayUtil.dip2px(mContext,14)), 0, 1, Spannable.SPAN_EXCLUSIVE_INCLUSIVE); //字号 style.setSpan(new ForegroundColorSpan(Color.parseColor("#afafaf")), z, text.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE); //颜色 style.setSpan(new AbsoluteSizeSpan(DisplayUtil.dip2px(mContext,14)), z, text.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE); //字号 tv.setText(style);

同样Html.fromHtml也可以实现。这样不就减少了两个TextView了。

按需载入

ViewStub

在开发中经常会遇到这样的情况,会在程序运行时动态根据条件来决定显示哪个View或某个布局。那么通常做法就是把用到的View都写在布局中,然后在代码中动态的更改它的可见性。但是它的这样仍然会创建View,会影响性能。

这时就可以用到ViewStub了,ViewStub是一个轻量级的View,不占布局位置,占用资源非常小。

例子:比如我们请求网络加载列表,如果网络异常或者加载失败我们可以显示一个提示View,上面可以点击重新加载。当然一直没有错误时,我们就不显示。

<?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" >    ……    <ViewStub        android:layout_gravity="center"        android:id="@+id/hint_view"        android:layout_width="match_parent"        android:inflatedId="@+id/hint_view"        android:layout_height="wrap_content"        android:layout="@layout/hint_view"/></merge>

hint_view.xml就是这个提示View,可以根据情况自己写。

用法:

private View hintView;if (网络异常。。。) {    if (hintView == null) {        ViewStub viewStub = (ViewStub)this.findViewById(R.id.hint_view);        hintView = viewStub.inflate();        TextView textView = (TextView) hintView.findViewById(R.id.tv);        textView.setText("网络异常!");    }    hintView.setVisibility(View.VISIBLE);}else{    if (hintView != null) {        hintView.setVisibility(View.GONE);    }}

用法很简单,记得一旦ViewStub可见或是被inflate了,ViewStub就不存在了,取而代之的是被inflate的Layout。所以它也被称做惰性控件。

其他小技巧

用LinearLayout自带的分割线

还记得上文用TextView同时显示图片和文字中的例子吗?我们可以看到每个条目之间都是有一根分隔线的,那么怎么实现呢?别人我不知道,反正我原来是用一个View设置高度实现的。相信一定有人和我一样。

那么老办法我就不演示了,直接上代码:

<LinearLayout    xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    android:divider="@drawable/divider"    android:showDividers="middle">    <TextView        android:drawableLeft="@drawable/icon_1"        android:drawableRight="@drawable/icon_4"        android:drawablePadding="10dp"        android:paddingLeft="10dp"        android:paddingRight="10dp"        android:textSize="16sp"        android:text="我的卡券"        android:background="@color/white"        android:gravity="center_vertical"        android:layout_width="match_parent"        android:layout_height="50dp" />    <TextView        android:drawableLeft="@drawable/icon_2"        android:drawableRight="@drawable/icon_4"        android:drawablePadding="10dp"        android:paddingLeft="10dp"        android:paddingRight="10dp"        android:textSize="16sp"        android:text="地址管理"        android:background="@color/white"        android:gravity="center_vertical"        android:layout_width="match_parent"        android:layout_height="50dp" />    <TextView        android:drawableLeft="@drawable/icon_3"        android:drawableRight="@drawable/icon_4"        android:drawablePadding="10dp"        android:paddingLeft="10dp"        android:paddingRight="10dp"        android:textSize="16sp"        android:text="检查更新"        android:background="@color/white"        android:gravity="center_vertical"        android:layout_width="match_parent"        android:layout_height="50dp" /></LinearLayout>

效果图:

这里写图片描述

实现的核心部分其实是LinearLayout的这两行。

android:divider="@drawable/divider"android:showDividers="middle"

其中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="#e1e1e1"/></shape>

showDividers 是分隔线的显示位置,beginning、middle、end分别代表显示在开始位置,中间,末尾。

还有dividerPadding属性这里没有用到,意思很明确给divider添加padding。感兴趣可以试试。

Space控件

还是接着上面的例子,如果要给条目中间添加间距,怎么实现呢?当然也很简单,比如添加一个高10dp的View,或者使用android:layout_marginTop="10dp"等方法。但是增加View违背了我们的初衷,并且影响性能。使用过多的margin其实会影响代码的可读性。

这时你就可以使用Space,他是一个轻量级的。我们可以看下源码:

/** * 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));    }}

可以看到在draw方法没有绘制任何东西,那么性能也就几乎没有影响。

实现代码与效果:

<?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"    android:divider="@drawable/divider"    android:showDividers="middle|beginning|end">    <TextView        android:drawableLeft="@drawable/icon_1"        android:drawableRight="@drawable/icon_4"        android:drawablePadding="10dp"        android:paddingLeft="10dp"        android:paddingRight="10dp"        android:textSize="16sp"        android:text="我的卡券"        android:background="@color/white"        android:gravity="center_vertical"        android:layout_width="match_parent"        android:layout_height="50dp" />    <TextView        android:drawableLeft="@drawable/icon_2"        android:drawableRight="@drawable/icon_4"        android:drawablePadding="10dp"        android:paddingLeft="10dp"        android:paddingRight="10dp"        android:textSize="16sp"        android:text="地址管理"        android:background="@color/white"        android:gravity="center_vertical"        android:layout_width="match_parent"        android:layout_height="50dp" />    <Space        android:layout_width="match_parent"        android:layout_height="15dp"/>    <TextView        android:drawableLeft="@drawable/icon_3"        android:drawableRight="@drawable/icon_4"        android:drawablePadding="10dp"        android:paddingLeft="10dp"        android:paddingRight="10dp"        android:textSize="16sp"        android:text="检查更新"        android:background="@color/white"        android:gravity="center_vertical"        android:layout_width="match_parent"        android:layout_height="50dp" /></LinearLayout>

这里写图片描述

防止过度绘制

这个完全可以看鸿洋大神这篇 《Android UI性能优化实战 识别绘制中的性能问题》:http://blog.csdn.net/lmj623565791/article/details/45556391

参考

  • Android布局优化:http://www.lightskystreet.com/2015/01/19/android-layout-optimize

总结

最后想想如果没有用这些技巧,我们要写多少代码,多少View?效果是不是杠杠的!其实上面说了这么多,具体的情景使用还是要看项目的具体情况,在性能面前有些还是要取舍的,但千万不能为了优化而优化。优化也是不断积累的过程,不要指望立竿见影。愿大家都能写出一手漂亮的布局。最后觉得不错的点个赞哈!

引用:布局优化技巧

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 敖东酵母锌60片多少钱 吉林敖东阿胶糕 敖东安神补脑液价格 000623吉林敖东股票 敖东血府逐瘀口服液 敖东鹿胎口服液价格 敖东药业保健品 敖东鹿胎颗粒 敖东维d2乳酸钙片价格 吉林傲东 000623 000623股票 000623股票行情 吉林熬东 jlad 000623股吧 安神补脑液吉林敖东 敖兴 敖包相会 敖包 敖包相恋 敖包再相会 敖包是什么 敖包会 敖包相会dj 敖包相会原唱 敖包相会歌词 敖包相会简谱 敖包是什么意思 敖包相恋原唱 敖包相会二胡简谱 敖包相会原唱伴奏 敖包相恋歌曲播放 敖包相会歌谱 敖包相会 歌词 二胡独奏敖包相会 敖包相会歌词歌词 敖包相会吉他谱 敖包相会是什么意思 敖包相恋歌词 敖包相会葫芦丝简谱