自定义view学习-创建自己的九宫格解锁view
来源:互联网 发布:淘宝权现在在哪里直播 编辑:程序博客网 时间:2024/04/27 12:30
先上效果图
效果如上,接下来是如何实现,并没有那么快上代码,不看代码不舒服的请迅速下翻。
九宫格解锁还是比较经典的,作为学习自定义view的入门。
对于九宫格解锁,我的实现思路是这样的:
1.先在屏幕上绘制一个正方形,就是上面草图中间的正方形。
2.将这个正方形纵向横向三等分,分为九个小正方形,分别序号1-9…
3.每个小正方形以1/3边长为半径画出圆,这时候我们已经有了基本的样子。
4.接下来是触屏事件的处理,把所有的触屏坐标减去大正方形的坐上点,就是以大正方形起始点为坐标原点。
private int whichPath(int x,int y){ if(x>startX+width | y>startY+width |x<startX |y<startY){ // Log.i("xy",x+"-"+y); return 0; }else { //以起始点开始计算坐标 int nX=x-startX; int nY=y-startY; int hang=(int)nY/tWidth;//在哪行,从零开始 int lie=(int)nX/tWidth;//在哪列,从零开始 // Log.i("nXY",nX+"-"+nY); int reInt= hang*3+1+lie; //缩小判断区域 int smallY=(tWidth/6)+hang*tWidth; int smallX=(tWidth/6)+lie*tWidth; if (nX>smallX && nY>smallY && nX<(smallX+2*tWidth/3) && nY<(smallY+2*tWidth/3)){ return reInt; }else{ return 0; } } }//which我用以上的方法判断坐标所在区域,并且把判断区域缩小范围,留出足够的空间进行斜向连线。
就是原来的范围为每个小正方形,我把他判定范围缩减到草图中一号位圆圈外的黑色方框以内。
5.当触屏移动,坐标改变。调用上面方法判断在哪个区域,如果进入了合法区域就记录在结果集list中。
不管坐标在不在合法区域,需要把list中的最后一个区域的圆心跟当前移动的点连接,画一条直线。
然后循环取出结果集的区域圆心,两两连线,把结果集中的所有圆圈变为红色。
6.最后,绘制解锁图案完成后提供接口回调。
思路看完,下面是主要代码:(为了方便给代码,我省略了attr的操作,可自行扩展)
package com.toxicant.hua.nicepathsunlock;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Point;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.View;import java.util.ArrayList;import java.util.List;/** * Created by hua on 2016/1/31. */public class NinePathsView extends View{ private Paint mPaint=new Paint();//画笔 private Paint mRedPaint=new Paint(); private int startX=0;// private int startY=0;// private Point touchPoint=new Point(0,0);//当前触控点 private int width=0;//大正方形的边长 private int tWidth=0;//九个小正方形的边长 private int nowP=0;//当前所在区域 private List<Point> pointList=new ArrayList<>();//存放圆心的list private volatile List<Integer> resultList=new ArrayList<>();//存放结果的list private boolean isUnLock=false; private DrawFinishListener mListener; //绘制完成的接口 interface DrawFinishListener{ void finish(List<Integer> resultList); } public NinePathsView(Context context) { super(context); } public NinePathsView(Context context, AttributeSet attrs) { super(context, attrs); } public NinePathsView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //此处获取自定义属性 } @Override protected void onDraw(Canvas canvas) { width=Math.min(getMeasuredHeight(),getMeasuredWidth());//获取正方形区域边长// Log.i("width",""+width); //获取起始绘制点 startY=(getMeasuredHeight()-width)/2; startX=(getMeasuredWidth()-width)/2; //绘制大正方形 mPaint.setColor(Color.WHITE); canvas.drawRect(startX, startY, startX + width, startY + width, mPaint); //设置画笔 mPaint.setColor(Color.BLUE); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(3); mRedPaint.setColor(Color.RED); mRedPaint.setStyle(Paint.Style.STROKE); mRedPaint.setStrokeWidth(3); //三等分正方形 tWidth=width/3; pointList.clear(); for(int j=0;j<3;j++){ int tY=startY+j*tWidth+tWidth/2; for(int k=0;k<3;k++){ int tX=startX+k*tWidth+tWidth/2; canvas.drawCircle(tX, tY, 2, mPaint); //此处已连接的点要变色 canvas.drawCircle(tX, tY, tWidth / 3, mPaint); pointList.add(new Point(tX,tY));//圆心存入list } } //连线已连接的点 for (int i=1;i<resultList.size();i++){ int back =resultList.get(i-1); Point backP=pointList.get(back-1);//上一个圆心 int now=resultList.get(i); Point nowP=pointList.get(now-1); canvas.drawLine(backP.x,backP.y,nowP.x,nowP.y,mRedPaint); } for (int i:resultList){ Point nowP=pointList.get(i-1); canvas.drawCircle(nowP.x,nowP.y,tWidth / 3,mRedPaint); } //如果正在连线,把最后一个圆心点和现在触控的点连接 if(isUnLock){ int last=resultList.get(resultList.size()-1); Point lastP=pointList.get(last-1); canvas.drawLine(lastP.x,lastP.y,touchPoint.x,touchPoint.y,mRedPaint); } }//draw @Override public boolean onTouchEvent(MotionEvent event) { int x= (int) event.getRawX(); int y= (int) event.getRawY(); //坐标转换 int[] location = new int[2] ; getLocationInWindow(location); //获取在当前窗口内的绝对坐标 //getLocationOnScreen(location);//获取在整个屏幕内的绝对坐标 //location [0]--->x坐标,location [1]--->y坐标 x=x-location [0]; y=y-location [1]; // Log.e("绝对坐标",x+"--"+y); int which=whichPath(x,y); switch (event.getAction()){ case MotionEvent.ACTION_DOWN:// Log.i("which","->"+which); resultList.clear();//开始下一次绘制前清空结果集 isUnLock=true; break; case MotionEvent.ACTION_MOVE: if (which!=nowP && which!=0){//移动到了另一个合法区域 nowP=which;//更改当前区域 if(!resultList.contains(which)){//确保没进入过此区域 resultList.add(which); } } //记录当前触控点并请求重绘 touchPoint.set(x,y); invalidate(); break; case MotionEvent.ACTION_UP: //完成绘制解锁图后 nowP=0; isUnLock=false; Log.i("result",resultList.toString()); if(mListener!=null){ mListener.finish(resultList); } rePlay(); break; } return true; }//touch private int whichPath(int x,int y){ if(x>startX+width | y>startY+width |x<startX |y<startY){ // Log.i("xy",x+"-"+y); return 0; }else { //以起始点开始计算坐标 int nX=x-startX; int nY=y-startY; int hang=(int)nY/tWidth;//在哪行,从零开始 int lie=(int)nX/tWidth;//在哪列,从零开始 // Log.i("nXY",nX+"-"+nY); int reInt= hang*3+1+lie; //缩小判断区域 int smallY=(tWidth/6)+hang*tWidth; int smallX=(tWidth/6)+lie*tWidth; if (nX>smallX && nY>smallY && nX<(smallX+2*tWidth/3) && nY<(smallY+2*tWidth/3)){ return reInt; }else{ return 0; } } }//which public void rePlay(){ resultList.clear(); isUnLock=false; invalidate(); }//rePlay void setDrawFinishListener(DrawFinishListener l){ this.mListener=l; }}//class调用自定义view的方法依然是这样的:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.toxicant.hua.nicepathsunlock.MainActivity"> <com.toxicant.hua.nicepathsunlock.NinePathsView android:id="@+id/view" android:layout_height="match_parent" android:layout_width="match_parent" android:layout_centerVertical="true" android:layout_centerHorizontal="true"> </com.toxicant.hua.nicepathsunlock.NinePathsView></RelativeLayout>直接作为普通组件调用。
在代码中进行回调:
package com.toxicant.hua.nicepathsunlock;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.widget.Toast;import java.util.List;public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); NinePathsView mView= (NinePathsView) findViewById(R.id.view); mView.setDrawFinishListener(new NinePathsView.DrawFinishListener() { @Override public void finish(List<Integer> resultList) { Toast.makeText(MainActivity.this,resultList.toString(),Toast.LENGTH_SHORT).show(); } }); }}回调的是一个List<Integer>类型,可以直接调用tostring来保存,比较密码,也可直接通过size来密码限制最小长度。
1 0
- 自定义view学习-创建自己的九宫格解锁view
- android自定义view之九宫格解锁
- android自定义view之九宫格解锁
- android简单的九宫格解锁view
- 自定义View----Android九宫格手势密码解锁
- 九点(九宫格)式手势解锁自定义view
- android 自定义view实现九宫格手势解锁
- 九点(九宫格)式手势解锁自定义view
- 自定义View----Android九宫格手势密码解锁
- 自定义view之九宫格手势解锁空间
- 自定义View九宫格手势
- 自定义View--九宫格手势
- Android进阶之自定义View实战(二)九宫格手势解锁实现
- 自己用View实现九宫格
- 自己学习自定义view的一些总结
- 自定义View之--九宫格图形密码锁
- 自定义view解锁
- 自定义View实现解锁
- 首页banner广告图片轮换超炫效果代码
- 杭电2391Filthy Rich(动态规划)
- android 逆向 初级系列(二)
- RDLC 报表系列(四) 子报表的使用
- 相关矩阵到相似矩阵--Ochiia系数
- 自定义view学习-创建自己的九宫格解锁view
- 学习Python语言---函数
- 开源库链接收藏
- delphi中webbrowser的用法
- 掌握需求过程
- 查找 4
- 【Java Socket】入门系列 3.3.通过 Socket 实现 TCP 编程 — 使用多线程实现多客户端通信
- Log4j动态日志配置切换并立即生效
- mysql-5.6.27-winx64 achieve 配置