在应用开发中,为了友好的用户体验,我们常常需要在文字旁边添加 ICON,因为用户对图形的感知往往要强于文字,比如这样子:

分类导航

大多数新手看一眼觉得很简单,使用 ImageViewTextView 组合即可。

的确,这是一种很简单的方法,但如上图中使用 GridLayout 来展示多个子项,明明 ICON 和文字属于同一项,组合写法会导致代码成倍增加,再加上需要用一个父容器(如 LinearLayout)来包裹这两个子项,布局文件就如老太太的裹脚布——又长又臭。

当然,你也可以把这个组合抽取出来,做成 Adapter 通用,尽管布局清晰了,但逻辑代码也增加不少。

实际上,Android 本身就为 TextView 提供了此功能,我们只需一行代码就可以使用:

<TextView
    ...
    android:drawableTop="@drawable/ic_drawable" /> 

该属性可以为 TextView 在某一方向上添加对应的 Drawable,其他方向只需修改属性中的方向名称即可。

AppCompat 提供了一些 Compat 属性,所以你也可以这样写:

<TextView
    ...
    app:drawableTopCompat="@drawable/ic_drawable" /> 

如果你想调整 Drawable 和文字的间隔,可以使用这个属性:

<TextView
    ...
    android:drawablePadding="16dp"
    app:drawableTopCompat="@drawable/ic_drawable" /> 

Drawable 尺寸过大时,你可能会注意到 Drawable 和文字并不是居中的,这时你要牢记,这个 Drawable 也是 TextView 的一部分:

TextView 范围

对于 ViewViewGroup 内部元素的对齐方式,我们通常可以使用:

<TextView
    ...
    android:gravity="center"
    app:drawableTopCompat="@drawable/ic_drawable" /> 

假如你需要在逻辑代码中动态修改该 Drawable,同样提供支持:

textView.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(R.drawable.ic_drawable), null, null, null); 

setCompoundDrawablesWithIntrinsicBounds() 方法接收四个参数,分别是四个方向上的 Drawable 资源,在对应方向传入所需的 Drawable 即可。

该方法同时也支持以资源 ID 的方式传入 Drawable,所以也可以这样写:

textView.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_drawable, 0, 0, 0); 

当你觉得这个功能挺好用时,假如美工让你调整一下 Drawable 的大小,你可能一下子就懵了,似乎找不到这个属性,还不如 ImageViewTextView 组合来得方便呀。

的确,在布局文件中没有调整 Drawable 尺寸的属性,但你要记得,这是一个 Drawable,既然是 Drawable,我们就可以通过逻辑代码控制它的尺寸:

Drawable drawable = getResources().getDrawable(R.drawable.ic_account);
drawable.setBounds(0, 0, 180, 180);                     // 设置图片的大小
textView.setCompoundDrawables(drawable, null, null, null);   // 设置图片的位置 

DrawablesetBounds() 方法接收四个参数,四个坐标形成一个矩形,Drawable 将在被绘制在这个矩形区域内。

接着调用的 setCompoundDrawables() 和上面提到的 setCompoundDrawablesWithIntrinsicBounds() 类似,将 Drawable 传入到对应位置即可。

另外我们知道,EditText 实际上是继承于 TextView 的,那么 EditText 也会有相同的属性,所以我们可以轻而易举的实现类似的功能:

EditText With ICON

属性和方法基本和 TextView 一致,不再重复贴代码。