lananrun

lananrun

0个粉丝

45

问答

0

专栏

1

资料

lananrun  发布于  2015-11-05 17:32:17
采纳率 0%
45个问答
4081

渤海银行九宫格锁屏示例

本帖最后由 Heguming 于 2015-11-5 22:07 编辑

        最近论坛好像很火啊,看到有好多的谭友在这里分享代码,感谢谭主,为大家提供了这么好的一个交流的机会。

        好,言归正传,前些天玩的一个九宫格锁屏实例,献给大家。

       MainActivity代码较为简单,主要实现向布局中添加九宫格视图,同时根据保存的数据,判断此为第几次输入锁屏密码,并执行相应操作。

       [code]
package cn.com.unfind.ges;

import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Window;
import android.widget.LinearLayout;
import android.widget.TextView;
import cn.com.unfind.ges.view.NinePointLineView;

/**
* 作用:测试九宫格手势密码 作者:Heguming 时间:2015年11月02日 09:37:54
* */
public class MainActivity extends Activity {

        private LinearLayout nine_con;// 九宫格容器

        NinePointLineView nv;// 九宫格View

        TextView showInfo;

        boolean isSetFirst = false;

        @Override
        public boolean onKeyDown(int keyCode, KeyEvent event) {
                // TODO Auto-generated method stub

                if (keyCode == KeyEvent.KEYCODE_BACK) {

                        SharedPreferences shareDate = getSharedPreferences("GUE_PWD", 0);

                        shareDate.edit().putBoolean("IS_SET", false).commit();

                }

                return super.onKeyDown(keyCode, event);
        }

        @Override
        protected void onCreate(Bundle savedInstanceState) {

                super.onCreate(savedInstanceState);

                this.requestWindowFeature(Window.FEATURE_NO_TITLE);// 设置标题不显示

                setContentView(R.layout.activity_main);

                initWidget();

                getSetPwd();

        }

        private void initWidget() {

                nv = new NinePointLineView(MainActivity.this);

                nine_con = (LinearLayout) findViewById(R.id.nine_con);

                nine_con.addView(nv);

                showInfo = (TextView) findViewById(R.id.show_set_info);

        }

        /**
         * 作用:获取现在密码的设置步骤 作者:Heguming 时间:2015年11月02日 14:20:36
         * */
        public void getSetPwd() {

                SharedPreferences shareDate = getSharedPreferences("GUE_PWD", 0);

                isSetFirst = shareDate.getBoolean("IS_SET", false);

                if (!isSetFirst) {

                        showInfo.setText("请设置手势密码");

                        shareDate.edit().clear().commit();

                } else {

                        showInfo.setText("请再次确认手势密码");
                }

        }

}
        [/code]
        
        此处,需要简单介绍一下这三种存储方式的应用场合及使用效率:SharedPreferences、File、SQLite。
   
       一般来说,SharedPreferences与SQLite适合存储需要频繁操作的数据,这两者存储数据类型简单,其构成元素均为基本的int、boolean、String等类型,优点是操作速度快,便于多次读写。

       相对于SharedPreferences 与SQLite ,File则更适合操作不频繁的数据,其存储数据类型较为复杂,这也造就了它读写速度较慢的缺点。

       而SQLite兼顾简单操作的功能,比如排序、查询等,这是其他两种存储方式不能比拟的,但也因此导致SQLite使用方法较为复杂,需要经过建库、建表等多个步骤,还需要定期进行更新与维护。

       最后一个不同是,SQLite与File适合存储大数据量的操作,SharedPreferences则更适合存储小数据量的操作。


       下面,就是关键代码了---NinePointLineView,此部分代码通过覆写onMeasure方法与onLayout方法,实现将九宫格视图添加至当前View,同时通过覆写onTouchEvent方法与onDraw方法监听屏幕输入,并对绘制视图进行实时更新。

       [code]
package cn.com.unfind.ges.view;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Cap;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
import cn.com.unfind.ges.MainActivity;
import cn.com.unfind.ges.R;

/**
* 作用:手势密码的九宫格 作者:ufnind 时间:2015年11月03日 12:34:52
* */
public class NinePointLineView extends View {

        Paint linePaint = new Paint();

        Paint whiteLinePaint = new Paint();

        Bitmap defaultBitmap = BitmapFactory.decodeResource(getResources(),
                        R.drawable.lock);

        int defaultBitmapRadius = defaultBitmap.getWidth() / 2;

