1、概述
话说,随着Android SDK版本的升级,很多控件增加了新的属性方便我们的使用,比如LinearLayout中多了:divider、showDividers等,用于为其内部元素添加分隔;但是呢,这样的属性在较低版本的SDK中不能被支持,那么,我们在开发过程中,可能会出现这样的需求:将这个新的特性想办法做到尽可能的向下兼容。有人说,可以自己写个新的控件去实现,这样的确可以,但是会不会太霸气了点。难道就没有接地气一点的方式么?嗯,本文就是这样的一个目的,以一种较为接地气的方式,实现新的属性的向下兼容。
这样的情况在Android中肯定会很多,希望可以以此进行抛砖引玉,大家遇到类似的情况,提供一定的思路。这才是这篇博客的真正目的!
2、divider相关用法
为了保证简介性,这里就不讨论divider有多么多么好用神马的,因为不是我们的重点。当然了这里提供一篇divider的参考:grid-spacing-on-android (基本就是引出divider的用处,有兴趣的看下,本文的demo样子也将参考本链接)。
大家先看一个效果图:
如果要实现,这样的效果图,对于这3个Button大家会怎么做(主要看button):
简单嘛:一个水平的线性布局,内部三个Button的weight都为1,然后第二个Button设置leftMargin,rightMargin就可以了。
嗯,没问题,假设现在我有一个需求:经过某个操作Button3隐藏,然后让Button1和Button2按如下布局:
这样的感觉是不是不错,虽然少了一个,完全不影响美观;但是,如果按照上述的答案
“一个水平的线性布局,内部三个Button的weight都为1,然后第二个Button设置leftMargin,rightMargin就可以了” Button2的右边会多出一个rightMargin 。
所以,这样的制作方式很明显不是最优秀的,最优秀的方案是,使用Linearlayout的divider、showDividers属性:
布局代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="20dp" android:layout_margin="10dp" android:background="#22444444" android:orientation="vertical" > <TextView android:layout_width="match_parent" android:layout_height="128dp" android:background="@android:color/darker_gray" android:gravity="center" android:text="application_logo" /> <LinearLayout android:id="@+id/buttons_container" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:divider="@drawable/divider" android:orientation="horizontal" android:showDividers="middle" > <Button android:id="@+id/btn_first" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:background="#ff0000" android:text="button_1" /> <Button android:id="@+id/btn_second" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:background="#00ff00" android:text="button_2" /> <Button android:id="@+id/btn_third" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:background="#0000ff" android:text="button_3" /> </LinearLayout> </LinearLayout> |
其实核心就是放置Button的LinearLayout设置了 android:divider=”@drawable/divider”和 android:showDividers=”middle” ;
当然了,有人会说,我就是任性,我就用margin来实现,消失的时候,我显示去控制button的rightMargin为0也可以。嗯,是的,你不嫌麻烦的确没问题。那么现在问题又来了,我现在要求每个Button间的间隔是蓝色的,你怎么办?注意:我们这里的divider的值设置的是一个drawable噢~~没辙了吧。
本例的drawable(divider.xml):
1 2 3 4 5 6 |
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <size android:width="15dp" /> <solid android:color="@android:color/transparent" /> </shape> |
下面简单介绍下divider、showDividers、dividerPadding:
divider可以设置一个drawable作为元素间的间隔;
showDividers:可取值为:middle(子元素间)、beginning(第一个元素左边)、end(最后一个元素右边)、none;【关于垂直方向的类似】
dividerPadding:设置绘制间隔元素的上下padding。
很简单,大家自己动手做下实验就知道了。
好了,到此,我们简单介绍了divider等的好处以及使用方式。但是这么优雅的来实现元素间的间隔只有在3.0以上才被支持,那么3.0以下怎么办呢?
别怕,下面开始本文的重点,让divider兼容至3.0一下。
3、自定义LinearLayout
看了标题,大家认为又是自定义LinearLayout么~~
嗯,继承LinearLayout是肯定的,我们没有办法改变它的源码,但是可以通过继承去改变一些特性。
注意下:现在的目的是兼容至3.0以下:
首先看一个3.0以下的效果图,不然你说我骗你:
上面的布局文件在3.0以下显示就是这么个样子,完全无视间隔。
首先考虑一个问题,对于divider、showDividers 3.0以下的LinearLayout肯定无视呀,咋办呢?
我们实现个LinearLayout的子类,让它认识divider和showDividers~~~重视一下这里,这里就是我们向前迈进的一大步,以后遇到类似问题,都这么干。
1、识别高版本的属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
public class IcsLinearLayout extends LinearLayout { private static final int[] LL = new int[] { // android.R.attr.divider,// android.R.attr.showDividers,// android.R.attr.dividerPadding // }; private static final int LL_DIVIDER = 0; private static final int LL_SHOW_DIVIDER = 1; private static final int LL_DIVIDER_PADDING = 2; /** * android:dividers */ private Drawable mDivider; /** * 对应:android:showDividers */ private int mShowDividers; /** * 对应:android:dividerPadding */ private int mDividerPadding; private int mDividerWidth; private int mDividerHeight; public IcsLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = context.obtainStyledAttributes(attrs, LL); setDividerDrawable(a.getDrawable(IcsLinearLayout.LL_DIVIDER)); mDividerPadding = a.getDimensionPixelSize(LL_DIVIDER_PADDING, 0); mShowDividers = a.getInteger(LL_SHOW_DIVIDER, SHOW_DIVIDER_NONE); a.recycle(); } /** * 设置分隔元素,初始化宽高等 */ public void setDividerDrawable(Drawable divider) { if (divider == mDivider) { return; } mDivider = divider; if (divider != null) { mDividerWidth = divider.getIntrinsicWidth(); mDividerHeight = divider.getIntrinsicHeight(); } else { mDividerWidth = 0; mDividerHeight = 0; } setWillNotDraw(divider == null); requestLayout(); } |
这里贴出了成员变量和我们的构造方法,成员变量中包含了3个属性对应的接收变量;然后我们在构造里面对这三个属性进行了获取并赋值给相应的属性;
这里大家肯定会困惑,我上面定义了一个整型数组,然后几个变量为数组下标,最后利用这个数组和下标在构造里面获取了值。是不是要问,你为什么这么写,你咋知道的?
嗯,这样,大家随便下载我之前包含自定义属性的文章,或者你自己写的:
这里我拿了Android BitmapShader 实战 实现圆形、圆角图片这个例子中的源代码,大家就不用下载了,看看我下面就明白了,我在这里例子中自定义了两个属性:type和border_radius,看看我们的R.java里面生成了什么样的代码:
1 2 3 4 5 6 7 8 |
public static final int border_radius=0x7f010001; public static final int type=0x7f010000; public static final int[] RoundImageViewByShader = { 0x7f010000, 0x7f010001 }; |