Android自定View实现滑动验证效果的代码

效果图

自定义属性代码

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyCheckView">
        <attr name="m_blockBg" format="reference" /><!--滑块背景图片-->
        <attr name="m_blockColor" format="color" /><!--滑块颜色-->
        <attr name="m_blockShadowLayer" format="color" /><!--滑块阴影颜色-->
        <attr name="m_proColor" format="color" /><!--进度条颜色-->
        <attr name="m_recColor" format="color" /><!--矩形背景色-->
        <attr name="m_circleSize" format="integer" /><!--圆角角度值-->
    </declare-styleable>
</resources>

自定义View代码

public class MyCheckView extends View {

    private boolean isBlockArea = false;
    private boolean isMove = false;
    private boolean isFinish = false;
    private boolean isDown = false;
    private int mRight;
    private int startX = 0;

    /**
     * 滑块边距
     */
    private final int blockSize = SizeUtils.dp2px(5);

    /**
     * 相关属性
     */
    private int m_blockColor = Color.WHITE;//默认滑块颜色
    private int m_blockShadowLayer = Color.parseColor("#D8D8D8");//默认滑块阴影色
    private int m_proColor = Color.parseColor("#ff3159");//默认进度条颜色
    private int m_recColor = Color.parseColor("#D8D8D8");//默认矩形颜色
    private int blockDrawableId;//默认滑块背景图

    /**
     * 矩形画笔
     */
    private final Paint recPaint = new Paint();

    /**
     * 进度条画笔
     */
    private final Paint proPaint = new Paint();

    /**
     * 滑块画笔
     */
    private final Paint blockPaint = new Paint();

    /**
     * 圆角角度
     */
    private int circleSize = SizeUtils.dp2px(20);

    /**
     * 记录父控件宽度
     */
    private float parentWidth = 0f;

    /**
     * 矩形高度
     */
    private int proHeight;

    /**
     * 默认高度
     */
    private final int DEFAULT_HEIGHT = SizeUtils.dp2px(45);

    /**
     * 滑块宽度
     */
    private final int blockWidth = SizeUtils.dp2px(60);

    /**
     * 手指落下位置
     */
    private int dX;

    /**
     * 偏移距离
     */
    private int mX;

    /**
     * 接口回调
     */
    private FinishListener finishListener;

    public void setFinishListener(FinishListener finishListener) {
        this.finishListener = finishListener;
    }

    public MyCheckView(@NonNull Context context) {
        super(context);
        init();
    }