        Bitmap selectedBitmap = BitmapFactory.decodeResource(getResources(),
                        R.drawable.indicator_lock_area);

        int selectedBitmapDiameter = selectedBitmap.getWidth();

        int selectedBitmapRadius = selectedBitmapDiameter / 2;

        PointInfo[] points = new PointInfo[9];

        PointInfo startPoint = null;

        int width, height;

        int moveX, moveY;

        boolean isUp = false;

        Context cxt;

        StringBuffer lockString = new StringBuffer();

        public NinePointLineView(Context context) {

                super(context);

                cxt = context;

                initPaint();
        }

        public NinePointLineView(Context context, AttributeSet attrs) {

                super(context, attrs);

                initPaint();
        }

        private void initPaint() {

                initLinePaint(linePaint);

                initWhiteLinePaint(whiteLinePaint);

        }

        /**
         * @param paint
         */
        private void initLinePaint(Paint paint) {

                paint.setColor(Color.GRAY);

                paint.setStrokeWidth(30);// 设置两个点之间的线的背景的宽度

                paint.setAntiAlias(true);

                paint.setStrokeCap(Cap.ROUND);

        }

        /**
         * @param paint
         */
        private void initWhiteLinePaint(Paint paint) {

                paint.setColor(Color.WHITE);

                paint.setStrokeWidth(20);// 设置两个点之间的线的宽度

                paint.setAntiAlias(true);

                paint.setStrokeCap(Cap.ROUND);

        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

                width = getWidth();

                height = getHeight();

                if (width != 0 && height != 0) {

                        initPoints(points);

                }

                super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        }

        private void initPoints(PointInfo[] points) {

                int len = points.length;

                int seletedSpacing = (width - selectedBitmapDiameter * 3) / 4;

                int seletedX = seletedSpacing;

                int seletedY = height - width + seletedSpacing;

                int defaultX = seletedX + selectedBitmapRadius - defaultBitmapRadius;

                int defaultY = seletedY + selectedBitmapRadius - defaultBitmapRadius;

                for (int i = 0; i < len; i++) {

                        if (i == 3 || i == 6) {

                                seletedX = seletedSpacing;

                                seletedY += selectedBitmapDiameter + seletedSpacing;

                                defaultX = seletedX + selectedBitmapRadius
                                                - defaultBitmapRadius;

                                defaultY += selectedBitmapDiameter + seletedSpacing;

                        }

                        points = new PointInfo(i, defaultX, defaultY, seletedX, seletedY);

                        seletedX += selectedBitmapDiameter + seletedSpacing;

                        defaultX += selectedBitmapDiameter + seletedSpacing;

                }
        }

        @Override
        protected void onLayout(boolean changed, int left, int top, int right,
                        int bottom) {

                super.onLayout(changed, left, top, right, bottom);

        }

        @Override
        protected void onDraw(Canvas canvas) {

                drawNinePoint(canvas);

                super.onDraw(canvas);
        }

        @SuppressLint("ClickableViewAccessibility")
        @Override
        public boolean onTouchEvent(MotionEvent event) {

                boolean flag = true;

                if (isUp) {

                        finishDraw();

                        flag = false;

                } else {
                        handlingEvent(event);

                        flag = true;

                }
                return flag;
        }

        private void handlingEvent(MotionEvent event) {

                switch (event.getAction()) {

                case MotionEvent.ACTION_MOVE:

                        moveX = (int) event.getX();

                        moveY = (int) event.getY();

                        for (PointInfo temp : points) {

                                if (temp.isInMyPlace(moveX, moveY)
                                                && temp.isSelected() == false) {

                                        temp.setSelected(true);

                                        int len = lockString.length();

                                        if (len != 0) {

                                                int preId = lockString.charAt(len - 1) - 48;

                                                points[preId].setNextId(temp.getId());

                                        }

                                        lockString.append(temp.getId());

                                        break;
                                }
                        }

                        invalidate(0, height - width, width, height);

                        break;

                case MotionEvent.ACTION_DOWN:

                        int downX = (int) event.getX();

                        int downY = (int) event.getY();

                        for (PointInfo temp : points) {

                                if (temp != null) {
                                        if (temp.isInMyPlace(downX, downY)) {

                                                temp.setSelected(true);

                                                startPoint = temp;

                                                lockString.append(temp.getId());

                                                break;
                                        }
                                }
                        }

                        invalidate(0, height - width, width, height);

                        break;

                case MotionEvent.ACTION_UP:

                        isUp = true;

                        invalidate();

                        savePwd();

                        break;

                default:
                        break;
                }
        }

