Android九宫格解锁的实现

演示效果如下

主要代码如下

布局文件如下:

<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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <com.xuliugen.jiugongge.SudokuView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

</RelativeLayout>

从布局文件中可以看出需要自定义一个View用于绘制九宫格图案:

SudokuView.java

package com.xuliugen.jiugongge;

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;
import android.widget.Toast;

public class SudokuView extends View {

    private static final int DEFALUT_CELL_WIDTH = 60; //默认的cell宽度
    private static final int DEFALUT_CELL_STROKE_WIDTH = 2;
    private static final int DEFALUT_SPACE = DEFALUT_CELL_WIDTH >> 1;

    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 int mWidth;
    private int mHeight;

    private float mCurrentX;
    private float mCurrentY;
    private boolean mFinish = false;

    private StringBuffer mSbSelected = new StringBuffer(20);

    /**
     * 下边是三个构造方法:每一个构造方法中有一个初始化操作
     */
    public SudokuView(Context context) {
        super(context);
        init();
    }

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

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

    /**
     * 初始化操作
     */
    private void init() {
        mCellWidth = DensityUtil.dip2px(getContext(), DEFALUT_CELL_WIDTH);
        mCellRadius = DensityUtil.dip2px(getContext(), DEFALUT_CELL_WIDTH >> 1);
        mCellStrokeWidth = DensityUtil.dip2px(getContext(),
                DEFALUT_CELL_STROKE_WIDTH);
        mSpace = DensityUtil.dip2px(getContext(), DEFALUT_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 drawCell(Canvas canvas) {
        for (int i = 0; i < 9; i++) {
            canvas.drawCircle(mCells[i].getCenterX(), mCells[i].getCenterY(),
                    mCellRadius, mCells[i].isSelected() ? mPaintSelected
                            : mPaintNormal);
        }
    }

    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);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mWidth = getRealSize(widthMeasureSpec);
        mHeight = getRealSize(heightMeasureSpec);

        setMeasuredDimension(mWidth, mWidth);
    }

    private int getRealSize(int measureSpc) {
        int result;
        int mode = MeasureSpec.getMode(measureSpc);
        int size = MeasureSpec.getSize(measureSpc);

        if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.UNSPECIFIED) {
            result = mCellWidth * 3 + mSpace * 4;
        } else {
            result = size;
        }

        return result;
    }

    @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;
            Toast.makeText(getContext(), mSbSelected.toString(),
                    Toast.LENGTH_SHORT).show();
            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;
    }
}

MainActivity.java如下:

package com.xuliugen.jiugongge;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

另外还需要一个存放圆圈的Javabean

package com.xuliugen.jiugongge;

/**
 * 代表每一个九宫格圆圈的Javabean
 * @author xuliugenpc
 */
public class Cell {
    private float centerX;
    private float centerY;
    private boolean selected;

    public Cell(float x, float y) {
        centerX = x;
        centerY = y;
    }

    public float getCenterX() {
        return centerX;
    }

    public void setCenterX(float centerX) {
        this.centerX = centerX;
    }

    public float getCenterY() {
        return centerY;
    }

    public void setCenterY(float centerY) {
        this.centerY = centerY;
    }

    public boolean isSelected() {
        return selected;
    }

    public void setSelected(boolean selected) {
        this.selected = selected;
    }
}

像素转换的工具类:

package com.xuliugen.jiugongge;

import android.content.Context;
/**
 * 手机屏幕px转dp和dp转px工具类
 * @author xuliugenpc
 */
public class DensityUtil {

    private static float scale;

    /**
     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
     */
    public static int dip2px(Context context, float dpValue) {
        if (scale == 0) {
            scale = context.getResources().getDisplayMetrics().density;
        }
        return (int) (dpValue * scale + 0.5f);
    }

    /**
     * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
     */
    public static int px2dip(Context context, float pxValue) {
        if (scale == 0) {
            scale = context.getResources().getDisplayMetrics().density;
        }
        return (int) (pxValue / scale + 0.5f);
    }
}

全部资源都在这里了,不上传项目代码了哦。

时间: 2024-08-25 00:33:29