    public MyCheckView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initParams(context, attrs);
        init();
    }

    public MyCheckView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initParams(context, attrs);
        init();
    }

    /**
     * 初始化自定义属性
     *
     * @param context 上下文
     * @param attrs   属性参数
     */
    private void initParams(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyCheckView);
        if (typedArray != null) {
            //获取滑块背景图片
            blockDrawableId = typedArray.getResourceId(R.styleable.MyCheckView_m_blockBg, -1);
            //获取滑块颜色
            m_blockColor = typedArray.getColor(R.styleable.MyCheckView_m_blockColor, m_blockColor);
            //滑块阴影色
            m_blockShadowLayer = typedArray.getColor(R.styleable.MyCheckView_m_blockColor, m_blockShadowLayer);
            //进度条颜色
            m_proColor = typedArray.getColor(R.styleable.MyCheckView_m_blockColor, m_proColor);
            //矩形颜色
            m_recColor = typedArray.getColor(R.styleable.MyCheckView_m_blockColor, m_recColor);
            //圆角角度值
            circleSize = typedArray.getInt(R.styleable.MyCheckView_m_blockColor, circleSize);
            typedArray.recycle();
        }
    }

    /**
     * 初始化画笔
     */
    private void init() {
        //设置矩形背景色
        recPaint.setColor(m_recColor);
        recPaint.setStyle(Paint.Style.FILL);
        recPaint.setAntiAlias(true);

        //设置进度条背景色
        proPaint.setColor(m_proColor);
        proPaint.setStyle(Paint.Style.FILL);
        recPaint.setAntiAlias(true);

        //判断是否使用了背景图
        if (blockDrawableId != -1) {
            //设置滑块背景色
            blockPaint.setColor(m_blockColor);
            blockPaint.setStyle(Paint.Style.FILL_AND_STROKE);
            blockPaint.setAntiAlias(true);
            //给滑块添加阴影
            blockPaint.setShadowLayer(35, 1, 1, m_blockShadowLayer);
        } else {
            blockPaint.setStyle(Paint.Style.FILL_AND_STROKE);
            blockPaint.setAntiAlias(true);
        }
    }

    public void blockReset() {
        mX = 0;
        reset(startX);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        parentWidth = getMyWSize(widthMeasureSpec);
        proHeight = getMyHSize(heightMeasureSpec);
        setMeasuredDimension((int) parentWidth, proHeight);

    }

    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制矩形
        RectF rectF = new RectF();
        rectF.left = 1;
        rectF.right = parentWidth - 1;
        rectF.top = 1;
        rectF.bottom = proHeight - 1;
        //绘制圆角矩形
        canvas.drawRoundRect(rectF, circleSize, circleSize, recPaint);

        if (isMove || isDown) {
            //绘制进度条
            RectF rectP = new RectF();
            rectP.left = 1;
            rectP.right = blockWidth + blockSize + mX;
            rectP.top = 1;
            rectP.bottom = proHeight - 1;
            canvas.drawRoundRect(rectP, circleSize, circleSize, proPaint);
        }

        //绘制滑块
        RectF rectB = new RectF();
        rectB.left = blockSize + mX;
        rectB.right = blockWidth + mX;
        rectB.top = blockSize;
        rectB.bottom = proHeight - blockSize;

        mRight = (int) rectB.right;

        //判断是否使用了背景图
        if (blockDrawableId != -1) {
            //绘制背景图
            Bitmap bitmap = BitmapFactory.decodeResource(getResources(), blockDrawableId);
            Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
            canvas.drawBitmap(bitmap, rect, rectB, blockPaint);
        } else {
            //绘制滑块
            canvas.drawRoundRect(rectB, circleSize, circleSize, blockPaint);
        }

    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                dX = (int) event.getX();
                int dY = (int) event.getY();
                int top = getTop();
                int bottom = getBottom();
                //判断区域是否为滑块
                if (dX > blockSize && dX < blockWidth && dY > blockSize && dY < (bottom - top)) {
                    isBlockArea = true;
                }
                return true;
            case MotionEvent.ACTION_MOVE:

                if (isBlockArea) {
                    mX = (int) event.getX() - dX;
                    //设置范围
                    if ((blockWidth + blockSize + mX) < parentWidth && (blockSize + mX) >= blockSize) {
                        //计算偏移量
                        invalidate();
                        startX = (int) event.getX() - blockWidth / 2;
                    } else if ((blockSize + mX) >= blockSize) {
                        //超出复位
                        mX = (int) parentWidth - blockWidth - blockSize;
                        invalidate();
                    }
                    isMove = true;
                }
                return true;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                isBlockArea = false;
                isFinish = mRight == parentWidth - blockSize;
                if (isFinish) {
                    //监听回调
                    if (finishListener != null) {
                        finishListener.finish();
                    }
                }
                if (!isFinish && isMove) {
                    reset(startX);
                }
                break;
        }
        return super.onTouchEvent(event);
    }

    /**
     * 松手回弹动画效果
     */
    private void reset(int start) {

        ValueAnimator valueAnimator = ValueAnimator.ofInt(start, 0);
        valueAnimator.setDuration(500);
        valueAnimator.start();
        valueAnimator.addUpdateListener(animation -> {
            mX = (int) animation.getAnimatedValue();
            //刷新
            invalidate();
        });
        valueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                isMove = false;
                isFinish = false;
                startX = 0;
            }
        });
    }

    /**
     * 获取测量大小
     */
    private int getMyWSize(int measureSpec) {
        int result;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;//确切大小,所以将得到的尺寸给view
        } else if (specMode == MeasureSpec.AT_MOST) {
            result = Math.min(getScreenWidth() - 20, specSize);
        } else {
            result = getScreenWidth() - 20;
        }
        return result;
    }

    /**
     * 获取测量大小
     */
    private int getMyHSize(int measureSpec) {
        int result;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;//确切大小,所以将得到的尺寸给view
        } else if (specMode == MeasureSpec.AT_MOST) {
            result = Math.min(DEFAULT_HEIGHT, specSize);
        } else {
            result = DEFAULT_HEIGHT - 20;
        }
        return result;
    }

    /**
     * 获取屏幕宽度
     */
    private int getScreenWidth() {
        WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        windowManager.getDefaultDisplay().getMetrics(displayMetrics);
        return displayMetrics.widthPixels;
    }

    /**
     * 接口回调方法
     */
    public interface FinishListener {
        void finish();
    }

}

