自定义滑动解锁View

先写出自定义View界面

代码如下:先创建一个View继承View,然后重写测量方法去测量出要显示的真是高度,再重写绘制方法,去把这个按钮绘制在什么位置。然后就是为我们后续的触摸事件做准备,重写OnTouchEvent()

package com.example.z.selfscrollunlock;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by z on 2017/11/25.
 */

public class SelfUnLockView extends View {

    private Bitmap mBitmap;
    private int mHeight;
    private int mWidth;
    private Paint mPaint;
    private int mWidth1;

    public SelfUnLockView(Context context) {
        this(context, null);
    }

    public SelfUnLockView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.switch_button);
        mHeight = mBitmap.getHeight();
        mWidth = mBitmap.getWidth();
        mPaint = new Paint();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mWidth1 = MeasureSpec.makeMeasureSpec(widthMeasureSpec, MeasureSpec.EXACTLY);
        setMeasuredDimension(mWidth1, mHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(mBitmap, 0, 0, mPaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                float rawX = event.getRawX();
                //当我手指触摸到滑块时候,滑块过来要移动这个点减去滑块一般的长度  raw
                float moveX = rawX - mWidth / 2;
                scrollTo((int) -moveX,0);
                break;
            case MotionEvent.ACTION_MOVE:

                break;
            case MotionEvent.ACTION_UP:

                break;

        }


        return super.onTouchEvent(event);
    }
}

在自定义View 的构造方法中,我们去初始化一个画笔,初始化背景的 长 宽。在onTouch()中,处理触摸事件,在手指按下的时候,让滑块中间位置移动到触摸点:注意,这个ScrollTo方法,往右边移动是减去一个数,可以想成,水调用这个Scroll方法,是this ,当前自定义View。你简单记忆成这个移动是移动他的爹,滑块向右移动,你就当成是滑块不动,他爹应该是往那边移动才是我们想要的结果,他爹是往左边移动才行。我们的左边是右边正,往左了肯定是负。效果如下:

但是很多问题,比如越界问题,回弹等,我们一步一步处理

处理点击滑块外部不响应

把这个滑动事件判断一下执行:

 if (rawX > 0 && rawX < mWidth) {
         scrollTo((int) -moveX, 0);
    }

处理左边越界问题

