Android之九宮格解鎖的實現

九宮格解鎖在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. }  

這裏只貼出了最重要的那部分代碼,有興趣的朋友可以下載源碼看看


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章