http://blog.csdn.net/lmj623565791/article/details/3623611http://blog.csdn.net/lmj623565791/article/details/362361133http://blog.csdn.net/lmj623565791/article/details/36236113

http://blog.csdn.net/lmj623565791/article/details/36236113





Android 手势锁的实现 让自己的应用更加安全吧

分类:android进阶android 1293人阅读 评论(5) 收藏 举报 android 手势锁 自定义View

目录(?)[+]

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/36236113

今天偶遇以github上gesturelock关于手势锁的一个例子(有兴趣的去搜索下看看),于是下载下来研究,无奈基本没有注释,代码上存在一些问题(当设置gravity=center_vertical无法进行手势选择,无意中发现的),于是借鉴这位仁兄的代码,自己重写写了一个,修复了一些问题,加入一些基本的自定义属性,在此先感谢这位兄弟~。

先上图,默认效果图:



当然可以自定义数量啊,颜色神马的,自定义效果图:



如果你有艺术细胞,可以给我推荐几个颜色,无奈个人审美有问题~


1、整体思路

a、自定义了一个RelativeLayout(GestureLockViewGroup)在里面会根据传入的每行的个数,生成多个GestureLockView(就是上面一个个小圈圈),然后会自动进行布局,里面的宽度,间距,内圆的直径,箭头的大小神马的都是百分比实现的,所以大胆的设置你喜欢的个数,只要你没有密集恐惧症~

b、GestureLockView有三个状态,没有手指触碰、手指触碰、和手指抬起,会根据这三个状态绘制不同的效果,以及抬起时的小箭头需要旋转的角度,会根据用户选择的GestureLockView,进行计算,在GestureLockViewGroup为每个GestureLockView设置

c、GestureLockViewGroup主要就是判断用户ACTION_MOVE,ACTION_DOWN ,ACTION_UP时改变选中的GestureLockView的状态,并且记录下来,提供一定的回调。

下面开始看代码:

2、声明一些用户可以设置的属性:

[html] view plain copy
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <resources>
  3. <attrname="color_no_finger_inner_circle"format="color"/>
  4. <attrname="color_no_finger_outer_circle"format="color"/>
  5. <attrname="color_finger_on"format="color"/>
  6. <attrname="color_finger_up"format="color"/>
  7. <attrname="count"format="integer"/>
  8. <attrname="tryTimes"format="integer"/>
  9. <declare-styleablename="GestureLockViewGroup">
  10. <attrname="color_no_finger_inner_circle"/>
  11. <attrname="color_no_finger_outer_circle"/>
  12. <attrname="color_finger_on"/>
  13. <attrname="color_finger_up"/>
  14. <attrname="count"/>
  15. <attrname="tryTimes"/>
  16. </declare-styleable>
  17. </resources>

用户可以用过在xml文件中设置这些属性,改变外观,最多尝试次数以及数量等。

3、GestureLockView

