/ android  自定义view  seekbar  自定义seekbar 

自定义SeekBar样式,自定义滑块


系统自带的SeekBar真是太难看了,不能容忍! 只能自己做了,先来张效果图

716D02DC-1F50-4ABB-90C3-8AE079A47A60.png


1、带数字的SeekBar,数字随着滑块移动

2、滑块在进度条下面


下面是实现方法:

public class MSeekBar extends View {
    ~~~~~
}


继承View,重写onMeasure方法,主要是计算这个View的高度,文本高度+竖线高度+进度条高度+间隔高度

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    float height = textHeight + lineHeight + seekHeight + seekBitmap.getHeight() + 5 * interval;
    super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec((int) height, heightMeasureSpec));

    init = true;
}


然后就是重新onDraw方法进行分别绘制

@Override
protected void onDraw(Canvas canvas) {
    if (!init) {
        return;
    }

    String text = "+" + selectNum;
    float textWidth = mTextPaint.measureText(text);
    float textX = mPositionX - textWidth / 2;

    if (textX < seekOffsetX) {
        textX = seekOffsetX;
    } else if (textX > getWidth() - seekOffsetX - textWidth) {
        textX = getWidth() - seekOffsetX - textWidth;
    }

    //绘制文本
    mTextPaint.setColor(textColor);
    canvas.drawText(text, textX, textHeight, mTextPaint);

    //绘制间隔线
    mTextPaint.setColor(seekColor);
    canvas.drawRect(mPositionX, textHeight + interval, mPositionX + lineWidth, textHeight + lineHeight + interval, mTextPaint);

    //绘制背景进度条
    mTextPaint.setColor(bgColor);
    canvas.drawRoundRect(seekOffsetX, textHeight + lineHeight + interval * 2, getWidth() - seekOffsetX, textHeight + lineHeight + seekHeight + 2 * interval, radius, radius, mTextPaint);

    //----start-----绘制进度条
    int sc = canvas.saveLayer(seekOffsetX, textHeight + lineHeight + interval * 2, getWidth() - seekOffsetX, textHeight + lineHeight + seekHeight + 2 * interval, null, Canvas.ALL_SAVE_FLAG);

    //绘制进度条
    mTextPaint.setColor(seekColor);
    canvas.drawRoundRect(seekOffsetX, textHeight + lineHeight + interval * 2, getWidth() - seekOffsetX, textHeight + lineHeight + seekHeight + 2 * interval, radius, radius, mTextPaint);

    //裁剪进度条
    mTextPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
    canvas.drawRect(mPositionX, textHeight + lineHeight + interval * 2, getWidth() - seekOffsetX, textHeight + lineHeight + seekHeight + 2 * interval, mTextPaint);
    canvas.restoreToCount(sc);
    mTextPaint.setXfermode(null);
    //----end-----绘制进度条

    //绘制游标
    canvas.drawBitmap(seekBitmap, mPositionX - seekOffsetX, bitmapTop, mTextPaint);
}

上面有备注。


重新onTouch方法,进行事件判断:

private float startX, startY;
private float diffX;

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            startX = event.getX();
            startY = event.getY();
            diffX = startX - mPositionX;
            return checkEvent(startX, startY);
        case MotionEvent.ACTION_MOVE:
            float tempX = event.getX() - diffX;
            if (tempX >= seekOffsetX && tempX <= getWidth() - seekOffsetX) {
                mPositionX = tempX;
            } else {
                if (tempX < seekOffsetX) {
                    mPositionX = seekOffsetX;
                } else {
                    mPositionX = getWidth() - seekOffsetX;
                }
            }

            progress = (mPositionX - seekOffsetX) * 1.0 / (getWidth() - 2 * seekOffsetX);
            selectNum = (int) (max * progress);

            if (onSeekBarChangeListener != null) {
                onSeekBarChangeListener.onProgressChanged(progress, selectNum);
            }

            invalidate();
            break;
    }
    return super.onTouchEvent(event);
}


判断手指是否在滑块范围内:

private boolean checkEvent(float x, float y) {
    return (x >= mPositionX - seekOffsetX && x <= mPositionX + seekOffsetX) &&
            (y >= bitmapTop && y <= bitmapTop + seekBitmap.getHeight());
}


好了,大概思路就是这样。


送上完整的代码如下:

package com.wenwen.nianfo.custom.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.wenwen.nianfo.R;
import com.wenwen.nianfo.utils.CommUtils;
import com.wenwen.nianfo.utils.PicUtils;

/**
 * Created by Resmic on 2018/8/13.
 * Email:xiangyx@wenwen-tech.com
 * <p>
 * <p>
 * describe:自定义SeekBar
 */
public class MSeekBar extends View {
    private Bitmap seekBitmap;
    private Paint mTextPaint;
    private int selectNum = 0;
    private int lineHeight = 7;
    private int lineWidth = 1;
    private int seekHeight = 10;
    private int max = 100;
    private double progress = 0;
    private int textHeight;
    private int seekOffsetX;
    private float interval = 1.5f;
    private float mPositionX;
    private float bitmapTop;
    private int textColor;
    private int bgColor;
    private int seekColor;
    private float radius;
    private boolean init = false;

    public MSeekBar(Context context) {
        super(context);
        initView();
    }

