Android 自定义九宫格手势锁

预览效果图如下:

这里写图片描述

主要的方法是重写View.onTouchEvent( MotionEvent event ) , 常用的三个操作:ACTION_DOWN 手指触摸屏幕 ; ACTION_UP 手指离开屏幕;
ACTION_MOVE手指在屏幕滑动。
如果该方法返回true ,表示该事件已经被View处理,不再向上层的View或Activity传递 ; 如果返回false, 表示事件未处理,继续传递。

具体代码如下:

package com.ninegrid;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by Administrator on 2017/6/24.
 */

public class SuduView extends View {

    //定义默认常量
    private static final int DEFAULT_CELL_WIDTH = 200 ;
    private static final int DEFAULT_CELL_STROKE_WIDTH = 10 ;
    private static final int DEFAULT_SPACE = 100 ;

    //九宫格数组
    private Cell mCells[] = new Cell[9] ;

    //直径
    private int mCellWidth;
    //半径
    private int mCellRadius;
    //边框宽度
    private int mCellStrokeWidth;
    //空白部分
    private int mSpace ;

    //定义画笔
    private Paint mPaintNormal ;
    private Paint mPaintSelected ;

    private float mCurrentX ;
    private float mCurrentY ;

    //判断是否结束的标识
    private boolean mFinish = false ;


    private StringBuffer mSbSelected = new StringBuffer(20);
    public SuduView(Context context) {
        super(context);
        init();
    }

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

    public SuduView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init(){
        //初始化画笔
        mCellWidth = DEFAULT_CELL_WIDTH ;
        mCellRadius = DEFAULT_CELL_WIDTH >> 1 ;
        mCellStrokeWidth = DEFAULT_CELL_STROKE_WIDTH ;
        mSpace = DEFAULT_SPACE ;

        mPaintNormal = new Paint();
        mPaintNormal.setColor(Color.WHITE);
        mPaintNormal.setStrokeWidth(mCellStrokeWidth);
        mPaintNormal.setStyle(Paint.Style.STROKE);
        mPaintNormal.setAntiAlias(true);

        mPaintSelected = new Paint();
        mPaintSelected.setColor(Color.CYAN);
        mPaintSelected.setStrokeWidth(mCellStrokeWidth);
        mPaintSelected.setStyle(Paint.Style.STROKE);
        mPaintSelected.setAntiAlias(true);

        Cell cell ;
        float x;
        float y;
        //计算每个格子的坐标
        for( int i = 0 ; i < 9 ; i ++ ){
            x = mSpace * ( i%3 + 1 ) + mCellRadius + mCellWidth * ( i%3 ) ;
            y = mSpace * ( i/3 + 1 ) + mCellRadius + mCellWidth * ( i/3 ) ;

            cell = new Cell(x , y);
            mCells[i] = cell ;
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawCell(canvas);
        drawLine(canvas);
    }

    //绘制连接线
    private void drawLine( Canvas canvas ){
        if("".equals(mSbSelected.toString())){
            return;
        }
        String[] selectedIndexs = mSbSelected.toString().split(",");
        Cell cell = mCells[Integer.valueOf(selectedIndexs[0])];
        Cell nextCell ;

        //绘制每两个格子中心点之间的连接线
        if( selectedIndexs.length > 1) {
            for (int i = 1; i < selectedIndexs.length; i++) {
                nextCell = mCells[Integer.valueOf(selectedIndexs[i])];
                canvas.drawLine(cell.getCenterX(), cell.getCenterY(), nextCell.getCenterX(), nextCell.getCenterY(), mPaintSelected);

                cell = nextCell;
            }
        }
        //绘制格子到其他空白位置的连接线
        if( !mFinish ) {
            canvas.drawLine(cell.getCenterX(), cell.getCenterY(), mCurrentX, mCurrentY, mPaintSelected);
        }

    }

    private void drawCell( Canvas canvas ){
        for ( int i = 0 ; i < 9 ; i ++ ){
            canvas.drawCircle(mCells[i].getCenterX(), mCells[i].getCenterY() , mCellRadius ,
                    mCells[i].isSelected() ? mPaintSelected : mPaintNormal );
        }

    }

    //处理点击事件
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch ( event.getAction()){
            case MotionEvent.ACTION_DOWN:
                //如果手指已经松开,则所有格子变为初始状态
                if( mFinish ){
                    for ( int i = 0 ; i < 9 ; i ++ ){
                        mCells[i].setSelected(false);
                    }
                    mFinish = false ;
                    mSbSelected.delete(0,mSbSelected.length());
                    invalidate();
                    return false;
                }
                handleDownEvent(event);
                break;
            //松开则结束
            case MotionEvent.ACTION_UP:
                mFinish = true ;
                break;
            case MotionEvent.ACTION_MOVE:
                handleMoveEvent(event);
                break;
        }

        //表示已处理,不向上传递
        return true ;
    }

    //处理手指移动的事件
    private void handleMoveEvent( MotionEvent event ){
        int index = findCellIndex(event.getX(),event.getY());
        if( index != -1 ){
            mCells[index].setSelected(true);
            mSbSelected.append(index).append(",");

        }
        invalidate();
        mCurrentX = event.getX();
        mCurrentY = event.getY();
    }

    //处理手指按下的事件
    private void handleDownEvent( MotionEvent event){
        int index = findCellIndex(event.getX(),event.getY());
        if( index != -1 ){
            mCells[index].setSelected(true);
            mSbSelected.append(index).append(",");
            invalidate();
        }
        mCurrentX = event.getX();
        mCurrentY = event.getY();
    }

    //根据坐标判断点击的哪个格子
    private int findCellIndex( float x , float y){
        float cellX ;
        float cellY ;
        int result = -1 ;

        for( int i = 0 ; i < 9 ; i ++ ){
            if( mCells[i].isSelected()){
                continue;
            }

            //获取每个格子的坐标
            cellX = mCells[i].getCenterX();
            cellY = mCells[i].getCenterY();

            //计算按下的点到每个格子的距离
            float tempX = cellX - x ;
            float tempY = cellY - y ;
            float distance  = (float) Math.sqrt(tempX * tempX + tempY * tempY);

            //如果点击的位置在某个格子的圆内
            if( distance < mCellRadius  ){
                result = i ;
                break;
            }
        }
        //返回该格子的位置
        return result ;

    }


}

最后在布局文件中引用该View即可,若想实现更高的定制性,可以仿照上一篇文章重写View的onMearsure方法并增加自定义属性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值