[java] view plain copy
  1. packagecom.zhy.zhy_gesturelockview.view;
  2. importandroid.content.Context;
  3. importandroid.graphics.Canvas;
  4. importandroid.graphics.Paint;
  5. importandroid.graphics.Paint.Style;
  6. importandroid.graphics.Path;
  7. importandroid.view.View;
  8. publicclassGestureLockViewextendsView
  9. {
  10. privatestaticfinalStringTAG="GestureLockView";
  11. /**
  12. *GestureLockView的三种状态
  13. */
  14. enumMode
  15. {
  16. STATUS_NO_FINGER,STATUS_FINGER_ON,STATUS_FINGER_UP;
  17. }
  18. /**
  19. *GestureLockView的当前状态
  20. */
  21. privateModemCurrentStatus=Mode.STATUS_NO_FINGER;
  22. /**
  23. *宽度
  24. */
  25. privateintmWidth;
  26. /**
  27. *高度
  28. */
  29. privateintmHeight;
  30. /**
  31. *外圆半径
  32. */
  33. privateintmRadius;
  34. /**
  35. *画笔的宽度
  36. */
  37. privateintmStrokeWidth=2;
  38. /**
  39. *圆心坐标
  40. */
  41. privateintmCenterX;
  42. privateintmCenterY;
  43. privatePaintmPaint;
  44. /**
  45. *箭头(小三角最长边的一半长度=mArrawRate*mWidth/2)
  46. */
  47. privatefloatmArrowRate=0.333f;
  48. privateintmArrowDegree=-1;
  49. privatePathmArrowPath;
  50. /**
  51. *内圆的半径=mInnerCircleRadiusRate*mRadus
  52. *
  53. */
  54. privatefloatmInnerCircleRadiusRate=0.3F;
  55. /**
  56. *四个颜色,可由用户自定义,初始化时由GestureLockViewGroup传入
  57. */
  58. privateintmColorNoFingerInner;
  59. privateintmColorNoFingerOutter;
  60. privateintmColorFingerOn;
  61. privateintmColorFingerUp;
  62. publicGestureLockView(Contextcontext,intcolorNoFingerInner,intcolorNoFingerOutter,intcolorFingerOn,intcolorFingerUp)
  63. {
  64. super(context);
  65. this.mColorNoFingerInner=colorNoFingerInner;
  66. this.mColorNoFingerOutter=colorNoFingerOutter;
  67. this.mColorFingerOn=colorFingerOn;
  68. this.mColorFingerUp=colorFingerUp;
  69. mPaint=newPaint(Paint.ANTI_ALIAS_FLAG);
  70. mArrowPath=newPath();
  71. }
  72. @Override
  73. protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec)
  74. {
  75. super.onMeasure(widthMeasureSpec,heightMeasureSpec);
  76. mWidth=MeasureSpec.getSize(widthMeasureSpec);
  77. mHeight=MeasureSpec.getSize(heightMeasureSpec);
  78. //取长和宽中的小值
  79. mWidth=mWidth<mHeight?mWidth:mHeight;
  80. mRadius=mCenterX=mCenterY=mWidth/2;
  81. mRadius-=mStrokeWidth/2;
  82. //绘制三角形,初始时是个默认箭头朝上的一个等腰三角形,用户绘制结束后,根据由两个GestureLockView决定需要旋转多少度
  83. floatmArrowLength=mWidth/2*mArrowRate;
  84. mArrowPath.moveTo(mWidth/2,mStrokeWidth+2);
  85. mArrowPath.lineTo(mWidth/2-mArrowLength,mStrokeWidth+2
  86. +mArrowLength);
  87. mArrowPath.lineTo(mWidth/2+mArrowLength,mStrokeWidth+2
  88. +mArrowLength);
  89. mArrowPath.close();
  90. mArrowPath.setFillType(Path.FillType.WINDING);
  91. }
  92. @Override
  93. protectedvoidonDraw(Canvascanvas)
  94. {
  95. switch(mCurrentStatus)
  96. {
  97. caseSTATUS_FINGER_ON:
  98. //绘制外圆
  99. mPaint.setStyle(Style.STROKE);
  100. mPaint.setColor(mColorFingerOn);
  101. mPaint.setStrokeWidth(2);
  102. canvas.drawCircle(mCenterX,mCenterY,mRadius,mPaint);
  103. //绘制内圆
  104. mPaint.setStyle(Style.FILL);
  105. canvas.drawCircle(mCenterX,mCenterY,mRadius
  106. *mInnerCircleRadiusRate,mPaint);
  107. break;
  108. caseSTATUS_FINGER_UP:
  109. //绘制外圆
  110. mPaint.setColor(mColorFingerUp);
  111. mPaint.setStyle(Style.STROKE);
  112. mPaint.setStrokeWidth(2);
  113. canvas.drawCircle(mCenterX,mCenterY,mRadius,mPaint);
  114. //绘制内圆
  115. mPaint.setStyle(Style.FILL);
  116. canvas.drawCircle(mCenterX,mCenterY,mRadius
  117. *mInnerCircleRadiusRate,mPaint);
  118. drawArrow(canvas);
  119. break;
  120. caseSTATUS_NO_FINGER:
  121. //绘制外圆
  122. mPaint.setStyle(Style.FILL);
  123. mPaint.setColor(mColorNoFingerOutter);
  124. canvas.drawCircle(mCenterX,mCenterY,mRadius,mPaint);
  125. //绘制内圆
  126. mPaint.setColor(mColorNoFingerInner);
  127. canvas.drawCircle(mCenterX,mCenterY,mRadius
  128. *mInnerCircleRadiusRate,mPaint);
  129. break;
  130. }
  131. }
  132. /**
  133. *绘制箭头
  134. *@paramcanvas
  135. */
  136. privatevoiddrawArrow(Canvascanvas)
  137. {
  138. if(mArrowDegree!=-1)
  139. {
  140. mPaint.setStyle(Paint.Style.FILL);
  141. canvas.save();
  142. canvas.rotate(mArrowDegree,mCenterX,mCenterY);
  143. canvas.drawPath(mArrowPath,mPaint);
  144. canvas.restore();
  145. }
  146. }
  147. /**
  148. *设置当前模式并重绘界面
  149. *
  150. *@parammode
  151. */
  152. publicvoidsetMode(Modemode)
  153. {
  154. this.mCurrentStatus=mode;
  155. invalidate();
  156. }
  157. publicvoidsetArrowDegree(intdegree)
  158. {
  159. this.mArrowDegree=degree;
  160. }
  161. publicintgetArrowDegree()
  162. {
  163. returnthis.mArrowDegree;
  164. }
  165. }

