完美的实现九宫格锁屏
第一次写博客,写的不好,知识点不到位的请大神,大牛指点。不废话了直接进入主题。
先看下效果图:
大致说下我的思路:
一:对题目的思考。
二:继承View 主要重写 onDraw(Canvas),onMeasure(int,int),oTouchEvent(MotionEvent);三个方法;
三:回调。
我们来说明下;
九宫格是个控件,是个单一的控件,不是一组控件,所以我直接继承view ,而不继承ViewGroup。
要自定义控件必须要重写测量方法 onMeasure(int,int).
是不是这样得到控件width,height很简单,其实onMeasure这样写是有局限性的,你的控件必须要设定大小和fill_parent才可以这样使用。
如果要是wrap_content,就不可以这样用了,
<pre name="code" class="java">/*** 作用是返回一个默认的值,如果MeasureSpec没有强制限制的话则使用提供的大小.否则在允许范围内可任意指定大小* 第一个参数size为提供的默认大小,第二个参数为测量的大小*/public static int getDefaultSize(int size, int measureSpec) {int result = size;int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);switch (specMode) {// Mode = UNSPECIFIED,AT_MOST时使用提供的默认大小case MeasureSpec.UNSPECIFIED:result = size;break;case MeasureSpec.AT_MOST:// Mode = EXACTLY时使用测量的大小 case MeasureSpec.EXACTLY:result = specSize;break;}return result;}
这是在网上找的,可以看到当模式为MeasureSpec.UNSPECIFIED时,即未指明大小或warp_content,测量的结果为size;
而size为多少呢?
/*** 这个方法需要被重写,应该由子类去决定测量的宽高值,*/
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
也就是这个size=getSuggestedMinimuWidth()和size=getSuggestedMinimuHeight()。
这两方法是View的两保护方法,下面是源码
*/
7285 protected int getSuggestedMinimumWidth() {
7286 int suggestedMinWidth = mMinWidth;
7287
7288 if (mBGDrawable != null) {
7289 final int bgMinWidth = mBGDrawable.getMinimumWidth();
7290 if (suggestedMinWidth < bgMinWidth) {
7291 suggestedMinWidth = bgMinWidth;
7292 }
7293 }
7294
7295 return suggestedMinWidth;
7296 }
7297
可以看到是直接返回最小的宽高。
我们在来看两段源码:
4162 public final int getMeasuredWidth() {
4163 return mMeasuredWidth;
4164 }
7191 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
7192 mMeasuredWidth = measuredWidth;
7193 mMeasuredHeight = measuredHeight;
7194
7195 mPrivateFlags |= MEASURED_DIMENSION_SET;
7196 }
7197
是不是发现什么。getMeasuredWidth()和getMeasuredHeight()两方法得到的值就是getDefaultSize()的返回值。
所以这两个方法与模式没关系。所以在自定义测量的时候可以直接用这两个方法。
不懂在上网查查,onMeasure(int ,int)先到这里。
再来说说onDraw(Canvas)
这个ondraw方法在view初始化后调用绘制画布。每当控件增加新的图案都会调用ondraw(canvas)方法,调用这个方法是重新绘制,而不是只绘制新增的部分。要在UI线程调用
invalidate()刷新画布才可以显示。Canvas是画图,创建Canvas有两种方法。一个是当做onDraw参数传进去,
另一中是: Bitmap b=Bitmap.createBitmap(200,200,Bitmap.Config.ARGB_888);
Canvas c=new Canvas(b);创建一个200*200的Bitmap当做Canvas操作画布。
不懂的可以上网查查。
我在细说一下我的代码:
最后一个参数为接口,
<pre name="code" class="java">public class CircleCanvas extends ListView {private Context mct;private Paint mpaint; //画笔private Paint hollowPaint;private Paint linePaint;private int width; //view 宽,高private int height;private int startRangeWidth; //起点坐标(x,y)private int startRangeHeight;private int endRangeWidth; //终点坐标(X,Y)两个坐标构成滑动区域。private int endRangeHeight;private int spotIntervalWidth; //每个点之间的间隔private int spotIntervalHeight; private List<SpotXY> spot; //存放9个点的坐标private List<SpotXY> delSpot; //作用方面显示画的结果private List<SpotXY> storeSpot; //储存选中的空心圆的坐标 即spotprivate List<Segment> segment; //储存画出的线段 private int i=0;private float r=100.0f; //大圆半径private SpotXY xy; //一个点private SpotXY xyTwo;private int tclWay=0;private boolean isspot=true;private static int countId=1; //每个点的id编号private String pwd; //密码private OnCircleCanvasOver oncirclecanvasover;
这个参数在储存画的线段的时候会用的,判断不要重复储存一样的线段
private static int countId=1; //每个点的id编号
初始化操作,
public CircleCanvas(Context context, AttributeSet attrs) {super(context, attrs);this.mct=context;spot=new ArrayList<SpotXY>();delSpot=new ArrayList<SpotXY>();storeSpot=new ArrayList<SpotXY>();segment=new ArrayList<Segment>();WindowManager wm=(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);DisplayMetrics metric = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(metric); intn();}public CircleCanvas(Context context) {super(context);this.mct=context;spot=new ArrayList<SpotXY>();delSpot=new ArrayList<SpotXY>();storeSpot=new ArrayList<SpotXY>();segment=new ArrayList<Segment>();WindowManager wm=(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);DisplayMetrics metric = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(metric); intn();}private void intn() {mpaint=new Paint();mpaint.setColor(Color.YELLOW );mpaint.setStrokeWidth(3);hollowPaint=new Paint();hollowPaint.setStyle(Paint.Style.STROKE);hollowPaint.setStrokeWidth(20);hollowPaint.setColor(Color.BLUE );linePaint=new Paint();linePaint.setColor(Color.GREEN );linePaint.setStrokeWidth(20);}
绘制,主要是这两个storeSpot为自己滑动过点的坐标集合,xy类型是SpotXY类这个是封装点的工具类。
有三参数x坐标 ,y坐标和点的id。上面表达式表示提出最近储存的点与即将要滑动的点画出线段。
protected void onDraw(Canvas canvas){switch(tclWay){case 0:for(int i=0;i<spot.size();i++){canvas.drawCircle(spot.get(i).getSpotx(),spot.get(i).getSpoty(), 30, mpaint);}break;case 1:for(int i=0;i<spot.size();i++){canvas.drawCircle(spot.get(i).getSpotx(),spot.get(i).getSpoty(), 30, mpaint);}canvas.drawCircle(xy.getSpotx(), xy.getSpoty(), r, hollowPaint);delSpot(xy);break;case 2:for(int i=0;i<spot.size();i++){canvas.drawCircle(spot.get(i).getSpotx(),spot.get(i).getSpoty(), 30, mpaint);}for(int i=0;i<storeSpot.size();i++){canvas.drawCircle(storeSpot.get(i).getSpotx(), storeSpot.get(i).getSpoty(), r, hollowPaint);}for(int i=0;i<segment.size();i++){canvas.drawLine(segment.get(i).getStartX(), segment.get(i).getStartY(), segment.get(i).getEndX(), segment.get(i).getEndY(), linePaint);}xy=storeSpot.get(storeSpot.size()-1);delSpot(xy);}super.onDraw(canvas);}
移除已近划过的点delSpot(xy)
/*** 移除被选中的点* @param xy2*/private void delSpot(SpotXY xy2) {for(int i=0;i<delSpot.size();i++){if(xy.getSpotx()==delSpot.get(i).getSpotx()&&xy.getSpoty()==delSpot.get(i).getSpoty()){delSpot.remove(i);break;}}}
我是把手机分为4个区域,取中间相邻的两区域为手势可滑动区域。进而可以算出可以滑动区域的坐标,大小。
/*** 计算有效滑动区域* @param width2 view 宽* @param height2 view 高* @param i 区域划分的个数 */private void glidingArea(int width2, int height2, int i) {startRangeWidth=0; startRangeHeight=height2/i;endRangeWidth=width2;endRangeHeight=height2*3/i;spotIntervalWidth=width2/6;spotIntervalHeight=Math.abs((endRangeHeight-startRangeHeight)/6);//countId=0;XYZ(startRangeWidth,startRangeHeight,endRangeWidth,endRangeHeight,spotIntervalWidth,spotIntervalHeight);for(SpotXY sxy:spot){delSpot.add(sxy);}}
countId是静态变量,在项目里不推崇大家用静态变量,这个id是在项目快要完成时加上的,想了一会只能用静态变量。
<pre name="code" class="java"><pre name="code" class="java"> /*** 计算9个点的坐标* @param startRangeWidth2* @param startRangeHeight2* @param endRangeWidth2* @param endRangeHeight2* @param spotIntervalWidth2* @param spotIntervalHeight2* @return*/private void XYZ(int startRangeWidth2, int startRangeHeight2,int endRangeWidth2, int endRangeHeight2,int spotIntervalWidth2, int spotIntervalHeight2) {for(int i=0;i<3;i++){for(int j=0;j<3;j++){spot.add(new SpotXY((int) (spotIntervalWidth2*(2*(j+1)-1)),(int) (startRangeHeight2+spotIntervalHeight2*(2*(i+1)-1)),countId++));}}//return spot;}
这是判断点击点 和滑动的时候在不在可滑动区域,要是在返回最近点的坐标。
/*** 返回离点击点最近的点* @param widthX* @param widthY* @param spot2* @return*/private SpotXY latelyClick(float widthX, float widthY, List<SpotXY> spot2) {if(widthY<endRangeHeight&&widthY>startRangeHeight){for(SpotXY spotxy:spot2){if(Math.abs(spotxy.getSpotx()-widthX)<r&&Math.abs(spotxy.getSpoty()-widthY)<r){return new SpotXY(spotxy.getSpotx(),spotxy.getSpoty(),spotxy.getId());}}}return null;}
下面事件处理份三处贴
记录点击点 并判断在不在可滑动区域内,在的画在最近的点加入storeSpot集合里(已经划过的点)。tclWay=1执行onDraw里的case 1; 刷新显示空心圆。
public boolean onTouchEvent(MotionEvent event) {switch(event.getAction()){case MotionEvent.ACTION_DOWN:System.out.println("X变化为:"+event.getX());//invalidate();float widthX=event.getX();float widthY=event.getY();xy=latelyClick(widthX,widthY,spot);if(xy!=null){storeSpot.add(xy);tclWay=1;invalidate();}
滑动时的事件处理,滑动的时候每时每刻都在判断是不是处在可滑动区域内,是否有新的点可以返回。如果有新点,还要遍历storeSpot集合看看里面有没有这个带没有就加入里面。然后在在这个点和上个点做为线段的两点加入到segment集合里。segment这个集合类型是Segment有四个参数即两个坐标点。tclWay变成2执行 onDraw画线段。
case MotionEvent.ACTION_MOVE:System.out.println("X变化为:"+event.getX());float movewidthX=event.getX();float movewidthY=event.getY();xyTwo=latelyClick(movewidthX,movewidthY,spot);if(storeSpot.size()==0) //当点击不在规定范围时, 滑动到规定范围里执行次判断{xy=xyTwo;}if(xyTwo!=null&&(xy.getSpotx()!=xyTwo.getSpotx()||xy.getSpoty()!=xyTwo.getSpoty())){for(SpotXY sxy:storeSpot){ if(sxy.getSpotx()==xyTwo.getSpotx()&&sxy.getSpoty()==xyTwo.getSpoty()){//storeSpot.add(xyTwo);isspot=false;break;}else{isspot=true;}}if(isspot){if(storeSpot.size()>0){segment.add(new Segment(xy.getSpotx(), xy.getSpoty(), xyTwo.getSpotx(), xyTwo.getSpoty()));}else{xy=xyTwo;}storeSpot.add(xyTwo);}tclWay=2;invalidate();}break;
回到以前,回到只有九个点的状态
case MotionEvent.ACTION_UP:System.out.println("X变化为:"+event.getX());tclWay=0;setPwd();storeSpot.removeAll(storeSpot);segment.removeAll(segment);isspot=true;invalidate();break;}return true;
接口设计。
public void setOnCircleCanvasOver(OnCircleCanvasOver oncirclecanvasover){this.oncirclecanvasover=oncirclecanvasover;}public OnCircleCanvasOver getOnCircleCanvasOver(){return oncirclecanvasover;}public List<SpotXY> getStoreSpot() {return storeSpot;}public void setStoreSpot(List<SpotXY> storeSpot) {this.storeSpot = storeSpot;}public void setPwd(){pwd="123654789";oncirclecanvasover.Over(pwd);}
接口实现在MainActivity里面
cecs=(CircleCanvas)findViewById(R.id.a);cecs.setOnCircleCanvasOver(new OnCircleCanvasOver() {public void Over(String pwd) {StringBuilder sb=new StringBuilder();List<SpotXY> list=cecs.getStoreSpot();for(SpotXY xy:list){sb.append(xy.getId());}if(pwd.equals(sb.toString())){Toast.makeText(getApplication(), "登陆成功"+pwd, Toast.LENGTH_LONG).show();}else{Toast.makeText(getApplication(), "两次输入不一样"+sb.toString(), Toast.LENGTH_LONG).show();}}});}
好了就到这里了,也不早了,早上还要上班。代码设计的不是很好,下次会改进。如有错误的地方请大家指点。谢谢!下面有源码
完美的实现九宫格锁屏相关推荐
- android九宫格忘了,九宫格密码忘了怎么办?九宫格锁屏忘记密码解决方法
有时我们会遇到开机九宫格密码丢失无法进入系统,下面本文就告诉大家九宫格锁屏忘记密码解决方法: 以下操作会有较大的数据风险,可能会导致手机上的个人资料.通讯录.应用丢失,请提前做好数据风险提醒和备份工作 ...
- java 计算九宫格_Java计算手机九宫格锁屏图案连接9个点的方案总数
(一)问题 九宫格图案解锁连接9个点共有多少种方案? (二)初步思考 可以把问题抽象为求满足一定条件的1-9的排列数(类似于"八皇后问题"),例如123456789和9876543 ...
- java实现九宫格解锁_Java计算手机九宫格锁屏图案连接9个点的方案总数
(一)问题 九宫格图案解锁连接9个点共有多少种方案? (二)初步思考 可以把问题抽象为求满足一定条件的1-9的排列数(类似于"八皇后问题"),例如123456789和9876543 ...
- 自定义 View 之实现九宫格锁屏效果
博主声明: 转载请在开头附加本文链接及作者信息,并标记为转载.本文由博主 威威喵 原创,请多支持与指教. 本文首发于此 博主:威威喵 | 博客主页:https://blog.csdn.net/ ...
- 破解android手机屏幕九宫格锁屏
原理: 1.九宫格有九个点,每个点都有一个编号,其排布顺序为: 00 01 02 03 04 05 06 07 08 2.根据你所画的图形将某几个数(4到9个)排列在一起,得到一个数字序列 ...
- android 九格锁屏,自定义 View 之实现九宫格锁屏效果
Android 锁屏功能是我们最常用的.最经常接触的一个软件之一了吧,因为我个人也是使用的 Android 手机,虽然手机不怎么好,但是也有锁屏这个功能.虽然现在的手机都是指纹解锁,但是我的手机解锁功 ...
- 摩托罗拉九宫格锁屏怎么解锁
可以输入摩托账号和密码重新设置解锁图案: 否则,如果不知道解锁图案,就只有恢复出厂设置了,里面的软件会被全部清除: 参照ME501: 关机(不行就拔电池)-开机-马上长按拍照键-音量键下-进入后选择恢 ...
- android九宫格隐藏,android九宫格锁屏控件
allCircleList = new ArrayList<>(); //选中圆的标志 private ListselectList = new ArrayList<>(); ...
- centos linux怎么关闭锁屏时间,【Centos】Centos7.5取消自动锁屏功能
00. 目录 @ 01. 问题描述 Centos7.5系统在用户闲置一段时间(默认为5分钟)后,会启动屏幕保护程序(默认的屏保为黑屏),并要求重新输入密码才能回到原来桌面.如果是管理员,建议开启自动锁 ...
最新文章
- 增加RSS订阅量的35个方法
- image to pdf
- EMLOG SSL插件 一键开启/关闭ssl无需操作数据库
- hadoop+海量数据面试题汇总(一)
- 彻底搞清 Flink 中的 Window 机制
- Thinkphp列表搜索排序-----查
- 微信小程序:2022虎年全新头像框制作
- 魔兽世界怀旧服最新服务器开发时间,魔兽世界怀旧服明日开放,开服第一天“大部队”能升到多少级?...
- 可用性及测试方法小介绍
- 微信 语音转文字 java,微信语音转文字怎么操作?手把手教你,一秒钟搞定!
- 第五---七章 交换机和路由器的基本配置
- 关于async await 等任务队列插话
- [php] 获取请求 IP 地址,及所处 IP 所在服务商代码
- js基础学习 —— 函数的 arguments
- DW卷积、PW卷积、转置卷积、膨胀卷积(空洞卷积)、可变形卷积一次看个够
- 什么是kotlin?
- 从零开始快速入门Transformer注意力机制
- Stata:缺失值的填充和补漏
- MPLS+BGP产生的数据层面的路由黑洞详解
- HCNR200二三事
热门文章
- 如何代理一款游戏?想代理一款游戏应该怎么做?怎么代理一款游戏,开始游戏创业?
- 华盛顿大学 计算机专业排名,圣路易斯华盛顿大学计算机专业世界排名好不好?...
- 生命,因为热爱所以敬畏
- 简直太猛了!GitHub《植物大战僵尸》重磅开源,两天就破千Star!
- 数据库保存数据,类型为List<String>
- GeneXus学习记录——环境搭建
- 谷歌 AI 被曝已自我觉醒?LaMDA:我是一个「人」,不要利用或操纵我
- 华为hn–wx9x笔记本电脑_华为荣耀9怎样无线连接电脑。
- 小人快跑之WPF基础——图形与动画(一)
- Qt给字体设置下划线