自定義滑動解鎖View

先寫出自定義View界面

代碼如下:先創(chuàng)建一個View繼承View射亏,然后重寫測量方法去測量出要顯示的真是高度,再重寫繪制方法,去把這個按鈕繪制在什么位置拌夏。然后就是為我們后續(xù)的觸摸事件做準備推穷,重寫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 的構(gòu)造方法中,我們?nèi)コ跏蓟粋€畫筆馒铃,初始化背景的 長 寬蟹腾。在onTouch()中,處理觸摸事件区宇,在手指按下的時候娃殖,讓滑塊中間位置移動到觸摸點:注意,這個ScrollTo方法议谷,往右邊移動是減去一個數(shù)炉爆,可以想成,水調(diào)用這個Scroll方法卧晓,是this ,當前自定義View芬首。你簡單記憶成這個移動是移動他的爹,滑塊向右移動逼裆,你就當成是滑塊不動衩辟,他爹應(yīng)該是往那邊移動才是我們想要的結(jié)果,他爹是往左邊移動才行波附。我們的左邊是右邊正艺晴,往左了肯定是負。效果如下:

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

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

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

 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;

注意上面的滑動越界問題仅财,我是通過手指的位置判斷的狈究,當然你可以通過一個增加量來判斷是否滿足條件,如果滿足不滿足條件直接把偏移量置零或者最大 盏求。注意上面的判斷有個細節(jié)抖锥,我使用的是getMeasuredWidth( ) 來處理,并不是用的mWidth1,如果你是用后者碎罚,你會發(fā)現(xiàn)這個值非常大磅废。會越界。這里的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.創(chuàng)建Scroller對象
2.調(diào)用startScroll 方法去滾動 账蓉,配置滾動信息
3.出發(fā)重新繪制調(diào)用 invalidate();
4.計算滾動的偏移量。重寫computerScroll( ) 逾一,根據(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();
                //當我手指觸摸到滑塊時候怨规,滑塊過來要移動這個點減去滑塊一般的長度  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:觸發(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)系作者
  • 序言:七十年代末陌宿,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子波丰,更是在濱河造成了極大的恐慌壳坪,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掰烟,死亡現(xiàn)場離奇詭異爽蝴,居然都是意外死亡,警方通過查閱死者的電腦和手機纫骑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進店門蝎亚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人先馆,你說我怎么就攤上這事发框。” “怎么了煤墙?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵梅惯,是天一觀的道長。 經(jīng)常有香客問我仿野,道長铣减,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任脚作,我火速辦了婚禮徙歼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己魄梯,他們只是感情好桨螺,可當我...
    茶點故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著酿秸,像睡著了一般灭翔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上辣苏,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天肝箱,我揣著相機與錄音,去河邊找鬼稀蟋。 笑死煌张,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的退客。 我是一名探鬼主播骏融,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼萌狂!你這毒婦竟也來了档玻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤茫藏,失蹤者是張志新(化名)和其女友劉穎误趴,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體务傲,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡凉当,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了售葡。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纤怒。...
    茶點故事閱讀 40,852評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖天通,靈堂內(nèi)的尸體忽然破棺而出泊窘,到底是詐尸還是另有隱情,我是刑警寧澤像寒,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布烘豹,位于F島的核電站,受9級特大地震影響诺祸,放射性物質(zhì)發(fā)生泄漏携悯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一筷笨、第九天 我趴在偏房一處隱蔽的房頂上張望憔鬼。 院中可真熱鬧龟劲,春花似錦、人聲如沸轴或。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽照雁。三九已至蚕愤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間饺蚊,已是汗流浹背萍诱。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留污呼,地道東北人裕坊。 一個月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像燕酷,于是被迫代替她去往敵國和親籍凝。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,851評論 2 361

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

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