九点(九宫格)式手势解锁自定义view

来源:互联网 发布:linux远程拷贝文件命令 编辑:程序博客网 时间:2024/03/28 19:15

周末闲着没事,写了个手势解锁的view,实现起来也蛮快的,半天多一点时间就完事。把源码和资源贴出来,给大家分享,希望对大家有用。

效果,就跟手机上的九点手势解锁一样,上个图吧:

\

 

过程嘛感觉确实没啥好讲的了,涉及的知识以前的博客都说过了,无非就是canva,paint,touch事件这些,画画圆圈画画线条,剩下的就是细节处理逻辑了。都在代码里,所以这里就主要是贴资源吧。

这个自定义view就一个类,源码如下:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
packagecom.cc.library.view;
 
importandroid.content.Context;
importandroid.graphics.Canvas;
importandroid.graphics.Color;
importandroid.graphics.Paint;
importandroid.graphics.Path;
importandroid.location.Location;
importandroid.util.AttributeSet;
importandroid.util.Log;
importandroid.view.MotionEvent;
importandroid.view.View;
importandroid.view.ViewTreeObserver;
 
/**
 * 图案解锁view
 * Created by zhangyu on 2016-07-15 15:05.
 */
publicclass UnlockView extendsView {
    privatestatic final String TAG = "UnlockView";
    //view宽高
    privatefloat width, height;
    //平均宽高(分三份)
    privatefloat averageWidth, averageHeight;
    //九个点的位置数据,从左到右、从上到下 123...789
    Location[] locations = newLocation[9];
    //圆圈半径
    privatefloat radius;
    //绘制密码
    privateint[] drawingPwd = newint[9];
    //正确的密码
    privateint[] rightPwd;
    //画笔
    privatePaint whitePaint, cyanPaint;
    //已经绘制过了的点个数
    privateint drawedNumber;
    //当前正被触摸的点
    privateLocation nowTouchedPosition = newLocation();
    //监听
    privateUnlockListener unlockListener;
 
 
    publicvoid setUnlockListener(UnlockListener unlockListener) {
        this.unlockListener = unlockListener;
    }
 
    publicUnlockView(Context context) {
        super(context);
        init();
    }
 
    publicUnlockView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
 
    publicUnlockView(Context context, AttributeSet attrs, intdefStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
 
 
    privatevoid init() {
        ViewTreeObserver vto = getViewTreeObserver();
        vto.addOnGlobalLayoutListener(newViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            publicvoid onGlobalLayout() {
                height = getHeight();
                width = getWidth();
                Log.d(TAG,"width = " + width + "  ,height = " + height);
                averageWidth = width / 3f;
                averageHeight = height / 3f;
                radius = averageHeight > averageWidth ? averageWidth / 5f : averageHeight / 5f;
 
                initLocation();
                invalidate();
            }
        });
 
        whitePaint = newPaint();
        whitePaint.setAntiAlias(true);
        whitePaint.setColor(Color.parseColor("#ffffff"));
        whitePaint.setStyle(Paint.Style.STROKE);
 
        cyanPaint = newPaint();
        cyanPaint.setAntiAlias(true);
        cyanPaint.setColor(Color.parseColor("#4169E1"));
        cyanPaint.setStyle(Paint.Style.STROKE);
 
        initDrawingPwd();
    }
 
    privatevoid drawStart() {
        drawedNumber = 0;
    }
 
    privatevoid drawOver() {
        //debug
        StringBuffer sb = newStringBuffer();
        for(inti = 0; i < drawingPwd.length; i++) {
            sb.append(drawingPwd[i] + ",");
        }
        Log.i(TAG,"drawingPwd:"+ sb.toString());
 
        initLocation();
        initDrawingPwd();
        drawedNumber = 0;
        invalidate();
    }
 
    /**
     * 初始化绘制密码
     */
    privatevoid initDrawingPwd() {
        for(inti = 0; i < 9; i++) {
            drawingPwd[i] = -1;
        }
    }
 
    /**
     * 初始化九个点坐标
     */
    privatevoid initLocation() {
        for(inti = 0; i < 9; i++) {
            locations[i] = newLocation();
            locations[i].deawed = false;
 
            //纵向1、2、3列x坐标
            if(i % 3== 0) {
                locations[i].x = averageWidth * 0.5f;
            }elseif (i % 3== 1) {
                locations[i].x = averageWidth * 1.5f;
            }elseif (i % 3== 2) {
                locations[i].x = averageWidth * 2.5f;
            }
 
            //横向1、2、3排y坐标
            if(i / 3== 0) {
                locations[i].y = averageHeight * 0.5f;
            }elseif (i / 3== 1) {
                locations[i].y = averageHeight * 1.5f;
            }elseif (i / 3== 2) {
                locations[i].y = averageHeight * 2.5f;
            }
        }
    }
 
    @Override
    protectedvoid onDraw(Canvas canvas) {
        for(inti = 0; i < 9; i++) {
            if(!locations[i].deawed) {//没被画
                whitePaint.setStrokeWidth(4);
                canvas.drawPoint(locations[i].x, locations[i].y, whitePaint);
                whitePaint.setStrokeWidth(1.5f);
                canvas.drawCircle(locations[i].x, locations[i].y, radius, whitePaint);
            }else{//被画过了
                cyanPaint.setStrokeWidth(8);
                canvas.drawPoint(locations[i].x, locations[i].y, cyanPaint);
                cyanPaint.setStrokeWidth(3f);
                canvas.drawCircle(locations[i].x, locations[i].y, radius, cyanPaint);
            }
 
            intlastestDrawedPoint = -1;
            if(drawedNumber > 0)
                lastestDrawedPoint = drawingPwd[drawedNumber - 1];
            if(lastestDrawedPoint != -1) {
                Location lastestDrawedLocation = locations[lastestDrawedPoint];//最新一个被选中的点
                cyanPaint.setStrokeWidth(3f);
                canvas.drawLine(lastestDrawedLocation.x, lastestDrawedLocation.y, nowTouchedPosition.x, nowTouchedPosition.y, cyanPaint);
            }
 
            if(drawedNumber > 1) {
                for(intj = 0; j < drawedNumber - 1; j++) {
                    cyanPaint.setStrokeWidth(3f);
                    canvas.drawLine(locations[drawingPwd[j]].x, locations[drawingPwd[j]].y, locations[drawingPwd[j + 1]].x, locations[drawingPwd[j + 1]].y, cyanPaint);
                }
            }
        }
        super.onDraw(canvas);
    }
 
    floatmoveX, moveY;
 
    @Override
    publicboolean onTouchEvent(MotionEvent event) {
        switch(event.getAction()) {
            caseMotionEvent.ACTION_DOWN:
                drawStart();
                break;
            caseMotionEvent.ACTION_MOVE:
                moveX = event.getX();
                moveY = event.getY();
 
                dealPosition(moveX, moveY);
                break;
            caseMotionEvent.ACTION_UP:
 
                if(unlockListener != null) {
                    unlockListener.drawOver(drawingPwd);
                    if(verificationPwd(rightPwd)) {
                        unlockListener.isPwdRight(true);
                    }else{
                        unlockListener.isPwdRight(false);
                    }
                }
                drawOver();
                break;
        }
        returntrue;
    }
 
    privatevoid dealPosition(floatnowX, floatnowY) {
        nowTouchedPosition.x = nowX;
        nowTouchedPosition.y = nowY;
 
        intnowTouched = getWhichOneBeTouched(nowX, nowY);
        if(nowTouched != -1) {//触摸到了点上
 
            if(!locations[nowTouched].deawed) {//如果这点没被触摸过
                drawingPwd[drawedNumber] = nowTouched;      //记录密码
                drawedNumber++;    //被触摸点数+1
                Log.v(TAG,"nowTouched " + nowTouched + "  ,drawedNumber = " + drawedNumber);
 
            }
            locations[nowTouched].deawed = true;
        }
        invalidate();
    }
 
    privateclass Location {
        publicfloat x = -1, y = -1;
        publicboolean deawed;//是否被画过了
    }
 
    /**
     * 获取被触摸到的点
     *
     * @param x 坐标x点
     * @param y 坐标y点
     * @return 被触摸的坐标点位置 或者-1
     */
    privateint getWhichOneBeTouched(floatx, floaty) {
        for(inti = 0; i < locations.length; i++) {
 
            doublelPowX = Math.pow(Math.abs(x - locations[i].x), 2);
            doublelPowY = Math.pow(Math.abs(y - locations[i].y), 2);
 
            if(Math.sqrt(lPowX + lPowY) < radius)
                returni;
        }
        return-1;
    }
 
    /**
     * 校验密码是否正确
     *
     * @param rightPwd 正确的密码
     * @return 正确返回true 否则返回false
     */
    publicboolean verificationPwd(int[] rightPwd) {
        if(rightPwd == null)
            returnfalse;
 
        for(inti = 0; i < rightPwd.length; i++) {
            if(rightPwd[i] != drawingPwd[i])
                returnfalse;
        }
 
        returntrue;
    }
 
    /**
     * 获取当前绘制的密码
     *
     * @return
     */
    publicint[] getDrawedPwd() {
        returndrawingPwd;
    }
 
    /**
     * 设置正确的密码
     *
     * @param rightPwd
     */
    publicvoid setRightPwd(int[] rightPwd) {
        this.rightPwd = rightPwd;
    }
 
    //监听接口
    publicinterface UnlockListener {
        publicvoid drawOver(int[] pwd);
        publicvoid isPwdRight(booleanisRight);
    }
}
布局(view的宽高你可以随意指定,bg1是效果里那张背景图片):

 

 