        private void finishDraw() {

                for (PointInfo temp : points) {

                        temp.setSelected(false);

                        temp.setNextId(temp.getId());

                }

                lockString.delete(0, lockString.length());

                isUp = false;

                invalidate();
        }

        /**
         *
         * @param canvas
         */
        private void drawNinePoint(Canvas canvas) {

                if (startPoint != null) {

                        drawEachLine(canvas, startPoint);

                }

                for (PointInfo pointInfo : points) {

                        if (pointInfo != null) {

                                if (pointInfo.isSelected()) {

                                        canvas.drawBitmap(selectedBitmap, pointInfo.getSeletedX(),
                                                        pointInfo.getSeletedY(), null);

                                }

                                canvas.drawBitmap(defaultBitmap, pointInfo.getDefaultX(),
                                                pointInfo.getDefaultY(), null);

                        }
                }

        }

        /**
         * @param canvas
         * @param point
         */
        private void drawEachLine(Canvas canvas, PointInfo point) {
                if (point.hasNextId()) {
                        int n = point.getNextId();
                        drawLine(canvas, point.getCenterX(), point.getCenterY(),
                                        points[n].getCenterX(), points[n].getCenterY());
                        drawEachLine(canvas, points[n]);
                }
        }

        /**
         *
         * @param canvas
         * @param startX
         * @param startY
         * @param stopX
         * @param stopY
         */
        private void drawLine(Canvas canvas, float startX, float startY,
                        float stopX, float stopY) {

                canvas.drawLine(startX, startY, stopX, stopY, linePaint);

                canvas.drawLine(startX, startY, stopX, stopY, whiteLinePaint);

        }

        /**
         * @author zkwlx
         *
         */
        private class PointInfo {

                private int id;

                private int nextId;

                private boolean selected;

                private int defaultX;

                private int defaultY;

                private int seletedX;

                private int seletedY;

                public PointInfo(int id, int defaultX, int defaultY, int seletedX,
                                int seletedY) {
                        this.id = id;
                        this.nextId = id;
                        this.defaultX = defaultX;
                        this.defaultY = defaultY;
                        this.seletedX = seletedX;
                        this.seletedY = seletedY;
                }

                public boolean isSelected() {
                        return selected;
                }

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

                public int getId() {
                        return id;
                }

                public int getDefaultX() {
                        return defaultX;
                }

                public int getDefaultY() {
                        return defaultY;
                }

                public int getSeletedX() {
                        return seletedX;
                }

                public int getSeletedY() {
                        return seletedY;
                }

                public int getCenterX() {
                        return seletedX + selectedBitmapRadius;
                }

                public int getCenterY() {
                        return seletedY + selectedBitmapRadius;
                }

                public boolean hasNextId() {
                        return nextId != id;
                }

                public int getNextId() {
                        return nextId;
                }

                public void setNextId(int nextId) {
                        this.nextId = nextId;
                }

                /**
                 * @param x
                 * @param y
                 */
                public boolean isInMyPlace(int x, int y) {
                        boolean inX = x > seletedX
                                        && x < (seletedX + selectedBitmapDiameter);
                        boolean inY = y > seletedY
                                        && y < (seletedY + selectedBitmapDiameter);

                        return (inX && inY);
                }

        }

        public String getPwd() {// 获取本次的密码

                return lockString.toString();

        }

