详解安卓Gravity的进制封装
前言
安卓中的部分控件中有一个setGravity
的方法,可以使用它设置View内重力的方向。
以LinearLayout为例,它的使用是这样的
LinearLayout linearlayout=findViewById(R.id.xxx);
linearlayout.setGravity(Gravity.Top|Gravity.Center|Gravity.Start);//添加重力
这样的代码,通过符号"|"设置多种重力仅需要一次set,阅读起来十分简洁。
那它是怎么做到的呢?
准备
代码分析需要一定的进制操作符基础,我们先简单复习一下java关于进制的运算符
声明:以下均是对2进制的操作
定义A=0011_1100
定义B=0000_1101
操作符 | 描述 | 例子 |
---|---|---|
& | 如果都是1,则为1,否则0 | A&B=0000_1100 |
| | 如果都是0,则为0,否则1 | A|B=0011_1101 |
^ | 如果值相同,则为0,否则1 | A^B=0011_0001 |
~ | 如果是0,则变1.如果是1,则变0 | ~A=1100_0011 |
<< | 向左移动,用0补齐 | A<<2=1111_0000 |
>> | 向右移动 | A>>2=1111 |
>>> | 向右移动,用0补齐 | A>>>2=0000_1111 |
代码分析
复习好了进制运算符,我们来看一下代码
按下Ctrl+左键
,单击进入setGravity
方法可以看到如下代码
public void setGravity(int gravity) {
if (mGravity != gravity) {
if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
gravity |= Gravity.START;
}
if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
gravity |= Gravity.TOP;
}
mGravity = gravity;
//去除了部分无关代码
}
}
可以确定mGravity
是LinearLayout的重力储存变量
我们再来分析一下这两个if是干什么的。按下Ctrl+左键
,跟进Gravity
类
内部定义的常量如下
//去除了部分无关代码
public static final int AXIS_SPECIFIED = 0x0001;//1
public static final int AXIS_PULL_BEFORE = 0x0002;//10
public static final int AXIS_PULL_AFTER = 0x0004;//100
public static final int AXIS_X_SHIFT = 0;
public static final int AXIS_Y_SHIFT = 4;
public static final int TOP = (AXIS_PULL_BEFORE|AXIS_SPECIFIED)<<AXIS_Y_SHIFT;//110000
public static final int BOTTOM = (AXIS_PULL_AFTER|AXIS_SPECIFIED)<<AXIS_Y_SHIFT;//1010000
public static final int LEFT = (AXIS_PULL_BEFORE|AXIS_SPECIFIED)<<AXIS_X_SHIFT;//11
public static final int RIGHT = (AXIS_PULL_AFTER|AXIS_SPECIFIED)<<AXIS_X_SHIFT;//101
public static final int RELATIVE_LAYOUT_DIRECTION = 0x00800000;//100000000000000000000000
public static final int START = RELATIVE_LAYOUT_DIRECTION | LEFT;
//100000000000000000000011
public static final int END = RELATIVE_LAYOUT_DIRECTION | RIGHT;
//100000000000000000000101
public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = START | END;
//100000000000000000000111
//为了方便阅读我将这些常量的二进制写在了注释
观察代码
TOP
和BOTTOM
都是左偏移4位的值,而LEFT
和RIGHT
都是左偏移0位的值
再根据变量名称,可以确定 将Gravity从后向前看,前四位控制的是与X轴有关的重力,四位以后控制的是与Y轴有关的重力
而START
和End
是LEFT
和RIGHT
补位后的值
RELATIVE_HORIZONTAL_GRAVITY_MASK
是START|END
回过来再看刚才的if
if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
gravity |= Gravity.START;
}
很明显,这个if是判断传入的gravity
是否具有LEFT或者RIGHT的重力方向,也就是X轴的重力方向
如果不具备X轴的重力,则添加START
第2个if则是判断是否具备Y轴的重力
至此,setGravity
就分析完成了
那怎么判断传入的gravity是否具有某一方向的重力呢
if(gravity&BOTTOM^BOTTOM==0){
//有
}
总结
对于多类型参数传参操作,可以使用进制封装进行大幅度简化
我们只需要定义每一位的作用,并遵循一个规则
1为有
0为没有
|添加
^如果没有就添加,如果有就去除
&判断是否有