使用方法

<com.guanwei.globe.view.MyCheckView
        android:id="@+id/checkView"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:m_blockBg="@mipmap/block" />

到此这篇关于Android自定View实现滑动验证效果的文章就介绍到这了,更多相关Android自定View滑动验证内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android 高仿斗鱼滑动验证码

    如下图.在Android上实现起来就不太容易,有些效果还是不如web端酷炫.) 我们的Demo,Ac娘镇楼 (图很渣,也忽略底下的SeekBar,这不是重点) 一些动画,效果录不出来了,大家可以去斗鱼web端看一下,然后下载Demo看一下,效果还是可以的. 代码 传送门: https://github.com/mcxtzhang/SwipeCaptcha 我们的Demo和web端基本上一样. 那么本控件包含不仅包含以下功能: 随机区域起点(左上角x,y)生成一个验证码阴影.验证码拼图 凹凸图形会

  • Android自定view画圆效果

    这是一个自定义view画圆,对于初学自定义view的小伙伴这是一个很好的帮助. 看图 代码: package sjx.com.custonview; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.support.annotation.Nullable; impor

  • Android自定义SeekBar实现滑动验证且不可点击

    最近公司因为短信接口被盗刷的比较严重,需要做一个类似于淘宝的滑动验证,用于特定环境,以增加一层保障.拿到需求首先想到的是自定义ViewGroup来实现,里面放一个seekbar和TextView即可.但是有更简单的方法,直接在布局中放入seekbar和TextView,不就ok了?用最简单快捷的方法实现需求,才是硬道理. 值得一提的是,seekbar默认情况下是支持点击事件的,也就是说,用户可以直接点击进度条以实现滑动验证这是不允许的,因此,自定义seekbar,屏蔽点击事件.下面我们先从see

  • Android自定义滑动验证条的示例代码

    本文介绍了Android自定义滑动验证条的示例代码,分享给大家,具体如下: *注:不知道为什么,h5的标签在这里没用了,所以我也只能用Markdown的语法来写了 项目地址:https://github.com/994866755/handsomeYe.seekbar.github.io 需求: 在我们的某些应用中需要滑动验证.比如说这个样子的: 刚开始我也很懵逼要怎么去弄,结果我去看了一些人的代码,有人是用自定义viewgroup去做,就是viewgroup包含滑动块和滑动条.但我觉得太麻烦,

  • Android自定View流式布局根据文字数量换行

    本文实例为大家分享了Android根据文字数量换行的具体代码,供大家参考,具体内容如下 //主页 定义数据框 package com.example.customwaterfallviewgroup; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.EditText; import java.util

  • Android控件SeekBar仿淘宝滑动验证效果

    SeekBar是一个拖动条控件,最简单的案例就是我们的调节音量,还有音频视频的播放,传统的SeekBar样式,如图 传统的实现太简单,不足以让我们到能装逼的地步.本来是打算实现滴滴出行滑动完成订单的效果,可惜找不到效果图,今天也就用淘宝的滑动验证来作为实例 1.1 实现分析 SeekBar:使用progressDrawable属性自定义SeekBar 拖动块:使用thumb属性更改,其实就是一张图片 文字:使用RelativeLayout嵌套在一起 1.2 实现布局 <?xml version=

  • Android 自定View实现仿QQ运动步数圆弧及动画效果

    在之前的Android超精准计步器开发-Dylan计步中的首页用到了一个自定义控件,和QQ运动的界面有点类似,还有动画效果,下面就来讲一下这个View是如何绘制的. 1.先看效果图 2.效果图分析 功能说明:黄色的代表用户设置的总计划锻炼步数,红色的代表用户当前所走的步数. 初步分析:完全自定义View重写onDraw()方法,画圆弧. 3.画一个圆弧必备知识 在Canvas中有一个画圆弧的方法 drawArc(RectF oval, float startAngle, float sweepA

  • Android自定View实现滑动验证效果的代码

    效果图 自定义属性代码 <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="MyCheckView"> <attr name="m_blockBg" format="reference" /><!--滑块背景图片--> <attr name=&

  • Android自定义view实现滑动解锁效果

    本文实例为大家分享了Android自定义view实现滑动解锁的具体代码,供大家参考,具体内容如下 1. 需求如下: 近期需要做一个类似屏幕滑动解锁的功能,右划开始,左划暂停. 2. 需求效果图如下 3. 实现效果展示 4. 自定义view如下 /** * Desc 自定义滑动解锁View * Author ZY * Mail sunnyfor98@gmail.com * Date 2021/5/17 11:52 */ @SuppressLint("ClickableViewAccessibili

  • Android实现仿通讯录侧边栏滑动SiderBar效果代码

    本文实例讲述了Android实现仿通讯录侧边栏滑动SiderBar效果代码.分享给大家供大家参考,具体如下: 之前看到某些应用的侧边栏做得不错,想想自己也弄一个出来,现在分享出来,当然里面还有不足的地方,请大家多多包涵. 先上图: 具体实现的代码如下: package com.freesonfish.listview_index; import android.content.Context; import android.graphics.Canvas; import android.grap

  • Android 通过自定义view实现水波纹效果案例详解

    在实际的开发中,很多时候还会遇到相对比较复杂的需求,比如产品妹纸或UI妹纸在哪看了个让人兴奋的效果,兴致高昂的来找你,看了之后目的很明确,当然就是希望你能给她: 在这样的关键时候,身子板就一定得硬了,可千万别说不行,爷们儿怎么能说不行呢: 好了,为了让大家都能给妹纸们想要的,后面会逐渐分享一些比较比较不错的效果,目的只有一个,通过自定义view实现我们所能实现的动效: 今天主要分享水波纹效果: 标准正余弦水波纹: 非标准圆形液柱水波纹: 虽说都是水波纹,但两者在实现上差异是比较大的,一个通过正余

  • Android activity和view判断滑动

    Android activity和view判断滑动 实例代码: //手指按下的点为(x1, y1)手指离开屏幕的点为(x2, y2) float x1 = 0; float x2 = 0; float y1 = 0; float y2 = 0; @Override public boolean onTouchEvent(MotionEvent event) { //继承了Activity的onTouchEvent方法,直接监听点击事件 if(event.getAction() == Motion

  • Android 仿今日头条简单的刷新效果实例代码

    点击按钮,先自动进行下拉刷新,也可以手动刷新,刷新完后,最后就多一行数据.有四个选项卡. 前两天导师要求做一个给本科学生预定机房座位的app,出发点来自这里.做着做着遇到很多问题,都解决了.这个效果感觉还不错,整理一下. MainActivity package com.example.fragmentmytest; import android.content.DialogInterface; import android.graphics.Color; import android.os.B

  • Android界面上拉下拉的回弹效果实例代码

    废话不多说,具体代码如下所示: public class MyScrollView extends ScrollView { private View childView; public MyScrollView(Context context) { super(context); } public MyScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public MyScrollView(Co

  • Android仿微信对话列表滑动删除效果

    微信对话列表滑动删除效果很不错的,借鉴了github上SwipeListView(项目地址:https://github.com/likebamboo/SwipeListView),在其上进行了一些重构,最终实现了微信对话列表滑动删除效果. 实现原理  1.通过ListView的pointToPosition(int x, int y)来获取按下的position,然后通过android.view.ViewGroup.getChildAt(position)来得到滑动对象swipeView  2

  • Android仿网易新闻图片详情下滑隐藏效果示例代码

    前言 本文主要给大家分享了Android仿网易新闻图片详情下滑隐藏效果的相关内容,分享出来供需要的朋友参考学习,下面话不多说了,来一起看看详细的介绍吧 效果图: 实例代码 public class InfoTextView extends AutoRelativeLayout { private Context context; private int lastY; private int offY; private int MIN_HEIGHT = 600; public InfoTextVi

随机推荐