更改一个地方:

 if (rawX > mWidth/2 && rawX < mWidth) {

处理滑块滑动

在ontouch事件的move 动作中处理:并处理滑动越界问题

  case MotionEvent.ACTION_MOVE:
                //处理越界问题
                float rawXMove = event.getRawX();//
                if(rawXMove >mWidth/2 && rawXMove <=getMeasuredWidth()-mWidth/2){
                    float dexX = rawXMove - mWidth/2; //变化量
                    scrollTo((int) ( - dexX), 0);
                }
                break;

注意上面的滑动越界问题,我是通过手指的位置判断的,当然你可以通过一个增加量来判断是否满足条件,如果满足不满足条件直接把偏移量置零或者最大 。注意上面的判断有个细节,我使用的是getMeasuredWidth( ) 来处理,并不是用的mWidth1,如果你是用后者,你会发现这个值非常大。会越界。这里的getMeasuredWidth()拿的值就是控件背景宽度。如果弄不明白就直接使用增加量判断

你的滑块是否能滑动呢?

如果你的滑块能点击,不能滑动,注意看你的自定义控件是否消费事件,如果没有消费事件,就是掉super方法,肯定不会处理,所以你要返回值改为true.消费时间才行,因为滑动事件和点击事件不同的!

滑块的回原点

case MotionEvent.ACTION_UP:
       float endRawX = event.getRawX();
       if(endRawX <getWidth() - mWidth/2 ){
           scrollTo(0,0);
       }else {
           Toast.makeText(getContext(),"解锁成功",Toast.LENGTH_LONG).show();
       }

解锁不成功,缓慢回弹

1.创建Scroller对象
2.调用startScroll 方法去滚动 ,配置滚动信息
3.出发重新绘制调用 invalidate();
4.计算滚动的偏移量。重写computerScroll( ) ,根据当前已过时间计算偏移量 返回的是boolean值,如果没结束,就是滚动还没有结束, scroller.scrollTo(X,getcriiX(),0)然后出发绘制,完整代码如下:

package com.example.z.selfscrollunlock;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Scroller;
import android.widget.Toast;

/**
 * Created by z on 2017/11/25.
 */

public class SelfUnLockView extends View {

    private Bitmap mBitmap;
    private int mHeight;
    private int mWidth;
    private Paint mPaint;
    private int mWidth1;
    private float mRawX;
    private Scroller mScroller;
    private ScrollListener mListener;

    public SelfUnLockView(Context context) {
        this(context, null);
    }

    public SelfUnLockView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.switch_button);
        mHeight = mBitmap.getHeight();
        mWidth = mBitmap.getWidth();
        mPaint = new Paint();

        mScroller = new Scroller(getContext());
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mWidth1 = MeasureSpec.makeMeasureSpec(widthMeasureSpec, MeasureSpec.EXACTLY);
        setMeasuredDimension(mWidth1, mHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(mBitmap, 0, 0, mPaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mRawX = event.getRawX();
                //当我手指触摸到滑块时候,滑块过来要移动这个点减去滑块一般的长度  raw
                float moveX = mRawX - mWidth / 2;
                if (mRawX > mWidth / 2 && mRawX < mWidth) {
                    scrollTo((int) -moveX, 0);
                }
                break;
            case MotionEvent.ACTION_MOVE:
                //处理越界问题
                float rawXMove = event.getRawX();//
                if(rawXMove >mWidth/2 && rawXMove <=getMeasuredWidth()-mWidth/2){
                    float dexX = rawXMove - mWidth/2; //变化量
                    scrollTo((int) ( - dexX), 0);
                }
                break;
            case MotionEvent.ACTION_UP:
                float endRawX = event.getRawX();
                if(endRawX <getWidth() - mWidth/2 ){
                  /*  mScroller.startScroll(getScrollX(),0,0-getScrollX(),0,500); //配置滚动信息
//                    invalidate();
//                    scrollTo(0,0);*/
                    int startX = getScrollX();//滚动开始时滚动偏移量
                    int startY = 0;
                    int endX = 0;//滚动最终位置的滚动偏移量
                    int dx = endX - startX;//滚动偏移量的变化量
                    int dy =0;
                    int duration = 1500;//滚动时长
                    //step2:配置滚动的成员变量
                    mScroller.startScroll(startX, startY, dx, dy, duration);
                    invalidate();//step3:触发重新绘制
                }else {
                    Toast.makeText(getContext(),"解锁成功",Toast.LENGTH_LONG).show();
                    /** 出发接口方法*/
                    if(mListener != null){
                        mListener.onScrollunLock();
                    }
                }
                break;
        }
        return true;
    }

    @Override
    public void computeScroll() {
       if(mScroller.computeScrollOffset()){
           scrollTo(mScroller.getCurrX(),0);
           invalidate();
       }
    }

    /**
     * 回调函数
     */
    public  interface ScrollListener{
       void onScrollunLock();
    }
    /**
     * 宫外不调用的方法
     */
    public  void  onScrollViewMethed(ScrollListener l){
        this.mListener  = l;
    }
}

测滑菜单

需求分析:
1.继承Viewgroup

2.测量布局孩子

3.处理越界问题

package com.example.z.selfscrollunlock;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by z on 2017/11/25.
 */

public class SlidingMenu extends ViewGroup {

    private float mRawX;
    private View mRight;
    private View mLeft;
    private int mMeasuredWidth;
    private int mMeasuredWidth1;

    public SlidingMenu(Context context) {
        this(context, null);
    }

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        measureChildren(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        mLeft = getChildAt(0);
        mRight = getChildAt(1);
        mMeasuredWidth = mLeft.getMeasuredWidth();
        mMeasuredWidth1 = mRight.getMeasuredWidth();
        int measuredHeight = mLeft.getMeasuredHeight();
        int measuredHeight1 = mRight.getMeasuredHeight();

        mLeft.layout(-mMeasuredWidth, 0, 0, measuredHeight);
        mRight.layout(0, 0, mMeasuredWidth1, measuredHeight1);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mRawX = event.getRawX();
                break;
            case MotionEvent.ACTION_MOVE:
                float rawX1 = event.getRawX();
                float v = -rawX1 + mRawX; //滚动偏移量
                float finall = v + getScrollX(); //最终偏移量
                if(finall >0){
                    scrollTo(0,0);
                }else {
                    scrollTo(-mMeasuredWidth,0);
                }
                return  true;
//
//                int i = mMeasuredWidth1 - mMeasuredWidth;
//                if (v <-i) {
//                    v = i;
//                }
//                else if (v < -mMeasuredWidth) {
//                    v = 0;
//                }
////                scrollTo((int) -v, 0);
//                scrollBy((int) -v, 0);
//                mRawX = rawX1;
        }
        return true;
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,568评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,612评论 4 59
  • 昨天,我们给学校成绩优秀一些的学生开了一个会议,目的是想他们可以树立信心,把握好时间,高效学习,进而中考考出优秀的...
    amazing2017阅读 283评论 0 1