自定义漂亮的seekBar,内带popwindow及指示器

来源:互联网 发布:软件测试举例 编辑:程序博客网 时间:2024/04/29 00:21

看到了一个App自定义的SeekBar很有趣,尝试着自己做一个。

不废话,先上图,看是否是你期望的:


增加了背景图片的自定义,增加了Thumb的自定义。当然还有动画效果。会动画滑动到附近的点。具体代码稍后奉上...

啊。。。乱七八糟事儿太多,这几天都没时间整理

这个demo的点可以自定义数量,并增加回调。我就不写原理了...直接把代码传上去...有时间再写...


首先需要画出seekbar的背景drawable:

package com.zkbc.tougu.demo;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.ColorFilter;import android.graphics.LinearGradient;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.RectF;import android.graphics.Shader;import android.graphics.drawable.Drawable;/** * 自定义seekBar背景图 * Created by Rock Lee on 2016/6/21. */public class MySeekBarDrawable extends Drawable {    int pointCount;    int startColor;    int centerColor;    int endColor;    private Paint paint;//画笔(背景)    LinearGradient shader;    private Paint paintCircle;//画笔-外圆    private Paint paintCircleCenter;//画笔-内圆    RectF rectF;//矩形上下左右的坐标    int colors[] = new int[3];//三个颜色渐变(shader)    float positions[] = new float[3];//渐变色的三个点(shader)    public MySeekBarDrawable(int pointCount, int startColor, int centerColor, int endColor) {        this.pointCount = pointCount * 2;//增加两点之间的中线        this.startColor = startColor;        this.centerColor = centerColor;        this.endColor = endColor;        paint = new Paint();        paintCircle = new Paint();        paintCircleCenter = new Paint();        rectF = new RectF();    }    @Override    public void draw(Canvas canvas) {        final Rect bounds = getBounds();        // 第1个点        colors[0] = startColor;        positions[0] = 0;        // 第2个点        colors[1] = centerColor;        positions[1] = 0.5f;        // 第3个点        colors[2] = endColor;        positions[2] = 1;        //是否有中间色        if (centerColor == 0) {            shader = new LinearGradient(0f, 0f, bounds.width(), bounds.height(), startColor, endColor, Shader.TileMode.MIRROR);        } else {            shader = new LinearGradient(0f, 0f, bounds.width(), bounds.height(), colors, positions, Shader.TileMode.MIRROR);        }        paint.setShader(shader);        paint.setStrokeCap(Paint.Cap.ROUND);// 圆角        paint.setAntiAlias(true); // 消除锯齿        paintCircle.setShader(shader);//        paintCircle.setStyle(Paint.Style.STROKE); // 设置空心//        paintCircle.setStrokeWidth(bounds.height()/2); // 设置笔画的宽度        paintCircle.setAntiAlias(true); // 消除锯齿        paintCircleCenter.setAntiAlias(true); // 消除锯齿        paintCircleCenter.setColor(Color.WHITE);        float lineHeight = bounds.height()/4.0f;        rectF.set(0, bounds.centerY() - lineHeight, bounds.width(), bounds.centerY() + lineHeight);        //绘制圆角矩形        canvas.drawRoundRect(rectF, lineHeight, lineHeight, paint);        float section = (float) bounds.width() / pointCount;        for (int i = 1; i < pointCount; i++) {            paint.setShader(null);            paint.setColor(Color.WHITE);//            paint.setStrokeWidth(1);            float cx = section * i;//X轴圆心坐标            if (i % 2 == 0) {                canvas.drawLine(cx, bounds.centerY() - lineHeight, cx, bounds.centerY() + lineHeight, paint);            } else {                canvas.drawCircle(cx, bounds.centerY(), lineHeight*2, paintCircle);                canvas.drawCircle(cx, bounds.centerY(), lineHeight, paintCircleCenter);            }        }    }    @Override    public void setAlpha(int alpha) {        paint.setAlpha(alpha);    }    @Override    public void setColorFilter(ColorFilter colorFilter) {        paint.setColorFilter(colorFilter);    }    @Override    public int getOpacity() {        return 1 - paint.getAlpha();    }    /**     * MySeekBarDrawable Builder     */    public static class Builder {        /**         * 分割段数         */        int pointCount;        /**         * 起始颜色         */        int startColor;        /**         * 中间色         */        int centerColor;        /**         * 结束颜色         */        int endColor;        /**         * Sets the seekBar point count.         *         * @returns This Builder         */        public Builder setPointCount(int pointCount) {            this.pointCount = pointCount;            return this;        }        /**         * Sets the seekBar start color.         *         * @param startColor start color in #AARRGGBB format.         * @returns This Builder         */        public Builder setStartColor(int startColor) {            this.startColor = startColor;            return this;        }        /**         * Sets the seekBar center color.         *         * @param centerColor center color in #AARRGGBB format.         * @returns This Builder         */        public Builder setCenterColor(int centerColor) {            this.centerColor = centerColor;            return this;        }        /**         * Sets the seekBar end color.         *         * @param endColor end color in #AARRGGBB format.         * @returns This Builder         */        public Builder setEndColor(int endColor) {            this.endColor = endColor;            return this;        }        /**         * Creates a new MySeekBarDrawable with the requested parameters         *         * @return New MySeekBarDrawableInstance         */        public MySeekBarDrawable create() {            return new MySeekBarDrawable(pointCount, startColor, centerColor, endColor);        }    }}

第二步:自定义seekbar,并将我们的自定义drawable附上:


package com.zkbc.tougu.demo;import android.animation.Animator;import android.animation.AnimatorSet;import android.animation.ObjectAnimator;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.drawable.BitmapDrawable;import android.graphics.drawable.Drawable;import android.util.AttributeSet;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.view.animation.AccelerateDecelerateInterpolator;import android.widget.LinearLayout;import android.widget.PopupWindow;import android.widget.SeekBar;import android.widget.TextView;import com.zkbc.tougu.R;/** * 自定义seekBar * Created by Rock Lee on 2016/6/21. */public class MyNiceSeekBar extends SeekBar implements SeekBar.OnSeekBarChangeListener {    private int pointCount;    private int startColor;    private int centerColor;    private int endColor;    public final int oneLength = 100;//每个隔断的刻度    int risk;    TextView centerText;    Drawable thumbDrawable;    View thumb;    MySeekBarDrawable drawable;    SeekBarInterface barInterface;//参数回调    SeekBarOnDrawListener onDrawListener;//seekBar绘画监听    private boolean mPopupStyle;//是否显示pop    private boolean mThumbStyle;    private int xOffset;    private PopupWindow mPopup;    private TextView mPopupTextView;    private int mYLocationOffset;    public MyNiceSeekBar(Context context) {        this(context, null);    }    public MyNiceSeekBar(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public MyNiceSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init(context, attrs);    }    private void init(Context context, AttributeSet attrs) {        TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.MySeekBar);        pointCount = mTypedArray.getInteger(R.styleable.MySeekBar_pointCount, 5);        startColor = mTypedArray.getColor(R.styleable.MySeekBar_startColor, Color.GREEN);        centerColor = mTypedArray.getColor(R.styleable.MySeekBar_centerColor, 0);        endColor = mTypedArray.getColor(R.styleable.MySeekBar_endColor, Color.RED);        mPopupStyle = mTypedArray.getBoolean(R.styleable.MySeekBar_popupStyle, false);        mThumbStyle = mTypedArray.getBoolean(R.styleable.MySeekBar_popupStyle, false);        xOffset = (int) mTypedArray.getDimension(R.styleable.MySeekBar_xOffset, 0);        mYLocationOffset = (int) mTypedArray.getDimension(R.styleable.MySeekBar_yOffset, 0);        mTypedArray.recycle();        setMax(pointCount * 2 * oneLength);        setProgress(3 * oneLength);        setOnSeekBarChangeListener(this);        drawable = new MySeekBarDrawable.Builder()                .setPointCount(pointCount)                .setStartColor(startColor)                .setCenterColor(centerColor)                .setEndColor(endColor).create();        setProgressDrawable(drawable);        initThumb((getProgress() / (2 * oneLength) + 1) + "");        initHintPopup();    }    public void initThumb(String risk) {        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);        thumb = inflater.inflate(R.layout.seekbar_thumb, null);        centerText = (TextView) thumb.findViewById(R.id.text1);        if (mThumbStyle) {            centerText.setText(risk);        }        thumbDrawable = convertViewToDrawable(thumb);        setThumb(thumbDrawable);    }    public static Drawable convertViewToDrawable(View view) {        view.measure(                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));        view.layout(0, 0, view.getMeasuredHeight(), view.getMeasuredHeight());        view.setDrawingCacheEnabled(true);        Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache(true));        Drawable drawable = new BitmapDrawable(null, bitmap);        view.destroyDrawingCache();        view.setDrawingCacheEnabled(false);        return drawable;    }    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);    }    @Override    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight());    }    @Override    protected synchronized void onDraw(Canvas canvas) {        super.onDraw(canvas);        if (onDrawListener != null) {            onDrawListener.onDrawListener();        }    }    @Override    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {        //进度改变时调用        risk = getTargetProgress(seekBar) / (2 * oneLength) + 1;        String popupText;        if (barInterface != null) {            int targetProgress = getTargetProgress(seekBar);            popupText = barInterface.progressChangeCallBack(this, getProgress(), targetProgress);            mPopupTextView.setText(popupText != null ? popupText : String.valueOf(targetProgress));        }        if (mPopupStyle && mPopup != null) {            showPopup();            mPopup.update(this, (int) getXPosition(getProgress(), mPopup.getContentView()), -(this.getHeight() + mPopup.getContentView().getMeasuredHeight() + mYLocationOffset), -1, -1);        } else {            hidePopup();        }    }    @Override    public void onStartTrackingTouch(SeekBar seekBar) {        //进度条开始拖动的时候调用        showPopup();        centerText.setText("");        thumbDrawable = convertViewToDrawable(thumb);        setThumb(thumbDrawable);    }    @Override    public void onStopTrackingTouch(SeekBar seekBar) {        //进度条停止拖动的时候调用        int targetProgress = getTargetProgress(seekBar);        dodo(seekBar.getProgress(), targetProgress);        if (mThumbStyle) {            centerText.setText(risk + "");        }        thumbDrawable = convertViewToDrawable(thumb);        setThumb(thumbDrawable);    }    /**     * 赋值+执行动画     *     * @param progressText   当前滑动的点     * @param targetProgress 自动滑动到目标点     */    public void dodo(int progressText, int targetProgress) {        AnimatorSet animation = new AnimatorSet();        ObjectAnimator progressAnimation = ObjectAnimator.ofInt(this, "progress",                progressText, targetProgress);        progressAnimation.setDuration(300);        progressAnimation.setInterpolator(new AccelerateDecelerateInterpolator());        //增加动画监听        progressAnimation.addListener(new Animator.AnimatorListener() {            @Override            public void onAnimationStart(Animator animation) {            }            @Override            public void onAnimationEnd(Animator animation) {                hidePopup();            }            @Override            public void onAnimationCancel(Animator animation) {                hidePopup();            }            @Override            public void onAnimationRepeat(Animator animation) {            }        });        animation.playTogether(progressAnimation);        animation.start();    }    /**     * 选中回调     *     * @param barInterface 回调监听     */    public void setSeekBarCallBack(SeekBarInterface barInterface) {        this.barInterface = barInterface;    }    /**     * 绘画监听接口     *     * @param onDrawListener 绘画监听实现接口     */    public void setOnDrawListener(SeekBarOnDrawListener onDrawListener) {        this.onDrawListener = onDrawListener;    }    /**     * 是否显示pop     * @param style 是否显示pop     */    public void setPopupStyle(boolean style) {        mPopupStyle = style;    }    private void initHintPopup() {        String popupText = null;        if (barInterface != null) {            int targetProgress = getTargetProgress(this);            popupText = barInterface.progressChangeCallBack(this, getProgress(), targetProgress);        }        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);        final View undoView = inflater.inflate(R.layout.popup, null);        mPopupTextView = (TextView) undoView.findViewById(R.id.text);        mPopupTextView.setText(popupText != null ? popupText : String.valueOf(getProgress()));        mPopup = new PopupWindow(undoView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, false);        mPopup.getContentView().measure(0, 0);//获取测量后的popWindow高度        mPopup.setAnimationStyle(R.style.fade_animation);    }    private void showPopup() {        if (mPopupStyle) {            mPopup.showAsDropDown(this, (int) getXPosition(getProgress(), mPopup.getContentView()), -(this.getHeight() + mPopup.getContentView().getMeasuredHeight() + mYLocationOffset));        }    }    private void hidePopup() {        if (mPopup != null && mPopup.isShowing()) {            mPopup.dismiss();        }    }    /**     * 获取X坐标     *     * @param progress 进度     * @param v        在seekBar上显示的View     * @return X     */    private float getXPosition(int progress, View v) {        //seekBar总宽度包含ThumbOffset两边        float val = (((float) progress * ((float) getWidth())) / (float) getMax());        int textWidth = v.getMeasuredWidth();        float textCenter = (textWidth / 2.0f) + xOffset;        return val - textCenter;    }    /**     * 获取目标进度     *     * @return 返回目标进度     */    private int getTargetProgress(SeekBar seekBar) {        int targetProgress;//进度参数回调默认值        int proNow = seekBar.getProgress();//当前点        int yu = proNow % oneLength;//取余数        if ((proNow / oneLength) % 2 == 0) {            //是否为满进度,满进度回退一格            targetProgress = proNow == getMax() ? proNow - oneLength : proNow + oneLength - yu;        } else {            targetProgress = proNow - yu;        }        return targetProgress;    }    /**     * 设置推荐坐标     *     * @param recommendPosition 显示在第几个点,从0开始     * @param ll_recommend     */    public void setRecommendPosition(int recommendPosition, View ll_recommend) {        int progress = oneLength + recommendPosition * 2 * oneLength;        float x = getXPosition(progress, ll_recommend);        LinearLayout.LayoutParams pa = (LinearLayout.LayoutParams) ll_recommend.getLayoutParams();        pa.setMargins((int) x, 0, 0, 0);        ll_recommend.setLayoutParams(pa);    }
    public int getRisk() {        return risk;    }    public void setRisk(int risk) {        this.risk = risk;    }    /**     * 是否显示Thumb数字     * @param mThumbStyle     */    public void setThumbStyle(boolean mThumbStyle) {        this.mThumbStyle = mThumbStyle;    }}

使用方式:

private void initSeekbar() {        recommend = 3;        mSeekBar1.initThumb((mSeekBar1.getProgress() / (2 * mSeekBar1.oneLength)) + "");        mSeekBar1.setSeekBarCallBack(new SeekBarInterface() {            @Override            public String progressChangeCallBack(MyNiceSeekBar myNiceSeekBar, int progress, int targetProgress) {                risk = myNiceSeekBar.getRisk();                myNiceSeekBar.setRisk(risk);                                //返回Pop上需要显示的字符串                return "节点" + risk;            }        });        mSeekBar1.setOnDrawListener(new SeekBarOnDrawListener() {            @Override            public void onDrawListener() {                mSeekBar1.setRecommendPosition(recommend, ll_recommend);            }        });    }





2 0
原创粉丝点击