Android之九宫格解锁的实现

来源:互联网 发布:滨州电死外星人 知乎 编辑:程序博客网 时间:2024/04/30 09:31

九宫格解锁在Android中应用的很广泛,也是Android特有的一种解锁方式,其实实现起来也并不是很复杂,下面我就根据系统源码LockPatternView,移植出来的一个更加简单小巧九宫格解锁的例子,和大家一起学习一下。图片资源来自"支付宝钱包",先看看效果图:

源码下载地址:http://download.csdn.net/detail/weidi1989/5374787

                                                   


下面是最重要的那个LocusPassWordView:

[java] view plaincopy
  1. /** 
  2.  *  
  3.  * 九宫格解锁 
  4.  *  
  5.  * @author way 
  6.  *  
  7.  */  
  8. public class LocusPassWordView extends View {  
  9.     private float w = 0;  
  10.     private float h = 0;  
  11.   
  12.     //  
  13.     private boolean isCache = false;  
  14.     //  
  15.     private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
  16.   
  17.     //  
  18.     private Point[][] mPoints = new Point[3][3];  
  19.     // 圆的半径  
  20.     private float r = 0;  
  21.     // 选中的点  
  22.     private List<Point> sPoints = new ArrayList<Point>();  
  23.     private boolean checking = false;  
  24.     private Bitmap locus_round_original;// 圆点初始状态时的图片  
  25.     private Bitmap locus_round_click;// 圆点点击时的图片  
  26.     private Bitmap locus_round_click_error;// 出错时圆点的图片  
  27.     private Bitmap locus_line;// 正常状态下线的图片  
  28.     private Bitmap locus_line_semicircle;  
  29.     private Bitmap locus_line_semicircle_error;  
  30.     private Bitmap locus_arrow;// 线的移动方向  
  31.     private Bitmap locus_line_error;// 错误状态下的线的图片  
  32.     private long CLEAR_TIME = 0;// 清除痕迹的时间  
  33.     private int passwordMinLength = 5;// 密码最小长度  
  34.     private boolean isTouch = true// 是否可操作  
  35.     private Matrix mMatrix = new Matrix();  
  36.     private int lineAlpha = 50;// 连线的透明度  
  37.   
  38.     public LocusPassWordView(Context context, AttributeSet attrs, int defStyle) {  
  39.         super(context, attrs, defStyle);  
  40.     }  
  41.   
  42.     public LocusPassWordView(Context context, AttributeSet attrs) {  
  43.         super(context, attrs);  
  44.     }  
  45.   
  46.     public LocusPassWordView(Context context) {  
  47.         super(context);  
  48.     }  
  49.   
  50.     @Override  
  51.     public void onDraw(Canvas canvas) {  
  52.         if (!isCache) {  
  53.             initCache();  
  54.         }  
  55.         drawToCanvas(canvas);  
  56.     }  
  57.   
  58.     private void drawToCanvas(Canvas canvas) {  
  59.   
  60.         // mPaint.setColor(Color.RED);  
  61.         // Point p1 = mPoints[1][1];  
  62.         // Rect r1 = new Rect(p1.x - r,p1.y - r,p1.x +  
  63.         // locus_round_click.getWidth() - r,p1.y+locus_round_click.getHeight()-  
  64.         // r);  
  65.         // canvas.drawRect(r1, mPaint);  
  66.         // 画所有点  
  67.         for (int i = 0; i < mPoints.length; i++) {  
  68.             for (int j = 0; j < mPoints[i].length; j++) {  
  69.                 Point p = mPoints[i][j];  
  70.                 if (p.state == Point.STATE_CHECK) {  
  71.                     canvas.drawBitmap(locus_round_click, p.x - r, p.y - r,  
  72.                             mPaint);  
  73.                 } else if (p.state == Point.STATE_CHECK_ERROR) {  
  74.                     canvas.drawBitmap(locus_round_click_error, p.x - r,  
  75.                             p.y - r, mPaint);  
  76.                 } else {  
  77.                     canvas.drawBitmap(locus_round_original, p.x - r, p.y - r,  
  78.                             mPaint);  
  79.                 }  
  80.             }  
  81.         }  
  82.         // mPaint.setColor(Color.BLUE);  
  83.         // canvas.drawLine(r1.left+r1.width()/2, r1.top, r1.left+r1.width()/2,  
  84.         // r1.bottom, mPaint);  
  85.         // canvas.drawLine(r1.left, r1.top+r1.height()/2, r1.right,  
  86.         // r1.bottom-r1.height()/2, mPaint);  
  87.   
  88.         // 画连线  
  89.         if (sPoints.size() > 0) {  
  90.             int tmpAlpha = mPaint.getAlpha();  
  91.             mPaint.setAlpha(lineAlpha);  
  92.             Point tp = sPoints.get(0);  
  93.             for (int i = 1; i < sPoints.size(); i++) {  
  94.                 Point p = sPoints.get(i);  
  95.                 drawLine(canvas, tp, p);  
  96.                 tp = p;  
  97.             }  
  98.             if (this.movingNoPoint) {  
  99.                 drawLine(canvas, tp, new Point((int) moveingX, (int) moveingY));  
  100.             }  
  101.             mPaint.setAlpha(tmpAlpha);  
  102.             lineAlpha = mPaint.getAlpha();  
  103.         }  
  104.   
  105.     }  
  106.   
  107.     /** 
  108.      * 初始化Cache信息 
  109.      *  
  110.      * @param canvas 
  111.      */  
  112.     private void initCache() {  
  113.   
  114.         w = this.getWidth();  
  115.         h = this.getHeight();  
  116.         float x = 0;  
  117.         float y = 0;  
  118.   
  119.         // 以最小的为准  
  120.         // 纵屏  
  121.         if (w > h) {  
  122.             x = (w - h) / 2;  
  123.             w = h;  
  124.         }  
  125.         // 横屏  
  126.         else {  
  127.             y = (h - w) / 2;  
  128.             h = w;  
  129.         }  
  130.   
  131.         locus_round_original = BitmapFactory.decodeResource(  
  132.                 this.getResources(), R.drawable.locus_round_original);  
  133.         locus_round_click = BitmapFactory.decodeResource(this.getResources(),  
  134.                 R.drawable.locus_round_click);  
  135.         locus_round_click_error = BitmapFactory.decodeResource(  
  136.                 this.getResources(), R.drawable.locus_round_click_error);  
  137.   
  138.         locus_line = BitmapFactory.decodeResource(this.getResources(),  
  139.                 R.drawable.locus_line);  
  140.         locus_line_semicircle = BitmapFactory.decodeResource(  
  141.                 this.getResources(), R.drawable.locus_line_semicircle);  
  142.   
  143.         locus_line_error = BitmapFactory.decodeResource(this.getResources(),  
  144.                 R.drawable.locus_line_error);  
  145.         locus_line_semicircle_error = BitmapFactory.decodeResource(  
  146.                 this.getResources(), R.drawable.locus_line_semicircle_error);  
  147.   
  148.         locus_arrow = BitmapFactory.decodeResource(this.getResources(),  
  149.                 R.drawable.locus_arrow);  
  150.         // Log.d("Canvas w h :", "w:" + w + " h:" + h);  
  151.   
  152.         // 计算圆圈图片的大小  
  153.         float canvasMinW = w;  
  154.         if (w > h) {  
  155.             canvasMinW = h;  
  156.         }  
  157.         float roundMinW = canvasMinW / 8.0f * 2;  
  158.         float roundW = roundMinW / 2.f;  
  159.         //  
  160.         float deviation = canvasMinW % (8 * 2) / 2;  
  161.         x += deviation;  
  162.         x += deviation;  
  163.   
  164.         if (locus_round_original.getWidth() > roundMinW) {  
  165.             float sf = roundMinW * 1.0f / locus_round_original.getWidth(); // 取得缩放比例,将所有的图片进行缩放  
  166.             locus_round_original = BitmapUtil.zoom(locus_round_original, sf);  
  167.             locus_round_click = BitmapUtil.zoom(locus_round_click, sf);  
  168.             locus_round_click_error = BitmapUtil.zoom(locus_round_click_error,  
  169.                     sf);  
  170.   
  171.             locus_line = BitmapUtil.zoom(locus_line, sf);  
  172.             locus_line_semicircle = BitmapUtil.zoom(locus_line_semicircle, sf);  
  173.   
  174.             locus_line_error = BitmapUtil.zoom(locus_line_error, sf);  
  175.             locus_line_semicircle_error = BitmapUtil.zoom(  
  176.                     locus_line_semicircle_error, sf);  
  177.             locus_arrow = BitmapUtil.zoom(locus_arrow, sf);  
  178.             roundW = locus_round_original.getWidth() / 2;  
  179.         }  
  180.   
  181.         mPoints[0][0] = new Point(x + 0 + roundW, y + 0 + roundW);  
  182.         mPoints[0][1] = new Point(x + w / 2, y + 0 + roundW);  
  183.         mPoints[0][2] = new Point(x + w - roundW, y + 0 + roundW);  
  184.         mPoints[1][0] = new Point(x + 0 + roundW, y + h / 2);  
  185.         mPoints[1][1] = new Point(x + w / 2, y + h / 2);  
  186.         mPoints[1][2] = new Point(x + w - roundW, y + h / 2);  
  187.         mPoints[2][0] = new Point(x + 0 + roundW, y + h - roundW);  
  188.         mPoints[2][1] = new Point(x + w / 2, y + h - roundW);  
  189.         mPoints[2][2] = new Point(x + w - roundW, y + h - roundW);  
  190.         int k = 0;  
  191.         for (Point[] ps : mPoints) {  
  192.             for (Point p : ps) {  
  193.                 p.index = k;  
  194.                 k++;  
  195.             }  
  196.         }  
  197.         r = locus_round_original.getHeight() / 2;// roundW;  
  198.         isCache = true;  
  199.     }  
  200.   
  201.     /** 
  202.      * 画两点的连接 
  203.      *  
  204.      * @param canvas 
  205.      * @param a 
  206.      * @param b 
  207.      */  
  208.     private void drawLine(Canvas canvas, Point a, Point b) {  
  209.         float ah = (float) MathUtil.distance(a.x, a.y, b.x, b.y);  
  210.         float degrees = getDegrees(a, b);  
  211.         // Log.d("=============x===========", "rotate:" + degrees);  
  212.         canvas.rotate(degrees, a.x, a.y);  
  213.   
  214.         if (a.state == Point.STATE_CHECK_ERROR) {  
  215.             mMatrix.setScale((ah - locus_line_semicircle_error.getWidth())  
  216.                     / locus_line_error.getWidth(), 1);  
  217.             mMatrix.postTranslate(a.x, a.y - locus_line_error.getHeight()  
  218.                     / 2.0f);  
  219.             canvas.drawBitmap(locus_line_error, mMatrix, mPaint);  
  220.             canvas.drawBitmap(locus_line_semicircle_error, a.x  
  221.                     + locus_line_error.getWidth(),  
  222.                     a.y - locus_line_error.getHeight() / 2.0f, mPaint);  
  223.         } else {  
  224.             mMatrix.setScale((ah - locus_line_semicircle.getWidth())  
  225.                     / locus_line.getWidth(), 1);  
  226.             mMatrix.postTranslate(a.x, a.y - locus_line.getHeight() / 2.0f);  
  227.             canvas.drawBitmap(locus_line, mMatrix, mPaint);  
  228.             canvas.drawBitmap(locus_line_semicircle, a.x + ah  
  229.                     - locus_line_semicircle.getWidth(),  
  230.                     a.y - locus_line.getHeight() / 2.0f, mPaint);  
  231.         }  
  232.   
  233.         canvas.drawBitmap(locus_arrow, a.x, a.y - locus_arrow.getHeight()  
  234.                 / 2.0f, mPaint);  
  235.   
  236.         canvas.rotate(-degrees, a.x, a.y);  
  237.   
  238.     }  
  239.   
  240.     public float getDegrees(Point a, Point b) {  
  241.         float ax = a.x;// a.index % 3;  
  242.         float ay = a.y;// a.index / 3;  
  243.         float bx = b.x;// b.index % 3;  
  244.         float by = b.y;// b.index / 3;  
  245.         float degrees = 0;  
  246.         if (bx == ax) // y轴相等 90度或270  
  247.         {  
  248.             if (by > ay) // 在y轴的下边 90  
  249.             {  
  250.                 degrees = 90;  
  251.             } else if (by < ay) // 在y轴的上边 270  
  252.             {  
  253.                 degrees = 270;  
  254.             }  
  255.         } else if (by == ay) // y轴相等 0度或180  
  256.         {  
  257.             if (bx > ax) // 在y轴的下边 90  
  258.             {  
  259.                 degrees = 0;  
  260.             } else if (bx < ax) // 在y轴的上边 270  
  261.             {  
  262.                 degrees = 180;  
  263.             }  
  264.         } else {  
  265.             if (bx > ax) // 在y轴的右边 270~90  
  266.             {  
  267.                 if (by > ay) // 在y轴的下边 0 - 90  
  268.                 {  
  269.                     degrees = 0;  
  270.                     degrees = degrees  
  271.                             + switchDegrees(Math.abs(by - ay),  
  272.                                     Math.abs(bx - ax));  
  273.                 } else if (by < ay) // 在y轴的上边 270~0  
  274.                 {  
  275.                     degrees = 360;  
  276.                     degrees = degrees  
  277.                             - switchDegrees(Math.abs(by - ay),  
  278.                                     Math.abs(bx - ax));  
  279.                 }  
  280.   
  281.             } else if (bx < ax) // 在y轴的左边 90~270  
  282.             {  
  283.                 if (by > ay) // 在y轴的下边 180 ~ 270  
  284.                 {  
  285.                     degrees = 90;  
  286.                     degrees = degrees  
  287.                             + switchDegrees(Math.abs(bx - ax),  
  288.                                     Math.abs(by - ay));  
  289.                 } else if (by < ay) // 在y轴的上边 90 ~ 180  
  290.                 {  
  291.                     degrees = 270;  
  292.                     degrees = degrees  
  293.                             - switchDegrees(Math.abs(bx - ax),  
  294.                                     Math.abs(by - ay));  
  295.                 }  
  296.   
  297.             }  
  298.   
  299.         }  
  300.         return degrees;  
  301.     }  
  302.   
  303.     /** 
  304.      * 1=30度 2=45度 4=60度 
  305.      *  
  306.      * @param tan 
  307.      * @return 
  308.      */  
  309.     private float switchDegrees(float x, float y) {  
  310.         return (float) MathUtil.pointTotoDegrees(x, y);  
  311.     }  
  312.   
  313.     /** 
  314.      * 取得数组下标 
  315.      *  
  316.      * @param index 
  317.      * @return 
  318.      */  
  319.     public int[] getArrayIndex(int index) {  
  320.         int[] ai = new int[2];  
  321.         ai[0] = index / 3;  
  322.         ai[1] = index % 3;  
  323.         return ai;  
  324.     }  
  325.   
  326.     /** 
  327.      *  
  328.      * 检查 
  329.      *  
  330.      * @param x 
  331.      * @param y 
  332.      * @return 
  333.      */  
  334.     private Point checkSelectPoint(float x, float y) {  
  335.         for (int i = 0; i < mPoints.length; i++) {  
  336.             for (int j = 0; j < mPoints[i].length; j++) {  
  337.                 Point p = mPoints[i][j];  
  338.                 if (RoundUtil.checkInRound(p.x, p.y, r, (int) x, (int) y)) {  
  339.                     return p;  
  340.                 }  
  341.             }  
  342.         }  
  343.         return null;  
  344.     }  
  345.   
  346.     /** 
  347.      * 重置 
  348.      */  
  349.     private void reset() {  
  350.         for (Point p : sPoints) {  
  351.             p.state = Point.STATE_NORMAL;  
  352.         }  
  353.         sPoints.clear();  
  354.         this.enableTouch();  
  355.     }  
  356.   
  357.     /** 
  358.      * 判断点是否有交叉 返回 0,新点 ,1 与上一点重叠 2,与非最后一点重叠 
  359.      *  
  360.      * @param p 
  361.      * @return 
  362.      */  
  363.     private int crossPoint(Point p) {  
  364.         // 重叠的不最后一个则 reset  
  365.         if (sPoints.contains(p)) {  
  366.             if (sPoints.size() > 2) {  
  367.                 // 与非最后一点重叠  
  368.                 if (sPoints.get(sPoints.size() - 1).index != p.index) {  
  369.                     return 2;  
  370.                 }  
  371.             }  
  372.             return 1// 与最后一点重叠  
  373.         } else {  
  374.             return 0// 新点  
  375.         }  
  376.     }  
  377.   
  378.     /** 
  379.      * 添加一个点 
  380.      *  
  381.      * @param point 
  382.      */  
  383.     private void addPoint(Point point) {  
  384.         this.sPoints.add(point);  
  385.     }  
  386.   
  387.     /** 
  388.      * 转换为String 
  389.      *  
  390.      * @param points 
  391.      * @return 
  392.      */  
  393.     private String toPointString() {  
  394.         if (sPoints.size() > passwordMinLength) {  
  395.             StringBuffer sf = new StringBuffer();  
  396.             for (Point p : sPoints) {  
  397.                 sf.append(",");  
  398.                 sf.append(p.index);  
  399.             }  
  400.             return sf.deleteCharAt(0).toString();  
  401.         } else {  
  402.             return "";  
  403.         }  
  404.     }  
  405.   
  406.     boolean movingNoPoint = false;  
  407.     float moveingX, moveingY;  
  408.   
  409.     @Override  
  410.     public boolean onTouchEvent(MotionEvent event) {  
  411.         // 不可操作  
  412.         if (!isTouch) {  
  413.             return false;  
  414.         }  
  415.   
  416.         movingNoPoint = false;  
  417.   
  418.         float ex = event.getX();  
  419.         float ey = event.getY();  
  420.         boolean isFinish = false;  
  421.         boolean redraw = false;  
  422.         Point p = null;  
  423.         switch (event.getAction()) {  
  424.         case MotionEvent.ACTION_DOWN: // 点下  
  425.             // 如果正在清除密码,则取消  
  426.             if (task != null) {  
  427.                 task.cancel();  
  428.                 task = null;  
  429.                 Log.d("task""touch cancel()");  
  430.             }  
  431.             // 删除之前的点  
  432.             reset();  
  433.             p = checkSelectPoint(ex, ey);  
  434.             if (p != null) {  
  435.                 checking = true;  
  436.             }  
  437.             break;  
  438.         case MotionEvent.ACTION_MOVE: // 移动  
  439.             if (checking) {  
  440.                 p = checkSelectPoint(ex, ey);  
  441.                 if (p == null) {  
  442.                     movingNoPoint = true;  
  443.                     moveingX = ex;  
  444.                     moveingY = ey;  
  445.                 }  
  446.             }  
  447.             break;  
  448.         case MotionEvent.ACTION_UP: // 提起  
  449.             p = checkSelectPoint(ex, ey);  
  450.             checking = false;  
  451.             isFinish = true;  
  452.             break;  
  453.         }  
  454.         if (!isFinish && checking && p != null) {  
  455.   
  456.             int rk = crossPoint(p);  
  457.             if (rk == 2// 与非最后一重叠  
  458.             {  
  459.                 // reset();  
  460.                 // checking = false;  
  461.   
  462.                 movingNoPoint = true;  
  463.                 moveingX = ex;  
  464.                 moveingY = ey;  
  465.   
  466.                 redraw = true;  
  467.             } else if (rk == 0// 一个新点  
  468.             {  
  469.                 p.state = Point.STATE_CHECK;  
  470.                 addPoint(p);  
  471.                 redraw = true;  
  472.             }  
  473.             // rk == 1 不处理  
  474.   
  475.         }  
  476.   
  477.         // 是否重画  
  478.         if (redraw) {  
  479.   
  480.         }  
  481.         if (isFinish) {  
  482.             if (this.sPoints.size() == 1) {  
  483.                 this.reset();  
  484.             } else if (this.sPoints.size() < passwordMinLength  
  485.                     && this.sPoints.size() > 0) {  
  486.                 // mCompleteListener.onPasswordTooMin(sPoints.size());  
  487.                 error();  
  488.                 clearPassword();  
  489.                 Toast.makeText(this.getContext(), "密码太短,请重新输入!",  
  490.                         Toast.LENGTH_SHORT).show();  
  491.             } else if (mCompleteListener != null) {  
  492.                 if (this.sPoints.size() >= passwordMinLength) {  
  493.                     this.disableTouch();  
  494.                     mCompleteListener.onComplete(toPointString());  
  495.                 }  
  496.   
  497.             }  
  498.         }  
  499.         this.postInvalidate();  
  500.         return true;  
  501.     }  
  502.   
  503.     /** 
  504.      * 设置已经选中的为错误 
  505.      */  
  506.     private void error() {  
  507.         for (Point p : sPoints) {  
  508.             p.state = Point.STATE_CHECK_ERROR;  
  509.         }  
  510.     }  
  511.   
  512.     /** 
  513.      * 设置为输入错误 
  514.      */  
  515.     public void markError() {  
  516.         markError(CLEAR_TIME);  
  517.     }  
  518.   
  519.     /** 
  520.      * 设置为输入错误 
  521.      */  
  522.     public void markError(final long time) {  
  523.         for (Point p : sPoints) {  
  524.             p.state = Point.STATE_CHECK_ERROR;  
  525.         }  
  526.         this.clearPassword(time);  
  527.     }  
  528.   
  529.     /** 
  530.      * 设置为可操作 
  531.      */  
  532.     public void enableTouch() {  
  533.         isTouch = true;  
  534.     }  
  535.   
  536.     /** 
  537.      * 设置为不可操作 
  538.      */  
  539.     public void disableTouch() {  
  540.         isTouch = false;  
  541.     }  
  542.   
  543.     private Timer timer = new Timer();  
  544.     private TimerTask task = null;  
  545.   
  546.     /** 
  547.      * 清除密码 
  548.      */  
  549.     public void clearPassword() {  
  550.         clearPassword(CLEAR_TIME);  
  551.     }  
  552.   
  553.     /** 
  554.      * 清除密码 
  555.      */  
  556.     public void clearPassword(final long time) {  
  557.         if (time > 1) {  
  558.             if (task != null) {  
  559.                 task.cancel();  
  560.                 Log.d("task""clearPassword cancel()");  
  561.             }  
  562.             lineAlpha = 130;  
  563.             postInvalidate();  
  564.             task = new TimerTask() {  
  565.                 public void run() {  
  566.                     reset();  
  567.                     postInvalidate();  
  568.                 }  
  569.             };  
  570.             Log.d("task""clearPassword schedule(" + time + ")");  
  571.             timer.schedule(task, time);  
  572.         } else {  
  573.             reset();  
  574.             postInvalidate();  
  575.         }  
  576.   
  577.     }  
  578.   
  579.     //  
  580.     private OnCompleteListener mCompleteListener;  
  581.   
  582.     /** 
  583.      * @param mCompleteListener 
  584.      */  
  585.     public void setOnCompleteListener(OnCompleteListener mCompleteListener) {  
  586.         this.mCompleteListener = mCompleteListener;  
  587.     }  
  588.   
  589.     /** 
  590.      * 取得密码 
  591.      *  
  592.      * @return 
  593.      */  
  594.     private String getPassword() {  
  595.         SharedPreferences settings = this.getContext().getSharedPreferences(  
  596.                 this.getClass().getName(), 0);  
  597.         return settings.getString("password"""); // , "0,1,2,3,4,5,6,7,8"  
  598.     }  
  599.   
  600.     /** 
  601.      * 密码是否为空 
  602.      *  
  603.      * @return 
  604.      */  
  605.     public boolean isPasswordEmpty() {  
  606.         return StringUtil.isEmpty(getPassword());  
  607.     }  
  608.   
  609.     public boolean verifyPassword(String password) {  
  610.         boolean verify = false;  
  611.         if (com.way.util.StringUtil.isNotEmpty(password)) {  
  612.             // 或者是超级密码  
  613.             if (password.equals(getPassword())) {  
  614.                 verify = true;  
  615.             }  
  616.         }  
  617.         return verify;  
  618.     }  
  619.   
  620.     /** 
  621.      * 设置密码 
  622.      *  
  623.      * @param password 
  624.      */  
  625.     public void resetPassWord(String password) {  
  626.         SharedPreferences settings = this.getContext().getSharedPreferences(  
  627.                 this.getClass().getName(), 0);  
  628.         Editor editor = settings.edit();  
  629.         editor.putString("password", password);  
  630.         editor.commit();  
  631.     }  
  632.   
  633.     public int getPasswordMinLength() {  
  634.         return passwordMinLength;  
  635.     }  
  636.   
  637.     public void setPasswordMinLength(int passwordMinLength) {  
  638.         this.passwordMinLength = passwordMinLength;  
  639.     }  
  640.   
  641.     /** 
  642.      * 轨迹球画完成事件 
  643.      *  
  644.      * @author way 
  645.      */  
  646.     public interface OnCompleteListener {  
  647.         /** 
  648.          * 画完了 
  649.          *  
  650.          * @param str 
  651.          */  
  652.         public void onComplete(String password);  
  653.     }  
  654. }  

这里只贴出了最重要的那部分代码,有兴趣的朋友可以下载源码看看


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 黑布鞋不黑了怎么办 黑布鞋退白了怎么办 老北京布鞋款式太少怎么办 老人输液抽搐后昏迷怎么办 头七家里有狗怎么办 股票退市股民的钱怎么办 美国股票退市股民怎么办 百度云字幕和视频不同步怎么办 百度云加载字幕有延迟怎么办 很难适应新环境怎么办 蜘蛛丝碰到嘴唇上起包有毒怎么办? 电瓶车在路上爆胎了怎么办 嘴被虫子咬肿了怎么办 高铁管家购票失败怎么办 高铁车厢空调冷怎么办 高铁票过了时间怎么办 网购火车票丢了怎么办 改签没有票了怎么办 火车票取了没赶上车怎么办 上车后车票丢了怎么办 晒了吗任务过期怎么办 坐火车买了站票怎么办 坐火车忘记带票怎么办 距离二本线差几分怎么办 行李包落火车候车厅怎么办 高铁票买错地点怎么办 高铁票买错日期怎么办 票买错时间了怎么办 上高铁了票丢了怎么办 上车前高铁票丢了怎么办 高铁安检没收的东西怎么办 高铁安检员老了怎么办 高铁安检喷雾拍照了怎么办 十个小时的高铁怎么办 华为开机需要激活码怎么办 高铁提前上车了出站怎么办 买火车票忘记带身份证怎么办 买高铁票没赶上怎么办 电脑放视频没有声音怎么办 内业计算中角度超限怎么办 遇到飞机出故障乘客怎么办