Android技巧 - drawablePadding的问题

1.问题

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

《Android技巧 - drawablePadding的问题》

2.原因

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

3.实践

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

<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"
 />

对应的效果也可以实现

《Android技巧 - drawablePadding的问题》

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

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

相关代码:

public class IconButton extends Button {
    private int drawableWidth;
    private int iconPadding;
    private DrawablePosition position;
    Rect bounds;

    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();
    }
    private enum DrawablePosition {NONE,
        LEFT_AND_RIGHT,
        LEFT,
        RIGHT;
    }
}

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

<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地址

自己是从事了七年开发的Android工程师,不少人私下问我,2019年Android进阶该怎么学,方法有没有?

没错,年初我花了一个多月的时间整理出来的学习资料,希望能帮助那些想进阶提升Android开发,却又不知道怎么进阶学习的朋友。【包括高级UI、性能优化、架构师课程、NDK、Kotlin、混合式开发(ReactNative+Weex)、Flutter等架构技术资料】,希望能帮助到您面试前的复习且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。

资料获取方式:加入Android架构交流QQ群聊:513088520 ,进群即领取资料!!!

点击链接加入群聊【Android移动架构总群】:加入群聊

《Android技巧 - drawablePadding的问题》 资料大全

    原文作者:Android架构
    原文地址: https://www.jianshu.com/p/77ad37fcb51f
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