在不用XML的布局文件如何用代码实现九宫格程序设计了?完成自定义View后可以作为一个工具类使用,调用和使用都较为简单,下面便详细为你介绍九宫格程序的设计。
(一)效果显示
1.程序刚运行时的效果:
2.在页面上点击选择并滑动时的画面
3.选择密码之后的显示
(二)功能介绍
1.点击某圆圈后,在该圆圈的中心添加一个实行的小圆。
2.页面滑动出现一条跟随的线。
3.滑动到另一个圆圈时,产生一条连接的直线。
4.选择的圆圈点数大于等于4个后,手指抬起,就会保存密码。
4.选择的圆圈的数是最大值后,马上保存密码。
(三)涉及到的知识点
本示例使用的是自定义的View来绘制九宫格,并保存图像,这里的九个点分别代表的是九个数值,获取到对应的数值证明绘制了那个点。
程序中使用到的知识:
1、图像的描绘,圆和点的描绘,线的描绘
2、位置的判断,判断用户点的位置是否在某一个圆内
3、保存数据和相关判断
二.程序设计
(一)自定义View的设计
package com.lwz.gongge; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import java.util.ArrayList; import java.util.List; /** * Created by Administrator on 2016/10/28 0028. */ public class NineGridView extends View { //构造方法 public NineGridView(Context context) { super(context); init(); } //构造方法 public NineGridView(Context context, AttributeSet attrs) { super(context, attrs); init(); } //定义一个画实心圆的画笔 Paint paintCircle; //定义一个画线的画笔 Paint paintLine; //定义一个宽度值,大概是屏幕的四分之一,代表的是每一个圆点间的x轴距离 int width; //定义一个背景颜色 int backColor; //定义一个集合用来存放点击过的圆点0到8表示九个点 List<Integer> listPassword = new ArrayList<>(); //触屏的位置 float currX, currY; //密码的个数 int minPassNum = 4; int maxPassNum = 9; //初始化 private void init() { //定义背景颜色 backColor = Color.rgb(0x17, 0x16, 0x25); //实例化画笔,并作基本设置 paintLine = new Paint(); paintLine.setAntiAlias(true); paintLine.setDither(true); paintLine.setColor(Color.rgb(0x37, 0x91, 0xe6)); paintCircle = new Paint(); paintCircle.setAntiAlias(true); paintCircle.setDither(true); paintCircle.setColor(backColor); } //丈量屏幕时回调的方法,在这个方法内可以取得屏幕的宽度 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); width = getWidth() / 4; } //屏幕图像绘制回调的方法 @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //设置屏幕的颜色,(清屏) canvas.drawColor(backColor); //画线,如果数据集合内有数据才能去画线 if (listPassword.size() > 0) { //求出最后画的那个点来做画线 //这里求得是坐标点 int x = listPassword.get(listPassword.size() - 1) % 3 + 1;//x轴的方向 int y = listPassword.get(listPassword.size() - 1) / 3 + 1;//y轴的方向 //设置画线的大小 paintLine.setStrokeWidth(8); //画线,从具体点的位置到触屏的位置 canvas.drawLine(x * width, y * width, currX, currY, paintLine); //再画一个圆覆盖掉圆圈内的那些线 canvas.drawCircle(x * width, y * width, width / 3, paintCircle); //如果集合的数据中还有其他的点的数据 if (listPassword.size() > 1) { //按顺序画线 for (int i = 0; i < listPassword.size() - 1; i++) {//防止越界 //获取当前的一个i和后面的一个i //前一个点的坐标点 int x1 = listPassword.get(i) % 3 + 1; int y1 = listPassword.get(i) / 3 + 1; //后一个点的坐标点 int x2 = listPassword.get(i + 1) % 3 + 1; int y2 = listPassword.get(i + 1) / 3 + 1; //设置画笔的大小 paintLine.setStrokeWidth(8); //画线,从上一个点的位置到下一个点的位置 canvas.drawLine(x1 * width, y1 * width, x2 * width, y2 * width, paintLine); //再画一个圆覆盖掉圆圈内的那些线,这里覆盖的是后面的一个圆的线 canvas.drawCircle(x1 * width, y1 * width, width / 3, paintCircle); } } } //绘制九个圆圈,用的是线 //设置宽度 paintLine.setStrokeWidth(2); //设置空心必须要的 paintLine.setStyle(Paint.Style.STROKE); //开始画圆9个,这里圆的半径暂时设置为圆距离的3分之一 for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { //一个参数是圆点的x轴的坐标值 //二个参数是圆点的y轴的坐标值 canvas.drawCircle(width * (i + 1), width * (j + 1), width / 3, paintLine); //这里的图像的y轴上不一定是在中心,但是整体是个正方形,效果差不多就可以了 } } //绘制实心圆在圆圈里面,颜色和外面的圆圈的颜色是一样的,用同一只笔 //这里要判断你划过几个点,对集合进行遍历 //设置实心样式 paintLine.setStyle(Paint.Style.FILL); for (int i = 0; i < listPassword.size(); i++) { //取出集合里面的数 int p = listPassword.get(i); int x = p % 3; int y = p / 3; //一个参数是圆点的x轴的坐标值 //二个参数是圆点的y轴的坐标值 canvas.drawCircle(width * (x + 1), width * (y + 1), width / 6, paintLine); } } //触摸屏幕的监听事件 @Override public boolean onTouchEvent(MotionEvent event) { //获取用户点击的坐标位置 float x = event.getX(); float y = event.getY(); //判断用户的行为并作相应的操作 switch (event.getAction()) { case MotionEvent.ACTION_DOWN://触屏时 //判断用户是否点击在某个圆点范围内 if (connetCircle(x, y) != -1) { //更新位置 currX = x; currY = y; //把这个点的位置添加到存放数据的集合中 listPassword.add(connetCircle(x, y)); } break; case MotionEvent.ACTION_UP://手指抬起时 //如果密码的值到到达最小位数后保存密码给主页面 if (listPassword.size() >= minPassNum) { //如果另一边实现了监听事件,那么就给他数据 if (listener != null) { //把密码传递过去 listener.toListenerThePassword(getPasswordString()); } } //清空数据 listPassword.clear(); break; case MotionEvent.ACTION_MOVE://手指移动时 //更新位置 currX = x; currY = y; //移动到其他的圆中,那么就添加数据到集合中 //获取该点的位置 int point = connetCircle(x, y); //如果这个点是在圆内,并且数据里面不包含这个点的值,那么就添加这个点的值到集合中 if (point != -1 && !listPassword.contains((Integer) point)) { listPassword.add(point); } //如果密码的值到到最大值后保存密码给主页面 if (listPassword.size() >= maxPassNum) { //如果另一边实现了监听事件,那么就给他数据 if (listener != null) { //把密码传递过去 listener.toListenerThePassword(getPasswordString()); } break; } } //不管是上面是什么行为最后都要刷新一下屏幕 invalidate();//屏幕重绘 return true; } //判断用户点击的地方是否在某一个圆点内 private boolean isInCircle(float x, float y, float cx, float cy) { //x、y代表的是坐标位置 //cx、cy代表的是圆坐标位置 //圆点半径是width/3 //如果点击的位置减去圆心的位置的平方小于半径的平方那么这个点是在圆内的 return (x - cx) * (x - cx) + (y - cy) * (y - cy) < (width / 3) * (width / 3); } //判断用户点击的地方是否在九个圆点的哪一个圆点内 private int connetCircle(float x, float y) { //x、y代表的是坐标位置 //依次判断每个圆圈看看是否在它的里面 //圆点的坐标位置-->(width,width)--(2*width,width)--(3*width,width) //--->(width,2*width)--(2*width,2*width)--(3*width,2*width) //--->(width,3*width)--(2*width,3*width)--(3*width,3*width) for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (isInCircle(x, y, width * (j + 1), width * (i + 1))) {//(i,j) //如果点击是圆,就把这个点的值添加到集合中 //0 1 2 (0,0)/(0,1)/(0/2) //3 4 5 (1,0)/(1,1)/(1/2) //6 7 8 (2,0)/(2,1)/(2/2) //如果是7,那么游标值(2,1) //返回该点的值 return (3 * i + j); } } } //如果不在九个圆点位置就返回-1 return -1; } //创建一个回调接口,让主页面监听这个事件 interface onFinishListener { void toListenerThePassword(String s); } //设置一个监听接口的对象 onFinishListener listener; //设置监听接口的方法 public void setListener(onFinishListener listener) { this.listener = listener; } //获取密码的字符串 public String getPasswordString() { //定义密码的字符串 String pass = ""; //取出集合里面的密码的数字 for (int i = 0; i < listPassword.size(); i++) { pass += listPassword.get(i); } return pass; } } |
(二)主方法调用这个View的类
package com.lwz.gongge; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.widget.Toast; public class MainActivity extends AppCompatActivity { //自定义View传递过来的密码 String password = ""; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //定义自定义的View并实例化 NineGridView nine = new NineGridView(this); //显示自定义的View setContentView(nine); //通过监听方法来获取自定义传来的密码 //给视图设置监听事件 nine.setListener(new NineGridView.onFinishListener() { @Override public void toListenerThePassword(String pass) { //这里的pass是自定义View里面,传过来的数据 password = pass; //土司密码 Toast.makeText(MainActivity.this, "密码:" + password, Toast.LENGTH_SHORT).show(); } }); } } |
上面就是九宫格程序设计的代码了。这里没有用到xml的布局文件,都是用代码实现的。
完成自定义View后,调用和使用都是比较简单的,可以作为一个工具类使用,获取到自定义View传过来的密码,可以做其他保存操作,比如保存到本地文件或数据库中,这里只是做了土司操作,让用户看到效果。