android 自定义View(滑动解锁)

1,实现效果 

【1】scrollTo & scrrllBy的特点

  •    实际上上面2个api滚动是的view绘制的内容,view本身并没有动

  •    scrollTo当x传入正数往做移动.传入负数往右移动. (偏移量x = 0-i)

  •    scrollBy 在上一次移动的基础上在移动X

2,实现逻辑

【1】创建一个类,继承view ,重写onMeasure 和 onDraw  

public class LockView extends View {



    public LockView(Context context, AttributeSet attrs) {

        super(context, attrs);

    }

    

    //在这个方法里面测量当前view的大小

    @Override

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    }

    //往当前的view上画内容

    @Override

    protected void onDraw(Canvas canvas) {

        //[1]由于背景我已经在布局中加上 所以只需要往当前的view上画 滑块就可以了

     

    }

【2】MainActivity 的布局中声明使用自定义view

  •   android:background="@drawable/lockviewbg" 设置了背景

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    tools:context=".MainActivity" >

    <com.xiaoshuai.lockview.LockView

        android:id="@+id/lockView1"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:background="@drawable/lockviewbg"

        android:layout_centerHorizontal="true"

        android:layout_alignParentBottom="true"

        />

</RelativeLayout>

【3】布局的绘制

  • LockView构造方法,BitmapFactory获取图片资源图片

        //[1]获取背景图片和 滑动块的图

        lockViewBg = BitmapFactory.decodeResource(getResources(), R.drawable.lockviewbg);

        slideBg = BitmapFactory.decodeResource(getResources(), R.drawable.switch_button);

  • 在onMeasure进行测量背景图片的大小

    //在这个方法里面测量当前view的大小

    @Override

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        setMeasuredDimension(lockViewBg.getWidth(), lockViewBg.getHeight());

    }
  • 在onDraw绘制滑块内容

    //往当前的view上画内容

    @Override

    protected void onDraw(Canvas canvas) {

        //[1]由于背景我已经在布局中加上 所以只需要往当前的view上画 滑块就可以了

        canvas.drawBitmap(slideBg, 0, 0, null);

    }

【4】滑动事件处理 

  • 重写onTouchEvent 方法

@Override

    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {

        case MotionEvent.ACTION_DOWN:

            break;

        case MotionEvent.ACTION_MOVE:

            break;

        case MotionEvent.ACTION_UP:

           

            break;

        }

        return true; //消费事件

    }

重写scrollTo方法让它符合中国人的思维

  •  

    /**滚动view的内容  自己重写这个方法让它符合中国人的思维**/

    public void startScrollView(int x){

        super.scrollTo(-x, 0);

    }

  • ACTION_DOWN中获取按下的坐标,ACTION_MOVE中获取移动的完成坐标,moveX - downX获取偏移量

  • 调用startScrollView进行滑动

@Override

    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {

        case MotionEvent.ACTION_DOWN:

            downX = event.getX();

            break;

        case MotionEvent.ACTION_MOVE:

            float moveX = event.getX();

            distaceX = (int) (moveX - downX);

            //[1]让view 的内容进行移动

            startScrollView(distaceX);

            break;

 构造方法中获取滑块可以移动的最大左边距

  •  

        //[2]算出滑动块像右移动最大值

        slideLeftMaxSize = lockViewBg.getWidth()-slideBg.getWidth();

  •  ACTION_MOVE中判断边界
    
                case MotionEvent.ACTION_MOVE:
    
                float moveX = event.getX();
    
                distaceX = (int) (moveX - downX);
    
                //[0]判断边界
    
                if (distaceX <=0 ) {
    
                    distaceX = 0;
    
                }else if (distaceX > slideLeftMaxSize ) {
    
                    distaceX = slideLeftMaxSize;
    
                }
    
                
    
                //[1]让view 的内容进行移动
    
                startScrollView(distaceX);
    
                
    
                break;
  • ACTION_UP 中判断如果抬起时不是移动的最大边距

      

     case MotionEvent.ACTION_UP:

            //[2]当手指抬起  如果

            if (distaceX < slideLeftMaxSize) {

                //[3]让view的内容回到0

                startScrollView(0);

                

            }else {

               如果最大值,实现对应逻辑

            }

            

            break;

【5】接口回调 

  • 在LockView创建监听方法  ,传入变量是一个接口的子类

  • 定义成员变量

    private OnLockViewListener mLockViewListener;

    public void setOnLockViewListener(OnLockViewListener l){

        this.mLockViewListener = l;

    }
  • 定义接口的子类,实现开锁

    

    /**

     * 定义监听器对象

     * @author jinxing

     *

     */

    public interface OnLockViewListener{

        //当滑动解锁的时候调用

        void onLock();

    }

  • 滑动到位置为最大值解锁

        case MotionEvent.ACTION_UP:

            //[2]当手指抬起  如果

            if (distaceX < slideLeftMaxSize) {

                //[3]让view的内容回到0

                startScrollView(0);

              

                

            }else {

                //[4]解锁

                if (mLockViewListener!=null) {

                    mLockViewListener.onLock();

                }

            }

            break;

MainActivity调用listener 监听

  •  
public class MainActivity extends Activity {

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        LockView lockView = (LockView) findViewById(R.id.lockView1);

        lockView.setOnLockViewListener(new OnLockViewListener() {

            

            @Override

            public void onLock() {

                

                finish();

            }

        });

    }

}

