SeekBar使用自定义Drawable作为thumb

  • Post author:
  • Post category:其他




SeekBar使用自定义Drawable作为thumb

工作中遇到一个需求,要在seekBar的thumb上显示文本,并且thumb还有特定的样式,如下图。考虑了一下之后,决定采用自定义Drawable作为thumb drawable。

在这里插入图片描述



一、实现代码

public class LoadingTextDrawable extends Drawable implements DrawBufferIndicatorHelper.Callback {

    private final DrawBufferIndicatorHelper drawHelper;
    private Paint paint;
    private final RectF rectF;
    private Context context;
    private int dp2;

    public LoadingTextDrawable(Context context) {
        this.context = context;
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setTextSize(DisplayUtil.dip2px(context, 12));
        paint.setColor(Color.BLACK);

        rectF = new RectF();

        drawHelper = new DrawBufferIndicatorHelper(this);
        drawHelper.show(false);
    }

    public void loading(boolean loading) {
        drawHelper.show(loading);
    }

    /**
     * drawable边界改变
     *
     * @param bounds
     */
    @Override
    protected void onBoundsChange(Rect bounds) {
        super.onBoundsChange(bounds);
        dp2 = DisplayUtil.dip2px(context, 2);
        int dp50 = DisplayUtil.dip2px(context, 50);
        int dp30 = DisplayUtil.dip2px(context, 12);
        rectF.left = bounds.left + dp50;
        rectF.right = bounds.right - dp50;
        rectF.top = bounds.top + dp30;
        rectF.bottom = bounds.bottom - dp30;

        drawHelper.setSize((int) (Math.abs(rectF.height()) / 2f));

        invalidate();
    }

    /**
     * 绘制
     *
     * @param canvas
     */
    @Override
    public void draw(@NonNull Canvas canvas) {
        Log.d("MyDrawable", "drawable draw...");

        paint.setColor(Color.WHITE);
        float width = Math.abs(rectF.width());
        canvas.drawRoundRect(rectF, width / 4, width / 4, paint);


        //绘制时间文字
        String string = "00:10/06:22";
        paint.setColor(Color.BLACK);
        Paint.FontMetrics fontMetrics = paint.getFontMetrics();
        float bottomLineY = rectF.centerY() - (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.top;
        float x = (rectF.width() - paint.measureText(string)) / 2 + rectF.left + drawHelper.getSize();
        canvas.drawText(string, x, bottomLineY, paint);

        //绘制loading
        canvas.save();
        //loading怎么计算不能居中,加2dp视觉上居中
        canvas.translate(rectF.right + drawHelper.getSize(), rectF.centerY() + rectF.height() / 2 + drawHelper.getSize() / 2 + dp2);
        drawHelper.draw(canvas);
        canvas.restore();
    }

    /**
     * 设置画笔透明度
     *
     * @param alpha
     */
    @Override
    public void setAlpha(int alpha) {
        paint.setAlpha(alpha);
        invalidateSelf();
    }

    /**
     * 设置画笔颜色过滤器
     *
     * @param colorFilter
     */
    @Override
    public void setColorFilter(@Nullable ColorFilter colorFilter) {
        paint.setColorFilter(colorFilter);
        invalidateSelf();
    }

    /**
     * 设置drawable透明类型
     */
    /**
     * @return
     */
    @Override
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }

    @Override
    public void invalidate() {
        if (getCallback() == null) {
            Log.d("MyDrawable", "invalidateSelf null");
        } else {
            Log.d("MyDrawable", "invalidateSelf");
        }
        //刷新drawable
        invalidateSelf();
    }
}



二、细节,以及问题



1、onBoundsChange

拖动seekbar的时候,seekBar会调用thumb drawable的setBounds方法。onBoundsChange回调的时候,就是自定义drawable的绘制区域发生改变,如果不在onBoundsChange回调的时候调整绘制的位置,会导致seekBar拖动的时候thumb在原地。



2、drawable刷新

drawable是依附于view显示的,它定义的是绘制的方式,而绘制一般是由view来做的。

view在设置drawable的时候一般会同时设置一个callback,当调用drawable的invalidateSelf时,会通过callback回调view的invalidateDrawable。

但是自定义drawable用在seekbar上时,调用invalidateSelf没有刷新drawable。

可以在重载invalidateDrawable,在调用此方法之前执行

postInvalidateOnAnimation()



3、SeekBar两边有空隙

可以设置seekbar布局

android:paddingStart="0dp"



android:paddingEnd="0dp"



4、SeekBar按住的时候有一小块圆形阴影


android:thumb="@null"



版权声明:本文为SywCache原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。