注释很详细,主要就是onDraw时,判断当前状态,绘制不同的显示效果;状态的改变都是GestureLockViewGroup的onTouchEvent中设置的。

4、GestureLockViewGroup

[java] view plain copy
  1. packagecom.zhy.zhy_gesturelockview.view;
  2. importjava.util.ArrayList;
  3. importjava.util.List;
  4. importandroid.content.Context;
  5. importandroid.content.res.TypedArray;
  6. importandroid.graphics.Canvas;
  7. importandroid.graphics.Color;
  8. importandroid.graphics.Paint;
  9. importandroid.graphics.Path;
  10. importandroid.graphics.Point;
  11. importandroid.util.AttributeSet;
  12. importandroid.util.Log;
  13. importandroid.view.MotionEvent;
  14. importandroid.view.View;
  15. importandroid.widget.RelativeLayout;
  16. importcom.zhy.zhy_gesturelockview.R;
  17. importcom.zhy.zhy_gesturelockview.view.GestureLockView.Mode;
  18. /**
  19. *整体包含n*n个GestureLockView,每个GestureLockView间间隔mMarginBetweenLockView,
  20. *最外层的GestureLockView与容器存在mMarginBetweenLockView的外边距
  21. *
  22. *关于GestureLockView的边长(n*n):n*mGestureLockViewWidth+(n+1)*
  23. *mMarginBetweenLockView=mWidth;得:mGestureLockViewWidth=4*mWidth/(5
  24. **mCount+1)注:mMarginBetweenLockView=mGestureLockViewWidth*0.25;
  25. *
  26. *@authorzhy
  27. *
  28. */
  29. publicclassGestureLockViewGroupextendsRelativeLayout
  30. {
  31. privatestaticfinalStringTAG="GestureLockViewGroup";
  32. /**
  33. *保存所有的GestureLockView
  34. */
  35. privateGestureLockView[]mGestureLockViews;
  36. /**
  37. *每个边上的GestureLockView的个数
  38. */
  39. privateintmCount=4;
  40. /**
  41. *存储答案
  42. */
  43. privateint[]mAnswer={0,1,2,5,8};
  44. /**
  45. *保存用户选中的GestureLockView的id
  46. */
  47. privateList<Integer>mChoose=newArrayList<Integer>();
  48. privatePaintmPaint;
  49. /**
  50. *每个GestureLockView中间的间距设置为:mGestureLockViewWidth*25%
  51. */
  52. privateintmMarginBetweenLockView=30;
  53. /**
  54. *GestureLockView的边长4*mWidth/(5*mCount+1)
  55. */
  56. privateintmGestureLockViewWidth;
  57. /**
  58. *GestureLockView无手指触摸的状态下内圆的颜色
  59. */
  60. privateintmNoFingerInnerCircleColor=0xFF939090;
  61. /**
  62. *GestureLockView无手指触摸的状态下外圆的颜色
  63. */
  64. privateintmNoFingerOuterCircleColor=0xFFE0DBDB;
  65. /**
  66. *GestureLockView手指触摸的状态下内圆和外圆的颜色
  67. */
  68. privateintmFingerOnColor=0xFF378FC9;
  69. /**
  70. *GestureLockView手指抬起的状态下内圆和外圆的颜色
  71. */
  72. privateintmFingerUpColor=0xFFFF0000;
  73. /**
  74. *宽度
  75. */
  76. privateintmWidth;
  77. /**
  78. *高度
  79. */
  80. privateintmHeight;
  81. privatePathmPath;
  82. /**
  83. *指引线的开始位置x
  84. */
  85. privateintmLastPathX;
  86. /**
  87. *指引线的开始位置y
  88. */
  89. privateintmLastPathY;
  90. /**
  91. *指引下的结束位置
  92. */
  93. privatePointmTmpTarget=newPoint();
  94. /**
  95. *最大尝试次数
  96. */
  97. privateintmTryTimes=4;
  98. /**
  99. *回调接口
  100. */
  101. privateOnGestureLockViewListenermOnGestureLockViewListener;
  102. publicGestureLockViewGroup(Contextcontext,AttributeSetattrs)
  103. {
  104. this(context,attrs,0);
  105. }
  106. publicGestureLockViewGroup(Contextcontext,AttributeSetattrs,
  107. intdefStyle)
  108. {
  109. super(context,attrs,defStyle);
  110. /**
  111. *获得所有自定义的参数的值
  112. */
  113. TypedArraya=context.getTheme().obtainStyledAttributes(attrs,
  114. R.styleable.GestureLockViewGroup,defStyle,0);
  115. intn=a.getIndexCount();
  116. for(inti=0;i<n;i++)
  117. {
  118. intattr=a.getIndex(i);
  119. switch(attr)
  120. {
  121. caseR.styleable.GestureLockViewGroup_color_no_finger_inner_circle:
  122. mNoFingerInnerCircleColor=a.getColor(attr,
  123. mNoFingerInnerCircleColor);
  124. break;
  125. caseR.styleable.GestureLockViewGroup_color_no_finger_outer_circle:
  126. mNoFingerOuterCircleColor=a.getColor(attr,
  127. mNoFingerOuterCircleColor);
  128. break;
  129. caseR.styleable.GestureLockViewGroup_color_finger_on:
  130. mFingerOnColor=a.getColor(attr,mFingerOnColor);
  131. break;
  132. caseR.styleable.GestureLockViewGroup_color_finger_up:
  133. mFingerUpColor=a.getColor(attr,mFingerUpColor);
  134. break;
  135. caseR.styleable.GestureLockViewGroup_count:
  136. mCount=a.getInt(attr,3);
  137. break;
  138. caseR.styleable.GestureLockViewGroup_tryTimes:
  139. mTryTimes=a.getInt(attr,5);
  140. default:
  141. break;
  142. }
  143. }
  144. a.recycle();
  145. //初始化画笔
  146. mPaint=newPaint(Paint.ANTI_ALIAS_FLAG);
  147. mPaint.setStyle(Paint.Style.STROKE);
  148. //mPaint.setStrokeWidth(20);
  149. mPaint.setStrokeCap(Paint.Cap.ROUND);
  150. mPaint.setStrokeJoin(Paint.Join.ROUND);
  151. //mPaint.setColor(Color.parseColor("#aaffffff"));
  152. mPath=newPath();
  153. }
  154. @Override
  155. protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec)
  156. {
  157. super.onMeasure(widthMeasureSpec,heightMeasureSpec);
  158. mWidth=MeasureSpec.getSize(widthMeasureSpec);
  159. mHeight=MeasureSpec.getSize(heightMeasureSpec);
  160. //Log.e(TAG,mWidth+"");
  161. //Log.e(TAG,mHeight+"");
  162. mHeight=mWidth=mWidth<mHeight?mWidth:mHeight;
  163. //setMeasuredDimension(mWidth,mHeight);
  164. //初始化mGestureLockViews
  165. if(mGestureLockViews==null)
  166. {
  167. mGestureLockViews=newGestureLockView[mCount*mCount];
  168. //计算每个GestureLockView的宽度
  169. mGestureLockViewWidth=(int)(4*mWidth*1.0f/(5*mCount+1));
  170. //计算每个GestureLockView的间距
  171. mMarginBetweenLockView=(int)(mGestureLockViewWidth*0.25);
  172. //设置画笔的宽度为GestureLockView的内圆直径稍微小点(不喜欢的话,随便设)
  173. mPaint.setStrokeWidth(mGestureLockViewWidth*0.29f);
  174. for(inti=0;i<mGestureLockViews.length;i++)
  175. {
  176. //初始化每个GestureLockView
  177. mGestureLockViews[i]=newGestureLockView(getContext(),
  178. mNoFingerInnerCircleColor,mNoFingerOuterCircleColor,
  179. mFingerOnColor,mFingerUpColor);
  180. mGestureLockViews[i].setId(i+1);
  181. //设置参数,主要是定位GestureLockView间的位置
  182. RelativeLayout.LayoutParamslockerParams=newRelativeLayout.LayoutParams(
  183. mGestureLockViewWidth,mGestureLockViewWidth);
  184. //不是每行的第一个,则设置位置为前一个的右边
  185. if(i%mCount!=0)
  186. {
  187. lockerParams.addRule(RelativeLayout.RIGHT_OF,
  188. mGestureLockViews[i-1].getId());
  189. }
  190. //从第二行开始,设置为上一行同一位置View的下面
  191. if(i>mCount-1)
  192. {
  193. lockerParams.addRule(RelativeLayout.BELOW,
  194. mGestureLockViews[i-mCount].getId());
  195. }
  196. //设置右下左上的边距
  197. intrightMargin=mMarginBetweenLockView;
  198. intbottomMargin=mMarginBetweenLockView;
  199. intleftMagin=0;
  200. inttopMargin=0;
  201. /**
  202. *每个View都有右外边距和底外边距第一行的有上外边距第一列的有左外边距
  203. */
  204. if(i>=0&&i<mCount)//第一行
  205. {
  206. topMargin=mMarginBetweenLockView;
  207. }
  208. if(i%mCount==0)//第一列
  209. {
  210. leftMagin=mMarginBetweenLockView;
  211. }
  212. lockerParams.setMargins(leftMagin,topMargin,rightMargin,
  213. bottomMargin);
  214. mGestureLockViews[i].setMode(Mode.STATUS_NO_FINGER);
  215. addView(mGestureLockViews[i],lockerParams);
  216. }
  217. Log.e(TAG,"mWidth="+mWidth+",mGestureViewWidth="
  218. +mGestureLockViewWidth+",mMarginBetweenLockView="
  219. +mMarginBetweenLockView);
  220. }
  221. }
  222. @Override
  223. publicbooleanonTouchEvent(MotionEventevent)
  224. {
  225. intaction=event.getAction();
  226. intx=(int)event.getX();
  227. inty=(int)event.getY();
  228. switch(action)
  229. {
  230. caseMotionEvent.ACTION_DOWN:
  231. //重置
  232. reset();
  233. break;
  234. caseMotionEvent.ACTION_MOVE:
  235. mPaint.setColor(mFingerOnColor);
  236. mPaint.setAlpha(50);
  237. GestureLockViewchild=getChildIdByPos(x,y);
  238. if(child!=null)
  239. {
  240. intcId=child.getId();
  241. if(!mChoose.contains(cId))
  242. {
  243. mChoose.add(cId);
  244. child.setMode(Mode.STATUS_FINGER_ON);
  245. if(mOnGestureLockViewListener!=null)
  246. mOnGestureLockViewListener.onBlockSelected(cId);
  247. //设置指引线的起点
  248. mLastPathX=child.getLeft()/2+child.getRight()/2;
  249. mLastPathY=child.getTop()/2+child.getBottom()/2;
  250. if(mChoose.size()==1)//当前添加为第一个
  251. {
  252. mPath.moveTo(mLastPathX,mLastPathY);
  253. }else
  254. //非第一个,将两者使用线连上
  255. {
  256. mPath.lineTo(mLastPathX,mLastPathY);
  257. }
  258. }
  259. }
  260. //指引线的终点
  261. mTmpTarget.x=x;
  262. mTmpTarget.y=y;
  263. break;
  264. caseMotionEvent.ACTION_UP:
  265. mPaint.setColor(mFingerUpColor);
  266. mPaint.setAlpha(50);
  267. this.mTryTimes--;
  268. //回调是否成功
  269. if(mOnGestureLockViewListener!=null&&mChoose.size()>0)
  270. {
  271. mOnGestureLockViewListener.onGestureEvent(checkAnswer());
  272. if(this.mTryTimes==0)
  273. {
  274. mOnGestureLockViewListener.onUnmatchedExceedBoundary();
  275. }
  276. }
  277. Log.e(TAG,"mUnMatchExceedBoundary="+mTryTimes);
  278. Log.e(TAG,"mChoose="+mChoose);
  279. //将终点设置位置为起点,即取消指引线
  280. mTmpTarget.x=mLastPathX;
  281. mTmpTarget.y=mLastPathY;
  282. //改变子元素的状态为UP
  283. changeItemMode();
  284. //计算每个元素中箭头需要旋转的角度
  285. for(inti=0;i+1<mChoose.size();i++)
  286. {
  287. intchildId=mChoose.get(i);
  288. intnextChildId=mChoose.get(i+1);
  289. GestureLockViewstartChild=(GestureLockView)findViewById(childId);
  290. GestureLockViewnextChild=(GestureLockView)findViewById(nextChildId);
  291. intdx=nextChild.getLeft()-startChild.getLeft();
  292. intdy=nextChild.getTop()-startChild.getTop();
  293. //计算角度
  294. intangle=(int)Math.toDegrees(Math.atan2(dy,dx))+90;
  295. startChild.setArrowDegree(angle);
  296. }
  297. break;
  298. }
  299. invalidate();
  300. returntrue;
  301. }
  302. privatevoidchangeItemMode()
  303. {
  304. for(GestureLockViewgestureLockView:mGestureLockViews)
  305. {
  306. if(mChoose.contains(gestureLockView.getId()))
  307. {
  308. gestureLockView.setMode(Mode.STATUS_FINGER_UP);
  309. }
  310. }
  311. }
  312. /**
  313. *
  314. *做一些必要的重置
  315. */
  316. privatevoidreset()
  317. {
  318. mChoose.clear();
  319. mPath.reset();
  320. for(GestureLockViewgestureLockView:mGestureLockViews)
  321. {
  322. gestureLockView.setMode(Mode.STATUS_NO_FINGER);
  323. gestureLockView.setArrowDegree(-1);
  324. }
  325. }
  326. /**
  327. *检查用户绘制的手势是否正确
  328. *@return
  329. */
  330. privatebooleancheckAnswer()
  331. {
  332. if(mAnswer.length!=mChoose.size())
  333. returnfalse;
  334. for(inti=0;i<mAnswer.length;i++)
  335. {
  336. if(mAnswer[i]!=mChoose.get(i))
  337. returnfalse;
  338. }
  339. returntrue;
  340. }
  341. /**
  342. *检查当前左边是否在child中
  343. *@paramchild
  344. *@paramx
  345. *@paramy
  346. *@return
  347. */
  348. privatebooleancheckPositionInChild(Viewchild,intx,inty)
  349. {
  350. //设置了内边距,即x,y必须落入下GestureLockView的内部中间的小区域中,可以通过调整padding使得x,y落入范围不变大,或者不设置padding
  351. intpadding=(int)(mGestureLockViewWidth*0.15);
  352. if(x>=child.getLeft()+padding&&x<=child.getRight()-padding
  353. &&y>=child.getTop()+padding
  354. &&y<=child.getBottom()-padding)
  355. {
  356. returntrue;
  357. }
  358. returnfalse;
  359. }
  360. /**
  361. *通过x,y获得落入的GestureLockView
  362. *@paramx
  363. *@paramy
  364. *@return
  365. */
  366. privateGestureLockViewgetChildIdByPos(intx,inty)
  367. {
  368. for(GestureLockViewgestureLockView:mGestureLockViews)
  369. {
  370. if(checkPositionInChild(gestureLockView,x,y))
  371. {
  372. returngestureLockView;
  373. }
  374. }
  375. returnnull;
  376. }
  377. /**
  378. *设置回调接口
  379. *
  380. *@paramlistener
  381. */
  382. publicvoidsetOnGestureLockViewListener(OnGestureLockViewListenerlistener)
  383. {
  384. this.mOnGestureLockViewListener=listener;
  385. }
  386. /**
  387. *对外公布设置答案的方法
  388. *
  389. *@paramanswer
  390. */
  391. publicvoidsetAnswer(int[]answer)
  392. {
  393. this.mAnswer=answer;
  394. }
  395. /**
  396. *设置最大实验次数
  397. *
  398. *@paramboundary
  399. */
  400. publicvoidsetUnMatchExceedBoundary(intboundary)
  401. {
  402. this.mTryTimes=boundary;
  403. }
  404. @Override
  405. publicvoiddispatchDraw(Canvascanvas)
  406. {
  407. super.dispatchDraw(canvas);
  408. //绘制GestureLockView间的连线
  409. if(mPath!=null)
  410. {
  411. canvas.drawPath(mPath,mPaint);
  412. }
  413. //绘制指引线
  414. if(mChoose.size()>0)
  415. {
  416. if(mLastPathX!=0&&mLastPathY!=0)
  417. canvas.drawLine(mLastPathX,mLastPathY,mTmpTarget.x,
  418. mTmpTarget.y,mPaint);
  419. }
  420. }
  421. publicinterfaceOnGestureLockViewListener
  422. {
  423. /**
  424. *单独选中元素的Id
  425. *
  426. *@paramposition
  427. */
  428. publicvoidonBlockSelected(intcId);
  429. /**
  430. *是否匹配
  431. *
  432. *@parammatched
  433. */
  434. publicvoidonGestureEvent(booleanmatched);
  435. /**
  436. *超过尝试次数
  437. */
  438. publicvoidonUnmatchedExceedBoundary();
  439. }
  440. }