Android九宫格解锁的实现的相关文章

IOS仿Android九宫格解锁效果[转]

原理很简单,监听view中touch的一系列事件,当判定手指位置在某个按钮附近的时候则判断此按钮选中,并画出线. 效果图如下: 你可以在NineGridUnlockView.m文件中方法 touchesEnded:withEvent: 的最后添加自己的代码来决定画线完成后来做什么. (当前工程还没有加入委托,后续可能加上) 代码地址: https://github.com/lcwangchao/NineGridUnlocker IOS仿Android九宫格解锁效果[转]

App自动化(2)--Python&amp;Appium实现安卓手机九宫格解锁

九宫格作为常见的手势密码,我们在使用的时候,是从起点开始,按住不放,然后滑动手指,直到最后一个点松开手指,如果与设置的手势密码匹配,则解锁成功. 现在大多数九宫格作为一个元素存在,很难定位到每一个点. 解决思路有两个,一是用指针定位每一个点:二是先获取元素坐标位置,再获取元素大小,然后切割图片,分别计算出每个点的坐标: 本次笔记记录第一个解决思路: 目的:创建一个Unlock类,按顺序传入九宫格的解锁数字即可实现主屏幕解锁 模拟器:夜神 1.坐标定位到每个点 A.夜神模拟器开发者选项中开启指针位

【Android】自定义控件实现九宫格解锁

~转载请注明来源:http://blog.csdn.net/u013015161/article/details/46689011 介绍 这两天写了一个九宫格锁屏的控件,实现了九宫格锁屏的设置和解锁.该控件没有使用任何图片资源,显示的内容(包括点.圆.线等)全部由画笔绘制,所以可以自由复用. 使用效果图: 实现 先上代码吧. 自定义九宫格控件:LocusPassView package com.example.locusexample; import java.util.ArrayList; i

Android 九宫格

如下代码直接复制到项目就可以运行使用了.我们都知道,android的九宫格可以用GridView控件实现,这里首先定义一个 gridview.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="ma

Android九宫格界面实现点击每个格点击跳转界面

刚开始有个任务就是做一个九宫格界面,后来有个任务就是实现点击每个格并跳转界面实现每个格的功能.下面我就介绍一下我是如何实现该功能的 首先写一下我的想法是: 登录成功后显示一个九宫格界面,每个九宫格的每一个都是一个功能模块,当点击每个模块时,就会跳转到相应的界面并实现该模块所具备的功能. 下面是以"综合实践管理系统"这个格来实现的,当我们点击该按钮时,他就会跳转到"学生综合实践模块积分申请表"这个界面然后我们通过下拉菜单选择自己想要申请的项目.然后点击"下一

Android手势解锁

给大家介绍一个很好用的第三方手势解锁控件ShapleLocker, 废话不多先上效果图: 可自己根据UI需求替换图标: 圆圈, 小箭头等等.. github地址: http://panespanes.github.io/ShapeLocker/ 用法很简单, 首先在gradle中添加依赖: 在项目(project, 不是module)的build.gradle中, respositories的最后加上一行引用jitpack的maven仓库地址 allprojects { repositories

Android 九宫格密码锁进入程序

设置九宫格密码锁进入程序,设置,重置,取消等,安卓巴士地址http://www.apkbus.com/forum.php?mod=viewthread&tid=182620&extra= 源码运行截图: 代码:这里

android 九宫格(16宫格)控件

public class NineRectView extends ViewGroup { private Context ctx; private int wSize,hSize,row,column,count,childWidth,childHeight,parent_padding_top_bottom;//布局方式按照默认wSize=Hsize //间距都相同 private int childMargin =4; private int parent_padding; private

android项目大全,总有你所需的

注:打开请贴网址.有些直接通过链接打开的不对. 1.相对布局实例 http://kukuqiu.iteye.com/blog/1018396 2.Log图文具体解释(Log.v,Log.d,Log.i,Log.w,Log.e)(转) http://www.cnblogs.com/menglin2010/archive/2011/12/20/2294338.html3. getResources()方法的作用和要点http://blog.sina.com.cn/s/blog_9f4bc8e3010