自定義滑動解鎖View

先寫出自定義View界面

代碼如下:先創(chuàng)建一個(gè)View繼承View,然后重寫測量方法去測量出要顯示的真是高度,再重寫繪制方法,去把這個(gè)按鈕繪制在什么位置。然后就是為我們后續(xù)的觸摸事件做準(zhǔn)備,重寫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();
                //當(dāng)我手指觸摸到滑塊時(shí)候,滑塊過來要移動這個(gè)點(diǎn)減去滑塊一般的長度  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 的構(gòu)造方法中,我們?nèi)コ跏蓟粋€(gè)畫筆,初始化背景的 長 寬。在onTouch()中,處理觸摸事件,在手指按下的時(shí)候,讓滑塊中間位置移動到觸摸點(diǎn):注意,這個(gè)ScrollTo方法,往右邊移動是減去一個(gè)數(shù),可以想成,水調(diào)用這個(gè)Scroll方法,是this ,當(dāng)前自定義View。你簡單記憶成這個(gè)移動是移動他的爹,滑塊向右移動,你就當(dāng)成是滑塊不動,他爹應(yīng)該是往那邊移動才是我們想要的結(jié)果,他爹是往左邊移動才行。我們的左邊是右邊正,往左了肯定是負(fù)。效果如下:

但是很多問題,比如越界問題,回彈等,我們一步一步處理

處理點(diǎn)擊滑塊外部不響應(yīng)

把這個(gè)滑動事件判斷一下執(zhí)行:

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

處理左邊越界問題

更改一個(gè)地方:

 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;

注意上面的滑動越界問題,我是通過手指的位置判斷的,當(dāng)然你可以通過一個(gè)增加量來判斷是否滿足條件,如果滿足不滿足條件直接把偏移量置零或者最大 。注意上面的判斷有個(gè)細(xì)節(jié),我使用的是getMeasuredWidth( ) 來處理,并不是用的mWidth1,如果你是用后者,你會發(fā)現(xiàn)這個(gè)值非常大。會越界。這里的getMeasuredWidth()拿的值就是控件背景寬度。如果弄不明白就直接使用增加量判斷

你的滑塊是否能滑動呢?

如果你的滑塊能點(diǎn)擊,不能滑動,注意看你的自定義控件是否消費(fèi)事件,如果沒有消費(fèi)事件,就是掉super方法,肯定不會處理,所以你要返回值改為true.消費(fèi)時(shí)間才行,因?yàn)榛瑒邮录忘c(diǎn)擊事件不同的!

滑塊的回原點(diǎn)

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.創(chuàng)建Scroller對象
2.調(diào)用startScroll 方法去滾動 ,配置滾動信息
3.出發(fā)重新繪制調(diào)用 invalidate();
4.計(jì)算滾動的偏移量。重寫computerScroll( ) ,根據(jù)當(dāng)前已過時(shí)間計(jì)算偏移量 返回的是boolean值,如果沒結(jié)束,就是滾動還沒有結(jié)束, scroller.scrollTo(X,getcriiX(),0)然后出發(fā)繪制,完整代碼如下:

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();
                //當(dāng)我手指觸摸到滑塊時(shí)候,滑塊過來要移動這個(gè)點(diǎn)減去滑塊一般的長度  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();//滾動開始時(shí)滾動偏移量
                    int startY = 0;
                    int endX = 0;//滾動最終位置的滾動偏移量
                    int dx = endX - startX;//滾動偏移量的變化量
                    int dy =0;
                    int duration = 1500;//滾動時(shí)長
                    //step2:配置滾動的成員變量
                    mScroller.startScroll(startX, startY, dx, dy, duration);
                    invalidate();//step3:觸發(fā)重新繪制
                }else {
                    Toast.makeText(getContext(),"解鎖成功",Toast.LENGTH_LONG).show();
                    /** 出發(fā)接口方法*/
                    if(mListener != null){
                        mListener.onScrollunLock();
                    }
                }
                break;
        }
        return true;
    }

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

    /**
     * 回調(diào)函數(shù)
     */
    public  interface ScrollListener{
       void onScrollunLock();
    }
    /**
     * 宮外不調(diào)用的方法
     */
    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;
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,523評論 25 708
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,252評論 4 61
  • 昨天,我們給學(xué)校成績優(yōu)秀一些的學(xué)生開了一個(gè)會議,目的是想他們可以樹立信心,把握好時(shí)間,高效學(xué)習(xí),進(jìn)而中考考出優(yōu)秀的...
    amazing2017閱讀 306評論 0 1