?
1
2
3
4
5
<!--?xml version="1.0"encoding="utf-8"?-->
<relativelayout android:background="@drawable/bg1"android:layout_height="match_parent"android:layout_width="match_parent"xmlns:android="http://schemas.android.com/apk/res/android">
 
    <com.cc.library.view.unlockview android:id="@+id/unlock_view"android:layout_alignparentbottom="true"android:layout_height="360dp"android:layout_width="match_parent">
</com.cc.library.view.unlockview></relativelayout>

使用:

 

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
packagecom.sz.china.testmoudule;
 
importandroid.app.Activity;
importandroid.os.Bundle;
importandroid.widget.Toast;
 
importcom.cc.library.view.UnlockView;
 
/**
 * Created by zhangyu on 2016-07-15 14:55.
 */
publicclass TestUnlockViewActivity extendsActivity {
 
    privateUnlockView unlockView;
    @Override
    protectedvoid onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.unlock_activity);
 
        unlockView = (UnlockView) findViewById(R.id.unlock_view);
 
        //设置回调监听
        unlockView.setUnlockListener(newUnlockView.UnlockListener() {
            @Override
            publicvoid drawOver(int[] pwd) {//绘制完成,获取绘制的密码
                unlockView.getDrawedPwd();
            }
            @Override
            publicvoid isPwdRight(booleanisRight) {//密码是否校验正确
                if(isRight)
                    Toast.makeText(TestUnlockViewActivity.this,"密码正确",Toast.LENGTH_SHORT).show();
                else
                    Toast.makeText(TestUnlockViewActivity.this,"密码错误",Toast.LENGTH_SHORT).show();
            }
        });
 
        int[] pwd = {0,5,7,6};
        unlockView.setRightPwd(pwd);   //设置密码
 
    }
}
原创粉丝点击