注释极其详细,用极其不过分~主要就是onTouchEvent中对用户选择的GestureLockView进行判断,以及改变GestureLockView状态等。

5、布局文件

[html] view plain copy
  1. <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. xmlns:zhy="http://schemas.android.com/apk/res/com.zhy.zhy_gesturelockview"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent">
  6. <com.zhy.zhy_gesturelockview.view.GestureLockViewGroup
  7. android:id="@+id/id_gestureLockViewGroup"
  8. android:layout_width="match_parent"
  9. android:layout_height="match_parent"
  10. android:background="#F2F2F7"
  11. android:gravity="center_vertical"
  12. zhy:count="3"
  13. zhy:tryTimes="5"/>
  14. <!--zhy:color_no_finger_inner_circle="#ff085D58"
  15. zhy:color_no_finger_outer_circle="#ff08F0E0"
  16. zhy:color_finger_on="#FF1734BF"-->
  17. </RelativeLayout>

有兴趣的可以自定义属性,把注释的代码添进去就行,当然你也可以什么都不设置,单纯设置宽度和高度,我觉得默认效果也是不错的 ~

6、调用

[java] view plain copy
  1. packagecom.zhy.zhy_gesturelockview;
  2. importandroid.app.Activity;
  3. importandroid.os.Bundle;
  4. importandroid.widget.Toast;
  5. importcom.zhy.zhy_gesturelockview.view.GestureLockViewGroup;
  6. importcom.zhy.zhy_gesturelockview.view.GestureLockViewGroup.OnGestureLockViewListener;
  7. publicclassMainActivityextendsActivity
  8. {
  9. privateGestureLockViewGroupmGestureLockViewGroup;
  10. @Override
  11. protectedvoidonCreate(BundlesavedInstanceState)
  12. {
  13. super.onCreate(savedInstanceState);
  14. setContentView(R.layout.activity_main);
  15. mGestureLockViewGroup=(GestureLockViewGroup)findViewById(R.id.id_gestureLockViewGroup);
  16. mGestureLockViewGroup.setAnswer(newint[]{1,2,3,4,5});
  17. mGestureLockViewGroup
  18. .setOnGestureLockViewListener(newOnGestureLockViewListener()
  19. {
  20. @Override
  21. publicvoidonUnmatchedExceedBoundary()
  22. {
  23. Toast.makeText(MainActivity.this,"错误5次...",
  24. Toast.LENGTH_SHORT).show();
  25. mGestureLockViewGroup.setUnMatchExceedBoundary(5);
  26. }
  27. @Override
  28. publicvoidonGestureEvent(booleanmatched)
  29. {
  30. Toast.makeText(MainActivity.this,matched+"",
  31. Toast.LENGTH_SHORT).show();
  32. }
  33. @Override
  34. publicvoidonBlockSelected(intcId)
  35. {
  36. }
  37. });
  38. }
  39. }