【6】平滑滚动的效果

  • 创建scroller 可以获取产生移动的数据效果 。 

  • 构造方法中创建Scroller对象

    //[3]创建一个类 scroller  可以收集数据 并且产生一个滚动动画的效果

        mScroller = new Scroller(getContext());

        

  • ACTION_UP的时候实现平滑滚动效果   

  • mScroller.startScroll(startX, 0, dx, 0, duration);只能产生数据

    

    case MotionEvent.ACTION_UP:

            //[2]当手指抬起  如果

            if (distaceX < slideLeftMaxSize) {

                //实现平滑滚动

                int startX = distaceX;

                int endX = 0;

                int dx = endX - startX;

                int duration = Math.abs(dx)*20;

                //下面这句api不可以让view滚动

                mScroller.startScroll(startX, 0, dx, 0, duration);

                invalidate(); //--->最终会调用到computeScroll这个方法

                

            }else {

                //[4]解锁

                if (mLockViewListener!=null) {

                    mLockViewListener.onLock();

                }

            }

            

            break;

  • invalidate会调用onDrwa 也会调用computeScroll方法

@Override

    public void computeScroll() {

        if (mScroller.computeScrollOffset()) {  //为false的时候停止回调

            //获取我们在上面模拟的数据

             int currX = mScroller.getCurrX();

             System.out.println("currX:"+currX);

             startScrollView(currX);

             invalidate();

         }

    }

3,全部代码

package com.xiaoshuai.www.lockview;





import android.content.Context;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.graphics.Canvas;

import android.util.AttributeSet;

import android.view.MotionEvent;

import android.view.View;

import android.widget.Scroller;





public class LockView extends View {





    private OnLockViewListener mLockViewListener;

    /**代表背景**/

    private Bitmap lockViewBg;

    /**代表滑块**/

    private Bitmap slideBg;

    /**按下的坐标**/

    private float downX;

    private int slideLeftMaxSize;

    private int distaceX;

    private Scroller mScroller;





    public LockView(Context context, AttributeSet attrs) {

        super(context, attrs);

        //[1]获取背景图片和 滑动块的图

        lockViewBg = BitmapFactory.decodeResource(getResources(), R.drawable.lockviewbg);

        slideBg = BitmapFactory.decodeResource(getResources(), R.drawable.switch_button);

        //[2]算出滑动块像右移动最大值

        slideLeftMaxSize = lockViewBg.getWidth()-slideBg.getWidth();





        //[3]创建一个类 scroller  可以收集数据 并且产生一个滚动动画的效果

        mScroller = new Scroller(getContext());









    }





    //在这个方法里面测量当前view的大小

    @Override

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        setMeasuredDimension(lockViewBg.getWidth(), lockViewBg.getHeight());





    }





    //往当前的view上画内容

    @Override

    protected void onDraw(Canvas canvas) {

        //[1]由于背景我已经在布局中加上 所以只需要往当前的view上画 滑块就可以了

        canvas.drawBitmap(slideBg, 0, 0, null);

    }





    @Override

    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN:

                downX = event.getX();

                break;





            case MotionEvent.ACTION_MOVE:

                float moveX = event.getX();

                distaceX = (int) (moveX - downX);

                //[0]判断边界

                if (distaceX <=0 ) {

                    distaceX = 0;

                }else if (distaceX > slideLeftMaxSize ) {

                    distaceX = slideLeftMaxSize;

                }





                //[1]让view 的内容进行移动

                startScrollView(distaceX);





                break;





            case MotionEvent.ACTION_UP:

                //[2]当手指抬起  如果

                if (distaceX < slideLeftMaxSize) {

                    //[3]让view的内容回到0

//          startScrollView(0);





                    //实现平滑滚动

                    int startX = distaceX;

                    int endX = 0;

                    int dx = endX - startX;

                    int duration = Math.abs(dx)*20;

                    //下面这句api不可以让view滚动

                    mScroller.startScroll(startX, 0, dx, 0, duration);

                    invalidate(); //--->最终会调用到computeScroll这个方法





                }else {

                    //[4]解锁

                    if (mLockViewListener!=null) {

                        mLockViewListener.onLock();

                    }









                }





                break;

        }





        return true; //消费事件

    }





    @Override

    public void computeScroll() {

        if (mScroller.computeScrollOffset()) {

            //获取我们在上面模拟的数据

            int currX = mScroller.getCurrX();

            System.out.println("currX:"+currX);

            startScrollView(currX);

            invalidate();





        }





    }









    /**滚动view的内容  自己重写这个方法让它符合中国人的思维**/

    public void startScrollView(int x){

        super.scrollTo(-x, 0);

    }





    public void setOnLockViewListener(OnLockViewListener l){

        this.mLockViewListener = l;

    }









    /**

     * 定义监听器对象

     * @author jinxing

     *

     */

    public interface OnLockViewListener{

        //当滑动解锁的时候调用

        void onLock();

    }





}





猜你喜欢

转载自blog.csdn.net/Cricket_7/article/details/88732816