        /**
         * 作用:保存密码并且判断界面的跳转 作者:Heguming 时间:2015年11月02日 14:47:47
         * */
        public void savePwd() {

                Intent intent = new Intent();

                SharedPreferences shareDate = cxt.getSharedPreferences("GUE_PWD", 0);

                boolean isSetFirst = shareDate.getBoolean("IS_SET", false);

                if (isSetFirst) {// 如果第一次已经设置密码,验证第二次和第一次是否一致

                        String pwd = this.getPwd();

                        String first_pwd = shareDate.getString("FIRST_PWD", "NO HAVE PWD");

                        if (pwd.equals(first_pwd)) {// 第二次密码和第一次密码一样 设置成功

                                shareDate.edit().clear().commit();

                                intent.setClass(cxt, MainActivity.class);

                                Toast.makeText(cxt, "您输入的密码为:" + pwd, Toast.LENGTH_SHORT)
                                                .show();

                        } else {// 第二次输入的密码和第一次输入的密码不一致

                                Toast.makeText(cxt, "和第一次输入手势密码不一致,重新输入", Toast.LENGTH_SHORT)
                                                .show();

                                intent.setClass(cxt, MainActivity.class);

                        }

                        shareDate.edit().putBoolean("IS_SET", false).commit();

                } else {// 第一次设置手势密码

                        shareDate.edit().clear().commit();

                        shareDate.edit().putString("FIRST_PWD", this.getPwd()).commit();

                        shareDate.edit().putBoolean("IS_SET", true).commit();

                        intent.setClass(cxt, MainActivity.class);

                }

                cxt.startActivity(intent);

                ((Activity) cxt).finish();

        }

}
       [/code]

        以下,对该代码进行简要分析。

        首先,需要说明一下PointInfo类,该类相当于MVC模式(MVC:Model/模型-View/视图-Controller/控制器)中的M,即模型,其内部包含五个构造参数:id,defaultX,defaultY,seletedX,seletedY。

        id:九宫格中该点的序列号:0~8
      
        defaultX:未选中状态下该点的横坐标

        defaultY:未选中状态下该点的纵坐标
   
        seletedX:选中状态下该点的横坐标

        seletedY:选中状态下该点的纵坐标

        同时,该类还包含了两个局部变量:nextId---下个被选点的序列号,selected---该点是否被选中,以及一个普通方法:isInMyPlace(),用于判断该点的选中范围,即什么范围内,可认为该点被选中。

        接下来,对NinePointLineView类中的变量作下说明:

        linePaint、whiteLinePaint---画笔对象,用于绘制连接线。

        defaultBitmap、defaultBitmapRadius---Bitmap对象,分别为默认状态及选中状态下九宫格中各点的图片。

        defaultBitmapRadius、selectedBitmapDiameter、selectedBitmapRadius:分别为九宫格中各点默认状态下的半径、选中状态下的直径及选中状态下的半径。

        很明显,defaultBitmapRadius = defaultBitmap.getWidth() / 2, selectedBitmapDiameter = selectedBitmap.getWidth(), selectedBitmapRadius = selectedBitmapDiameter / 2。

        points---PointInfo对象点的集合。

        startPoint---开始绘制时的起始点。

        width、height---九宫格视图的宽度及高度。

        moveX、moveY:  onTouchEvent事件中,经过移动后的该点的横坐标、纵坐标。

        isUp: onTouchEvent事件中,用于判断触点是否离开屏幕。
  
        lockString:将输入密码转换为序列号集合的字符串。     

        cxt:上下文对象。

        下面,描述下该类的工作流程,并简要叙述下各个方法的功能。

        首先,在构造方法中,引入上下文对象并赋值,同时通过initPaint()方法初始化画笔。

        initPaint()方法中主要执行两个功能,其一,通过initLinePaint()方法,设置两个点之间连线背景的相关属性,即连线中的灰色背景的属性。其二,通过initWhiteLinePaint()方法,设置两个点之间连线前景的相关属性,即连线中白色前景的属性。二者的画笔属性主要包括颜色(Paint.setColor(Color.GRAY))、宽度(Paint.setStrokeWidth(30))、锯齿效果(Paint.setAntiAlias(true))、笔刷样式(Paint.setStrokeCap(Cap.ROUND))在内的四个部分。

        然后,通过onMeasure()方法,计算该九宫格视图所占的宽度及高度,并赋值给width、height,同时通过initPoints(PointInfo[] points)方法,初始化points集合中的各点。

        此处,需要详细说明下initPoints(PointInfo[] points)方法:

        该方法需要将九个点分别转换为PointInfo对象,之前讲过,PointInfo对象需要5个构造参数---id、defaultX、defaultY、seletedX、seletedY,故而需要计算出每个点的相关属性。

        第一步,计算选中状态下每两个点之间的间隔---seletedSpacing = (width - selectedBitmapDiameter * 3) / 4,即: (九宫格视图宽度 - 选中状态下各点的直径 * 3)/4。

        第二步,循环计算在默认状态与选中状态下,各点的横坐标与纵坐标: seletedX、seletedY、defaultX、defaultY。

        很明显,seletedX = id % 3 * selectedBitmapDiameter + (id % 3 + 1) * seletedSpacing
           
                   defaultX =  id % 3 * selectedBitmapDiameter + (id % 3 + 1) * seletedSpacing + selectedBitmapRadius - defaultBitmapRadius

                   seletedY =  id / 3 * selectedBitmapDiameter + (id / 3 + 1) * seletedSpacing

                   defaultY =  id % 3 * selectedBitmapDiameter + (id / 3 + 1) * seletedSpacing + selectedBitmapRadius - defaultBitmapRadius

        最后一步,分别实例化PointInfo对象,并将其添加至points集合。

        接下来,通过onLayout()方法确定布局位置,该方法内部直接调用父类onLayout()方法即可。

        然后,通过onTouchEvent()监听屏幕输入,然后通过onDraw()方法对每次屏幕输入进行视图绘制。

        在onTouchEvent()中,判断触点是否离开屏幕,即判断isUp是否为true。如果为true,即通过finishDraw()方法结束视图绘制,同时将flag置为false,否则,通过handlingEvent()方法对屏幕输入事件进行同时将flag置为true,通过返回flag标志位,系统可以判断是否对继续相应下一Touch事件(若返回为true,则继续执行onTouchEvent,否则终止执行,很明显,当isUp为true时,即触点离开屏幕时,终止onTouchEvent的执行)。

        对于finishDraw()方法,没什么需要介绍的,就是终止视图的绘制, 将points中所有点置位,即 setSelected(false)(设置选中状态为false)、setNextId(temp.getId())(设置下一选中点为它本身),同时刷新视图。

        对于handlingEvent()方法,其主要功能是根据event.getAction()方法获取MotionEvent常量,并根据常量值分别对event进行处理:

        MotionEvent.ACTION_DOWN---获取当前触点坐标,通过PointInfo.isInMyPlace()方法,根据坐标值,判断各点状态范围,即是否处于被选中状态范围之内,如果是,则设置该点为选中状态,同时赋值给startPoint,并将该点序列号以字符形式赋值给lockString,最后刷新视图。

        MotionEvent.ACTION_MOVE---获取当前触点坐标,通过PointInfo.isInMyPlace()方法,根据坐标值,判断各点状态范围,即是否处于被选中状态范围之内,如果是,还需判断该点是否已被选中,即强制同一点不可被重复选中。如果未曾选中过,则设置该点为选中状态,并将该点序列号以字符形式追加给lockString,同时设置上一选中点的nextId属性: points[preId].setNextId(temp.getId()), 即为该点的Id,最后刷新视图。

       MotionEvent.ACTION_UP---通过savePwd()方法保存九宫格密码:lockString,同时刷新视图。

       对于onDraw()方法,它在每次视图改变时,都会进行重新绘制。在该方法内部,主要通过drawNinePoint()方法对九宫格每一点进行绘制。

       在drawNinePoint()方法中,先判断startPoint 是否为空,即是否开始绘制锁屏图案。如果非空,通过drawEachLine()方法,根据每个点的Id属性与nextId属性,分别绘制这两个点之间的连线,即白色前景连线与灰色背景连线。后根据各个点的状态,绘制选中状态下的Bitmap,或是非选中状态下的Bitmap,即canvas.drawBitmap(selectedBitmap, pointInfo.getSeletedX(),pointInfo.getSeletedY(), null)、canvas.drawBitmap(defaultBitmap, pointInfo.getDefaultX(),pointInfo.getDefaultY(), null)( 此处Canvas为画布对象,读者可自行摆渡 )。

      对于savePwd()方法,该方法主要用于密码保存及密码验证。通过isSetFirst变量,判断此为第几次输入锁屏密码。如果为第一次,则保存该密码,同时启动MainActivity,再次输入锁屏密码。如果为第二次,则判断两次密码输入是否一致,如果一致,则保存该密码为最终密码,否则,提示用户两次密码输入不同,请重新输入。

       至此,所有代码分析完毕,效果如下:

      
  
      

       最后,附上程序代码(见附件)  :)

      原创,转载请注明出处

      附件:GesturePwd.rar
易百纳技术社区文件: GesturePwd.rar
下载
我来回答
回答1个
时间排序
认可量排序

david

33个粉丝

368

问答

253

专栏

229

资料

david 2015-11-10 19:54:14
认可0
这个必须顶。。
或将文件直接拖到这里
悬赏:
E币
网盘
* 网盘链接:
* 提取码:
悬赏:
E币

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
+ 添加网盘链接/附件

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

易百纳技术社区