调用是不是so easy,懒得看代码又需要用的,可以直接拿来使用,等哪天闲着蛋疼可以研究研究代码~


ok,有任何问题的留言~


源码明天到公司贴出来吧,尼玛,这是拿手机共享的热点写的,我的流量啊~~~~还好是1号~

源码点击下载




更多相关文章

  1. 记录状态栏与布局重合,状态栏颜色问题
  2. Android沉浸式状态栏实现
  3. android 3g状态及信号监测
  4. Android为Layout设置最大宽度
  5. Android获取状态栏、标题栏、ActionBar以及屏幕的高度
  6. Android状态栏上添加按钮
  7. Android获取屏幕的高度和宽度
  8. android去掉layout顶部的阴影(状态栏下边的阴影)
  9. Android 状态栏和应用标题栏颜色保持一致

随机推荐

  1. Go语言学习6-字典类型
  2. Go语言学习5-切片类型
  3. 关于OpenGL游戏全屏模式的设置
  4. VsCode常用设置,新手必备!
  5. 教你用Python爬虫自制有道翻译词典
  6. Go语言学习4-数组类型
  7. 《游戏程序设计模式》 2.2 - 游戏循环
  8. 网页游戏用的什么编程语言
  9. MySql基础语法的学习-基础的查询语句
  10. SpringBoot+Vue3前后端分离,实战wiki知识