美文网首页编程实践view
Android 自定义仿SeekBar滑动验证

Android 自定义仿SeekBar滑动验证

作者: 小白彡 | 来源:发表于2019-12-06 22:08 被阅读0次

    最近在项目中遇到一个需要滑动验证的功能,样式如下:

              在未滑动时滑块为箭头形式,滑动到末端后变为对勾样式,滑动过的路径变为红色,遇到问题当然是先百度一番啦,没有对象,只能面向百度编程了,结果弄了半天都没找到合适的,大部分都是通过SeekBar来做的,但动态设置thumb的时候滑到首尾上面的thumb总是被覆盖掉一半,然后找了半天也没得到解决,没想到这东西资料这么少,没办法,只能自己来了,先看一下效果:

    效果大概就是这个样子,不是很完美,勉强够用,没滑到底松开会自动回到起点,

    下面来说一下具体实现:

    1. 自定义VerifiSeekBar(就这个控件)继承自View。

    2.画背景灰色圆角矩形,画上方红色圆角矩形,画初始状态滑块(带箭头),画结束状态滑块。

    3.TouchEvent监听手势,主要是X轴位置,根据屏幕上的坐标动态画红色矩形和滑块

    4.监听滑动距离是否到最后,到最后后画完成状态滑块(对勾)

    思路就是这个样子咯,思路对了的话,代码就很好写了,下面贴一下代码,写得不是很好,有啥不对的地方欢迎大家指教。

    ```

    public class VerifiSeekBar extends View {

    private Contextcontext;

        private Paintpaint;

        private int movex;

        private RectFbgRect;

        private RectFupRect;

        private BitmapinBitmap;

        private BitmapoutBitmap;

        private int bitmapWidth;

        private int bitmapHeight;

        //防止多次调用

        private boolean isNewdown =true;

        private OnSeekbarCompleListenneronSeekbarCompleListenner;

        public VerifiSeekBar(Context context) {

    super(context);

            this.context = context;

            initView();

        }

    public VerifiSeekBar(Context context, @Nullable AttributeSet attrs) {

    super(context, attrs);

            this.context = context;

            initView();

        }

    public VerifiSeekBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

    super(context, attrs, defStyleAttr);

            this.context = context;

            initView();

        }

    public void setProgress(int progress) {

    movex = progress;

            invalidate();

        }

    @Override

        protected void onDraw(Canvas canvas) {

    super.onDraw(canvas);

            paint.setColor(ContextCompat.getColor(context, R.color.seekbar_notclick));

            bgRect.set(0, 0, getWidth(), bitmapHeight + SizeUtils.dp2px(6));

            canvas.drawRoundRect(bgRect, SizeUtils.dp2px(5), SizeUtils.dp2px(5), paint);

            if (movex > getWidth()) {

    movex = getWidth();

            }

    if (movex <=0) {

    movex =0;

            }

    upRect.set(0, 0, movex, bitmapHeight + SizeUtils.dp2px(6));

            paint.setColor(ContextCompat.getColor(context, R.color.red));

            canvas.drawRoundRect(upRect, SizeUtils.dp2px(5), SizeUtils.dp2px(5), paint);

            if (movex == getWidth()) {

    getParent().requestDisallowInterceptTouchEvent(false);

              canvas.drawBitmap(outBitmap, movex -bitmapWidth <0 ?

    SizeUtils.dp2px(3) :movex - (bitmapWidth + SizeUtils.dp2px(3)),

    SizeUtils.dp2px(3), paint);

                if (onSeekbarCompleListenner !=null) {

    if (isNewdown) {

    onSeekbarCompleListenner.comple();

                        isNewdown =false;

                    }

    }

    }else {

    canvas.drawBitmap(inBitmap, movex -bitmapWidth <0 ? SizeUtils.dp2px(3) :movex -bitmapWidth, SizeUtils.dp2px(3), paint);

                if (onSeekbarCompleListenner !=null) {

    onSeekbarCompleListenner.uncomple();

                }

    }

    }

    private void initView() {

    paint =new Paint();

            paint.setStyle(Paint.Style.FILL);

            paint.setColor(ContextCompat.getColor(context, R.color.red));

            paint.setStrokeWidth(2);

            bgRect =new RectF();

            upRect =new RectF();

            inBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.login_move);

            outBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.login_ok);

            bitmapWidth =inBitmap.getWidth();

            bitmapHeight =inBitmap.getHeight();

        }

    @Override

        public boolean onTouchEvent(MotionEvent event) {

    switch (event.getAction()) {

    case MotionEvent.ACTION_DOWN:

    isNewdown =true;

                    movex =bitmapWidth + SizeUtils.dp2px(3);

                case MotionEvent.ACTION_MOVE:

    movex = (int) event.getX();

                    invalidate();

    break;

                case MotionEvent.ACTION_UP:

    if (movex < getWidth()) {

    movex =0;

                    }

    invalidate();

    break;

                default:

    break;

            }

    return true;

        }

    public void setOnSeekbarCompleListenner(OnSeekbarCompleListenner onSeekbarCompleListenner) {

    this.onSeekbarCompleListenner = onSeekbarCompleListenner;

        }

    public interface OnSeekbarCompleListenner {

    void comple();

            void uncomple();

        }

    }

    ```

    里面用到的工具类:

    ```

    public final class SizeUtils {

    private SizeUtils() {

    throw new UnsupportedOperationException("u can't instantiate me...");

        }

    /**

    * Value of dp to value of px.

    *

         * @param dpValue The value of dp.

         * @return value of px

    */

        public static int dp2px(final float dpValue) {

    final float scale = Resources.getSystem().getDisplayMetrics().density;

            return (int) (dpValue * scale +0.5f);

        }

    /**

    * Value of px to value of dp.

    *

         * @param pxValue The value of px.

         * @return value of dp

    */

        public static int px2dp(final float pxValue) {

    final float scale = Resources.getSystem().getDisplayMetrics().density;

            return (int) (pxValue / scale +0.5f);

        }

    /**

    * Value of sp to value of px.

    *

         * @param spValue The value of sp.

         * @return value of px

    */

        public static int sp2px(final float spValue) {

    final float fontScale = Resources.getSystem().getDisplayMetrics().scaledDensity;

            return (int) (spValue * fontScale +0.5f);

        }

    /**

    * Value of px to value of sp.

    *

         * @param pxValue The value of px.

         * @return value of sp

    */

        public static int px2sp(final float pxValue) {

    final float fontScale = Resources.getSystem().getDisplayMetrics().scaledDensity;

            return (int) (pxValue / fontScale +0.5f);

        }

    /**

    * Converts an unpacked complex data value holding a dimension to its final floating

         * point value. The two parameters <var>unit</var> and <var>value

         * are as in {@link TypedValue#TYPE_DIMENSION}.

    *

         * @param value The value to apply the unit to.

         * @param unit  The unit to convert from.

         * @return The complex floating point value multiplied by the appropriate

    * metrics depending on its unit.

    */

        public static float applyDimension(final float value, final int unit) {

    DisplayMetrics metrics = Utils.getApp().getResources().getDisplayMetrics();

            switch (unit) {

    case TypedValue.COMPLEX_UNIT_PX:

    return value;

                case TypedValue.COMPLEX_UNIT_DIP:

    return value * metrics.density;

                case TypedValue.COMPLEX_UNIT_SP:

    return value * metrics.scaledDensity;

                case TypedValue.COMPLEX_UNIT_PT:

    return value * metrics.xdpi * (1.0f /72);

                case TypedValue.COMPLEX_UNIT_IN:

    return value * metrics.xdpi;

                case TypedValue.COMPLEX_UNIT_MM:

    return value * metrics.xdpi * (1.0f /25.4f);

            }

    return 0;

        }

    /**

    * Force get the size of view.

         * <p>e.g.

         *

         * SizeUtils.forceGetViewSize(view, new SizeUtils.onGetSizeListener() {

    *     Override

    *     public void onGetSize(final View view) {

    *         view.getWidth();

    *     }

    * });

         *

         *

         * @param view     The view.

         * @param listener The get size listener.

    */

        public static void forceGetViewSize(final View view, final onGetSizeListener listener) {

    view.post(new Runnable() {

    @Override

                public void run() {

    if (listener !=null) {

    listener.onGetSize(view);

                    }

    }

    });

        }

    /**

    * Return the width of view.

    *

         * @param view The view.

         * @return the width of view

    */

        public static int getMeasuredWidth(final View view) {

    return measureView(view)[0];

        }

    /**

    * Return the height of view.

    *

         * @param view The view.

         * @return the height of view

    */

        public static int getMeasuredHeight(final View view) {

    return measureView(view)[1];

        }

    /**

    * Measure the view.

    *

         * @param view The view.

         * @return arr[0]: view's width, arr[1]: view's height

    */

        public static int[]measureView(final View view) {

    ViewGroup.LayoutParams lp = view.getLayoutParams();

            if (lp ==null) {

    lp =new ViewGroup.LayoutParams(

    ViewGroup.LayoutParams.MATCH_PARENT,

                        ViewGroup.LayoutParams.WRAP_CONTENT

                );

            }

    int widthSpec = ViewGroup.getChildMeasureSpec(0, 0, lp.width);

            int lpHeight = lp.height;

            int heightSpec;

            if (lpHeight >0) {

    heightSpec = View.MeasureSpec.makeMeasureSpec(lpHeight, View.MeasureSpec.EXACTLY);

            }else {

    heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);

            }

    view.measure(widthSpec, heightSpec);

            return new int[]{view.getMeasuredWidth(), view.getMeasuredHeight()};

        }

    ///////////////////////////////////////////////////////////////////////////

    // interface

    ///////////////////////////////////////////////////////////////////////////

        public interface onGetSizeListener {

    void onGetSize(View view);

        }

    }

    ```

    这就是整个的代码啦,代码不多,有需要的直接拷过去用就行了,替换一下图片,颜色,也可以做一下优化。

    相关文章

      网友评论

        本文标题:Android 自定义仿SeekBar滑动验证

        本文链接:https://www.haomeiwen.com/subject/kgxygctx.html