1.问题

我想很多小伙伴都和我一样应该很喜欢TextView中drawableLeft、drawableTop、drawableRight、drawableBottom这几个属性,因为我们可以直接用它来画出来一个图文排列的标签或者按钮,这样就对于用两个控件组成的相对复杂的布局来说容易的多,这在移动UI开发中很常用,但是这样经常会有个问题困扰着我,因为有时候我们想把图片和文字对应居中,这样就会出现关于图片和文字之间的间距不好控制的问题,有时候我们设置drawablePadding这个属性之后发现也并没有达到我们想要的效果。

image

2.原因

大概看了下源码实现,得出的结论就是android:drawablePadding这个属性在 我们给view设置的宽度或者高度足够小(以至于将两者挤压在一起)的时候,这个属性才会起作用,也即在图片和文字之间会有间距产生。如果你的view所设置的宽度或者高度大于drawableLeft/drawableRight或者drawableTop/drawableBottom所产生的间距,那么这个属性当然也就不会起作用。

3.实践

一种最简单方法是我们可以直接去解决,就是通过设置view的内填充,我们从上面原因中可以知道,drawablePadding不起作用是因为view的宽度过宽,导致view内文本和图片间距过大,那我们可以通过设置paddingLeft、paddingRight、paddingTop、paddingBottom来缩写这个间距,如下代码:

1
2
3
4
5
6
7
8
9
10
11
<Button
android:layout_width="wrap_content"
android:layout_height="40dp"
android:text="@string/xian_txt"
android:drawableRight="@mipmap/ic_triangle_down"
android:background="@android:color/transparent"
android:drawablePadding="6dp"
android:gravity="center"
android:paddingRight="24dp"
android:paddingLeft="24dp"
/>

对应的效果也可以实现

image

另外,我们也可以通过自定义View来精确的计算:

  1. 我们先自定义属性iconPadding来设置间距,并提供方法给外部调用
  2. 重写setCompoundDrawablesWithIntrinsicBounds()方法来获取我们设置的drawable宽度。
  3. 最后重写onLayout方法,因为这里面改变了一些位置属性,需要通过重新布局才能起作用。

相关代码:

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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
public class IconButton extends Button {
private int drawableWidth;
private int iconPadding;
private DrawablePosition position;

Rect bounds;

private enum DrawablePosition{
NONE,
LEFT_AND_RIGHT,
LEFT,
RIGHT
}

public IconButton(Context context) {
this(context,null,0);
}

public IconButton(Context context, AttributeSet attrs) {
this(context, attrs,0);
}


public IconButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
bounds = new Rect();
applyAttributes(attrs);
}

protected void applyAttributes(AttributeSet attrs) {

if (null == bounds) {
bounds = new Rect();
}

TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.IconButton);
int paddingId = typedArray.getDimensionPixelSize(R.styleable.IconButton_iconPadding, 0);
setIconPadding(paddingId);
typedArray.recycle();
}

public void setIconPadding(int padding) {
iconPadding = padding;
requestLayout();
}

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);

Paint textPaint = getPaint();
String text = getText().toString();
textPaint.getTextBounds(text, 0, text.length(), bounds);

int textWidth = bounds.width();
int factor = (position == DrawablePosition.LEFT_AND_RIGHT) ? 2 : 1;
int contentWidth = drawableWidth + iconPadding * factor + textWidth;
int horizontalPadding = (int) ((getWidth() / 2.0) - (contentWidth / 2.0));

setCompoundDrawablePadding(-horizontalPadding + iconPadding);

switch (position) {
case LEFT:
setPadding(horizontalPadding, getPaddingTop(), 0, getPaddingBottom());
break;

case RIGHT:
setPadding(0, getPaddingTop(), horizontalPadding, getPaddingBottom());
break;

case LEFT_AND_RIGHT:
setPadding(horizontalPadding, getPaddingTop(), horizontalPadding, getPaddingBottom());
break;

default:
setPadding(0, getPaddingTop(), 0, getPaddingBottom());
}
}


@Override
public void setCompoundDrawablesWithIntrinsicBounds(Drawable left, Drawable top, Drawable right, Drawable bottom) {
super.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);

if (left != null && right != null) {
drawableWidth = left.getIntrinsicWidth() + right.getIntrinsicWidth();
position = DrawablePosition.LEFT_AND_RIGHT;
} else if (left != null) {
drawableWidth = left.getIntrinsicWidth();
position = DrawablePosition.LEFT;
} else if (right != null) {
drawableWidth = right.getIntrinsicWidth();
position = DrawablePosition.RIGHT;
} else {
position = DrawablePosition.NONE;
}

requestLayout();
}
}

这样同样可以实现我们想要的效果,并且可以自由设置间距

1
2
3
4
5
6
7
8
9
10
<com.yuxingxin.iconview.IconButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:gravity="center"
android:drawableRight="@mipmap/ic_triangle_down"
app:iconPadding="6dp"
android:background="@color/colorPrimary"
android:textColor="@android:color/white"
/>

附上demo地址

分享到:
移动开发者/技术爱好者/喜欢开源与分享,你也可以关注微信公众号MobDevGroup,移动开发在线分享:MobDevGroup