7.1.3 Android控件属性

每个Android控件都有一定的属性,用于表示控件对象的基本特征。这些属性都定义在View类中,因此,从View类中派生而来的每个子控件都具备一些属性。

❑标识

每个控件对象都可以由一个整型数作为其标识,开发者可以通过View.getId函数获取控件对象的标识,并能够利用View.setId函数为控件对象设定标识[1]

使用View.findViewById函数,可以从该控件的子控件中(含该控件本身)寻找到第一个匹配给定标识的控件对象,其寻找方式采用了树的深度遍历。

控件对象的标识并不需要在全局范围内保持唯一性,而仅需要在给定控件的子控件范围内保持唯一性,从而通过View.findViewById函数能够在父控件范围内准确定位到所需的控件对象。

并且,对于控件对象而言,标识并不是必需的属性,一些不需要动态变更内容的控件对象可以不需要有标识信息。

❑尺寸

Android中每个控件对象都会占据一定的矩形区域,该控件对象会处理与矩形区域相关的交互事件,并在此区域内绘制该控件对象的交互界面。

既然是矩形区域,自然是通过长、宽信息进行描述,在Android中,对控件对象矩形区域的长宽描述有两类方式。

第一类是“精确描述”,开发者可以为控件对象设定一个明确而固定的大小,比如13像素(px)、12毫米(mm)等。

除此之外,还有一种尺寸描述方式,称为“模糊描述”。基于模糊描述的控件对象,需要依赖父控件或者控件中的内容,来确定自己的真实大小。如图7-2a所示,开发者可以将控件对象的长或宽设置为android.view.ViewGroup.LayoutParams.FILL_PARENT [2],这就意味着该子控件对象将尽量充满整个父控件。而如果控件对象的长宽信息为android.view.ViewGroup.LayoutParams.WRAP_CONTENT,则说明该子控件矩形区域的大小以包裹控件中的内容为标准进行设定。

整体来看,控件的尺寸由父控件及其子控件共同影响、共同决定。在设定时需要综合考量,避免出现一些矛盾状况(比如父控件是WRAP_CONTENT,自身是FILL_PARENT)。

控件对象的尺寸参数可以通过View.setLayoutParams函数进行设定,该函数接受一个android.view.ViewGroup.LayoutParams对象。设定的子控件矩形区域,会与其父控件所占据的矩形区域求交,只有其交集部分才会作为该控件的有效交互区域,其余超出其父控件矩形范围的区域,都无法接收到相关的交互事件。

除了矩形区域相关的信息,很多控件中还有Margin和Padding等尺寸相关的信息。如图7-2b所示,Margin用于设定容器控件对象中子控件与其矩形区域的距离,它是容器控件的专属属性,通过MarginLayoutParams来设定;而Padding则用于指明控件对象中内容与该控件矩形区域边缘的距离,开发者可以通过View.setPading函数为控件对象设置上下左右的Padding信息。

7.1.3 Android控件属性 - 图1

图 7-2 控件的尺寸设置

❑位置

除了尺寸信息,每个控件对象还需要有对应的位置信息。如图7-3所示,与大部分平台类似,Android的控件位置坐标系的原点在左上角,x轴坐标自左向右,y轴坐标自上而下。Android可以通过View.getTop和View.getLeft函数获得该控件对象的左上角坐标,该坐标所在的坐标系,其原点是该控件所在控件树区域的左上角(也就是说,Android的坐标系是基于控件树来划分的)。

控件树不一定占据整个屏幕区域,因此,通过View.getTop等相关函数获得的位置信息都是相对位置信息,需要放在控件区域中考量才有意义。

除了相对位置,开发者还可以通过View.getLocationOnScreen函数,获得控件相对于屏幕的绝对位置信息。绝对位置的坐标系原点位于屏幕的左上角,与所在的控件树区域无关。在实际开发中,需要理解不同坐标系间的关系,才能正确地读取和设置控件对象的位置信息。

7.1.3 Android控件属性 - 图2

图 7-3 控件的位置设置

❑可见性

在交互界面的开发中,时常需要隐藏部分控件来控制用户的交互,这就需要控件可见性的支持。在Android中,开发者可以通过View.setVisibility函数来改变控件的可见性。控件的可见性共有三种,分别是可见状态View.VISIBLE、不可见状态View.INVISIBLE和消失状态View.GONE。

顾名思义,当控件处于可见状态时,该控件对象不仅会在界面中占据一定的矩形区域,还可以正常地呈现内容、响应用户操作;而当控件处于不可见状态时,虽然它依然在界面上占据固有的矩形区域,但它并不会在该区域内绘制内容,也不再响应用户操作;更进一步,如果控件处于消失状态,它不仅不会进行绘制内容和响应用户的操作,而且也不会占据界面的任何区域,仿佛“消失”了一般。

一个示例如图7-4所示,在一个垂向的线性容器控件中(即Orientation属性为LinearLayout.VERTICAL的LinearLayout控件),当控件B处于不可见状态时,控件C的位置不会有任何变化;而当控件B处于消失状态时,它就不再占据任何界面区域,控件C位置自然就会上移,占据控件B原有的区域。

7.1.3 Android控件属性 - 图3

图 7-4 控件的可见性示例

与传统的控件可见性相比,Android的控件增加了对“消失状态”的支持,在很多场景下,它大大降低了界面构造的难度(考虑一下上述例子,如果没有消失状态,控制控件将是多么痛苦的一件事情)。但值得注意的是,在关系型容器中(比如RelativeLayout控件),如果起定位作用的控件对象消失,可能会导致其他依赖它进行定位的控件位置错乱(这种现象在低版本的SDK中尤为严重)。因此,在关系型容器中,开发者需要额外注意控件可见性的设置,应尽量在多个SDK版本中进行测试。

❑焦点

不论用户是通过键盘还是触屏与应用进行交互,焦点信息都是非常重要的控件属性。比如当用户通过键盘进行输入时,系统就需要明确当前界面中的焦点位于哪个控件之上,并将按键消息传递给焦点控件。

Android的控件焦点切换,采取了动态计算的策略,当用户通过方向键切换焦点时,Android会计算在当前方向上与当前控件最接近的控件,并将焦点切换至此控件上。这种动态计算焦点的模式具有很强的灵活性,能够适配任意复杂多变的界面,同时也可以减轻开发者的工作。

但动态计算焦点切换不够精确,在一些界面中,其切换的策略可能会与开发者设计的最优路径有所不同。为了解决这个问题,Android提供了View.setNextFocusDownId等焦点关系设置函数,开发者可以为特定控件精确设定其在上、下、左、右各方向上切换焦点的目标控件,一旦相关焦点控件被设定,切换时就会依照设定的路径进行切换,而不再进行动态计算。值得注意的是,这种焦点切换的关系是单向的,也就是说即便A控件向上的焦点控件为B,也并不代表B控件向下的焦点控件一定为A。

在各个交互界面的开发中,开发者都需要测试默认的焦点切换逻辑是否能够满足其需求。如果默认模式不正确,开发者就需要妥善地设置控件的焦点关系,以保证用户通过键盘或轨迹球等设备进行交互时,也能够享有完美的体验。

[1]大部分时候,控件的标识都是通过资源文件进行设定,而不是直接在代码中给定,第8章将会介绍相关内容。

[2]在高版本(2.2以上)的SDK中,可以使用名称更符合实际表现的MATCH_PARENT来替代,该参数也依然保留。