    public MSeekBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    private void initView() {
        seekBitmap = PicUtils.zoomBitmap(PicUtils.res2Bitmap(getContext(), R.mipmap.slider),
                CommUtils.dip2px(34),
                CommUtils.dip2px(48));

        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        textColor = getResources().getColor(R.color.color_3);
        bgColor = Color.parseColor("#EDEFF4");
        seekColor = getResources().getColor(R.color.color_2);

        mTextPaint.setTextSize(CommUtils.dip2px(12));
        lineHeight = CommUtils.dip2px(lineHeight);
        seekHeight = CommUtils.dip2px(seekHeight);
        lineWidth = CommUtils.dip2px(lineWidth);
        interval = CommUtils.dip2px(interval);

        radius = seekHeight / 2;

        Rect bounds = new Rect();
        mTextPaint.getTextBounds("0", 0, 1, bounds);
        textHeight = bounds.bottom - bounds.top;

        seekOffsetX = seekBitmap.getWidth() / 2;

        mPositionX = seekOffsetX;
        bitmapTop = textHeight + lineHeight + seekHeight + 5 * interval;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        float height = textHeight + lineHeight + seekHeight + seekBitmap.getHeight() + 5 * interval;
        super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec((int) height, heightMeasureSpec));

        init = true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (!init) {
            return;
        }

        String text = "+" + selectNum;
        float textWidth = mTextPaint.measureText(text);
        float textX = mPositionX - textWidth / 2;

        if (textX < seekOffsetX) {
            textX = seekOffsetX;
        } else if (textX > getWidth() - seekOffsetX - textWidth) {
            textX = getWidth() - seekOffsetX - textWidth;
        }

        //绘制文本
        mTextPaint.setColor(textColor);
        canvas.drawText(text, textX, textHeight, mTextPaint);

        //绘制间隔线
        mTextPaint.setColor(seekColor);
        canvas.drawRect(mPositionX, textHeight + interval, mPositionX + lineWidth, textHeight + lineHeight + interval, mTextPaint);

        //绘制背景进度条
        mTextPaint.setColor(bgColor);
        canvas.drawRoundRect(seekOffsetX, textHeight + lineHeight + interval * 2, getWidth() - seekOffsetX, textHeight + lineHeight + seekHeight + 2 * interval, radius, radius, mTextPaint);

        //----start-----绘制进度条
        int sc = canvas.saveLayer(seekOffsetX, textHeight + lineHeight + interval * 2, getWidth() - seekOffsetX, textHeight + lineHeight + seekHeight + 2 * interval, null, Canvas.ALL_SAVE_FLAG);

        //绘制进度条
        mTextPaint.setColor(seekColor);
        canvas.drawRoundRect(seekOffsetX, textHeight + lineHeight + interval * 2, getWidth() - seekOffsetX, textHeight + lineHeight + seekHeight + 2 * interval, radius, radius, mTextPaint);

        //裁剪进度条
        mTextPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        canvas.drawRect(mPositionX, textHeight + lineHeight + interval * 2, getWidth() - seekOffsetX, textHeight + lineHeight + seekHeight + 2 * interval, mTextPaint);
        canvas.restoreToCount(sc);
        mTextPaint.setXfermode(null);
        //----end-----绘制进度条

        //绘制游标
        canvas.drawBitmap(seekBitmap, mPositionX - seekOffsetX, bitmapTop, mTextPaint);
    }

    private float startX, startY;
    private float diffX;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startX = event.getX();
                startY = event.getY();
                diffX = startX - mPositionX;
                return checkEvent(startX, startY);
            case MotionEvent.ACTION_MOVE:
                float tempX = event.getX() - diffX;
                if (tempX >= seekOffsetX && tempX <= getWidth() - seekOffsetX) {
                    mPositionX = tempX;
                } else {
                    if (tempX < seekOffsetX) {
                        mPositionX = seekOffsetX;
                    } else {
                        mPositionX = getWidth() - seekOffsetX;
                    }
                }

                progress = (mPositionX - seekOffsetX) * 1.0 / (getWidth() - 2 * seekOffsetX);
                selectNum = (int) (max * progress);

                if (onSeekBarChangeListener != null) {
                    onSeekBarChangeListener.onProgressChanged(progress, selectNum);
                }

                invalidate();
                break;
        }
        return super.onTouchEvent(event);
    }

    private boolean checkEvent(float x, float y) {
        return (x >= mPositionX - seekOffsetX && x <= mPositionX + seekOffsetX) &&
                (y >= bitmapTop && y <= bitmapTop + seekBitmap.getHeight());
    }

    public void setMax(int max) {
        this.max = max;
    }

    public void setSelectNum(int selectNum) {
        if (selectNum < 0 || selectNum > max) {
            return;
        }

        this.selectNum = selectNum;
        this.progress = selectNum * 1.0 / max;

        if (progress < 0) {
            progress = 0;
        } else if (progress > 100) {
            progress = 100;
        }

        if (onSeekBarChangeListener != null) {
            onSeekBarChangeListener.onProgressChanged(progress, selectNum);
        }

        mPositionX = (float) ((getMeasuredWidth() - seekOffsetX * 2) * progress) + seekOffsetX;

        postInvalidate();
    }

    public int getSelectNum() {
        return selectNum;
    }

    public interface OnSeekBarChangeListener {
        void onProgressChanged(double progress, int selectNum);
    }

    private OnSeekBarChangeListener onSeekBarChangeListener;

    public void setOnSeekBarChangeListener(OnSeekBarChangeListener onSeekBarChangeListener) {
        this.onSeekBarChangeListener = onSeekBarChangeListener;
    }
}


发布评论

热门评论区: