学习内容来自千锋Mars老师数独教程
主要学习内容:
1、图形编程
2、自定义View类
3、FontMmetrics
4、单击触摸事件
5、碰撞检测
6、可用数据计算
图形编程基本概念:
1、颜色对象
Color 安卓系统中的颜色的表示方法
(1)、int color = Color.blue; //纯色
(2)、int color = Color.argb(188,255,255,255);//自定义颜色
(3)、在xml文件当中定义颜色
2、画笔对象
Paint 该类的对象用于控制画笔的风格和颜色等方面的信息
(1)、paint.setColor(Color.blue);
3、canvas 该类代表一块“画布”,可以在“画布”上绘制字符,图形和图片
(1)、canvas.drawcircle(300,400,100,paint);
自定义View的基本实现方法:
(1)、定义一个类,继承View
(2)、复写View的onDraw函数
(3)、在onDraw当中使用canvas和paint对象绘制图形
Paint的设置方法:
1、setAntiAlias:设置画笔的锯齿效果
2、setARGB:设置画笔的argb对象
3、setTextSize:设置字体尺寸
4、setColor:设置画笔颜色
5、setAlpha:设置透明度值
6、setStyle:设置画笔风格,空心或实心
7、getColor:得到画笔颜色
8、getApha:得到画笔的透明度值
public boolean onTouchEvent(MotionEvent event){
//获得事件的种类
event.getAction();
//获取点击的坐标
event.getX();
event.getY();
}
直接上代码
总共四个类
一、ShuduView.java 游戏界面构画
1 package myview; 2 3 import xqx.shudu.Game; 4 import xqx.shudu.R; 5 import xqx.shudu.SelectDialog; 6 7 import android.app.AlertDialog; 8 import android.app.AlertDialog.Builder; 9 import android.content.Context; 10 import android.content.DialogInterface; 11 import android.graphics.Canvas; 12 import android.graphics.Color; 13 import android.graphics.Paint; 14 import android.graphics.Paint.Align; 15 import android.graphics.Paint.FontMetrics; 16 import android.graphics.Paint.Style; 17 import android.view.LayoutInflater; 18 import android.view.MotionEvent; 19 import android.view.View; 20 import android.widget.TextView; 21 import android.widget.Toast; 22 23 public class ShuduView extends View{ 24 //记录单元格的高度和宽度 25 private float width; 26 private float height; 27 private Game game = new Game(); 28 int selectx; 29 int selecty; 30 public ShuduView(Context context) { 31 super(context); 32 // TODO Auto-generated constructor stub 33 } 34 @Override 35 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 36 // TODO Auto-generated method stub 37 //计算当前单元格的宽度和高度 38 this.width = w/9f;//每一格的宽度 39 this.height = h/9f;//每一格的高度 40 super.onSizeChanged(w, h, oldw, oldh); 41 } 42 @Override 43 protected void onDraw(Canvas canvas) { 44 // TODO Auto-generated method stub 45 //1、绘制背景 46 Paint bgpaint = new Paint(); 47 bgpaint.setColor(Color.GRAY); 48 //绘制背景色 49 canvas.drawRect(0, 0, getWidth(), getHeight(), bgpaint); 50 51 Paint drakpaint = new Paint(); 52 drakpaint.setColor(Color.WHITE); 53 54 Paint whitepaint = new Paint(); 55 whitepaint.setColor(Color.BLACK); 56 57 for (int i = 0; i < 9; i++) { 58 //绘制横向的单元格线 59 canvas.drawLine(0, i*height, getWidth(), i*height, whitepaint); 60 canvas.drawLine(0, i*height+1, getWidth(), i*height+1, whitepaint); 61 //绘制纵向的单元格的线 62 canvas.drawLine(i*width, 0, i*width, getHeight(), whitepaint); 63 canvas.drawLine(i*width+1, 0, i*width+1, getHeight(), whitepaint); 64 } 65 //绘制横竖各三条分割线 66 for (int i = 0; i < 9; i++) { 67 if(i%3!=0) 68 { 69 continue; 70 } 71 //绘制横向的单元格线 72 canvas.drawLine(0, i*height, getWidth(), i*height, drakpaint); 73 canvas.drawLine(0, i*height+1, getWidth(), i*height+1, drakpaint); 74 //绘制纵向的单元格的线 75 canvas.drawLine(i*width, 0, i*width, getHeight(), drakpaint); 76 canvas.drawLine(i*width+1, 0, i*width+1, getHeight(), drakpaint); 77 } 78 //绘制数字 79 Paint numberpaint = new Paint(); 80 numberpaint.setColor(Color.BLACK); 81 numberpaint.setStyle(Style.STROKE); 82 numberpaint.setTextSize((float) (height*0.75)); 83 numberpaint.setTextAlign(Align.CENTER);//居中对齐 84 85 FontMetrics fm = numberpaint.getFontMetrics(); 86 float x = width/2; 87 float y = height/2-(fm.ascent-fm.descent)/2; 88 // 计算文字高度 89 float fontHeight = fm.bottom - fm.top; 90 // 计算文字baseline 91 float textBaseY = height - (height - fontHeight) / 2 - fm.bottom; 92 //canvas.drawText("1", 3*width+x, textBaseY, numberpaint); 93 //绘制数字 94 for(int i=0;i<9;i++) 95 { 96 for(int j=0; j<9;j++) 97 { 98 canvas.drawText(game.getTitlStringe(i,j), i*width+x, j*height+textBaseY, numberpaint); 99 } 100 } 101 super.onDraw(canvas); 102 } 103 //触摸事件 104 @Override 105 public boolean onTouchEvent(MotionEvent event) { 106 // TODO Auto-generated method stub 107 if(event.getAction()!=MotionEvent.ACTION_DOWN) 108 { 109 return super.onTouchEvent(event); 110 } 111 112 //得到点击位置的x,y坐标 113 selectx = (int) (event.getX()/width); 114 selecty = (int) (event.getY()/height); 115 116 int used[] = game.getused(selectx,selecty); 117 StringBuffer strbuf = new StringBuffer(); 118 for(int i=0;i<used.length;i++) 119 { 120 strbuf.append(used[i]+"、"); 121 } 122 123 124 SelectDialog seldia = new SelectDialog(getContext(),used,this); 125 seldia.show(); 126 return true; 127 128 } 129 130 //View类接受KeyDialog传递过来的数据,调用业务逻辑Game类,进行处理 131 public void setSelectTile(int tile) 132 { 133 if(game.setTileIfValid(selectx,selecty,tile)) 134 { 135 invalidate();//重新绘制View对象 136 } 137 } 138 }
二、Game.java 用于处理数独数据
1 package xqx.shudu; 2 3 public class Game { 4 //数独数据初始化 5 private final String str = "360000000" + 6 "004230800" + 7 "000004200" + 8 "070460003" + 9 "820000014" + 10 "500013020" + 11 "001900000" + 12 "007048300" + 13 "000000045"; 14 private int shuduku[]=new int[9*9]; 15 //用来存储每个单元格不可填写的数字 16 //1维 x坐标 2维 y坐标 3维 不可填写数字 17 private int used[][][]=new int[9][9][]; 18 public Game(){ 19 shuduku = fromPuzzleString(str); 20 calAllused(); 21 } 22 23 //根据字符串数据生成整型数组 24 public int[] fromPuzzleString(String str2) { 25 // TODO Auto-generated method stub 26 int shudu[] = new int[str2.length()]; 27 for(int i=0;i<shudu.length;i++) 28 { 29 shudu[i]=str2.charAt(i)-‘0‘; //吧字符转换为数字 30 } 31 return shudu; 32 } 33 34 //根据九宫格坐标返回该坐标所应该填写的数字 35 public int getTitile(int x,int y){ 36 return shuduku[y*9+x]; 37 } 38 39 public String getTitlStringe(int x,int y){ 40 int v = getTitile(x, y); 41 if(v==0){ 42 return ""; 43 } 44 else 45 { 46 return String.valueOf(v); 47 } 48 } 49 50 //计算某单元格已经不可填写的数字 51 public int[] calUsed(int x,int y){ 52 int c[]= new int[9]; 53 54 //判断y这一列,如果遍历他自己 ,跳过,如果遍历单元格数字不为0,则放入数组中 55 for(int i=0;i<9;i++) 56 { 57 if(i==y) 58 continue; 59 int t = getTitile(x, i); 60 if(t!=0) 61 c[t-1]=t; 62 } 63 //判断x这一行,如果遍历他自己 ,跳过,如果遍历单元格数字不为0,则放入数组中 64 for(int i=0;i<9;i++) 65 { 66 if(i==x) 67 continue; 68 int t = getTitile(i, y); 69 if(t!=0) 70 c[t-1]=t; 71 } 72 //判断该单元格所在的九宫格出现的数字并放入不可填写数字数组当中 73 int startx = (x/3)*3; 74 int starty = (y/3)*3; 75 for(int i=startx;i<startx+3;i++) 76 { 77 for(int j=starty;j<starty+3;j++) 78 { 79 if(i==x&&j==y) 80 continue; 81 int t = getTitile(i, j); 82 if(t!=0) 83 { 84 c[t-1]=t; 85 } 86 } 87 } 88 89 int nused = 0; 90 for(int t:c){ 91 if(t!=0) 92 nused++; 93 } 94 int c1[] = new int[nused]; 95 nused=0; 96 for(int t:c){ 97 if(t!=0) 98 { 99 c1[nused++]=t; 100 } 101 } 102 103 return c; 104 } 105 106 //计算所有单元格不可用数字数组 107 public void calAllused(){ 108 for(int x=0;x<9;x++) 109 { 110 for(int y=0;y<9;y++){ 111 used[x][y]=calUsed(x, y); 112 } 113 } 114 } 115 116 //得到该单元格不可用数字 117 public int[] getused(int x,int y){ 118 return used[x][y]; 119 } 120 //接收KeyDialog中点击的数字 121 public boolean setTileIfValid(int x, int y, int value) 122 { 123 int[] tiles = getused(x, y);//得到不可用的数据 124 125 126 if (value != 0) 127 { 128 for (int t : tiles) 129 { 130 if (t == value) 131 return false; 132 } 133 } 134 setSelectNum(x, y, value);//将对应的值value绘制在xy对应的格子中 135 calAllused();//重新计算所有格子的不可用数据 136 137 return true; 138 } 139 140 //在数独数组中更改填写后的数字 141 private void setSelectNum(int x, int y, int num) { 142 // TODO Auto-generated method stub 143 shuduku[y*9+x]=num; 144 } 145 } 146
三、SelectDialog.java 用于设置填写数字的对话框
1 package xqx.shudu; 2 3 import myview.ShuduView; 4 import android.app.Dialog; 5 import android.content.Context; 6 import android.os.Bundle; 7 import android.view.View; 8 import android.widget.Toast; 9 10 public class SelectDialog extends Dialog{ 11 int q; 12 //当dialog第一次显示时会调用其onCreate方法 13 //用来存放对话框中按钮对象 14 private ShuduView shuduview; 15 private View key[] = new View[9]; 16 private int used[]; 17 public SelectDialog(Context context, int used[],ShuduView shuduview) { 18 19 20 super(context); 21 this.used=used; 22 this.shuduview = shuduview; 23 // TODO Auto-generated constructor stub 24 } 25 26 @Override 27 protected void onCreate(Bundle savedInstanceState) { 28 // TODO Auto-generated method stub 29 super.onCreate(savedInstanceState); 30 setTitle("选择填入的数字"); 31 setContentView(R.layout.shudu_diolag);//设置布局文件 32 findView(); 33 34 for(int i=0;i<used.length;i++) 35 { 36 if(used[i]!=0) 37 { 38 key[used[i]-1].setVisibility(View.INVISIBLE); 39 } 40 } 41 //为对话框中所有内容设置监听器 42 setListener(); 43 } 44 45 //为按钮设置监听器 46 public void setListener() 47 { 48 for(int i = 0; i<key.length; i++) 49 { 50 final int t = i+1; 51 key[i].setOnClickListener(new View.OnClickListener() 52 { 53 54 @Override 55 public void onClick(View v) 56 { 57 // TODO Auto-generated method stub 58 returnResult(t); 59 } 60 }); 61 } 62 } 63 64 //对话框将选择的数据传递给View对象,让其处理业务逻辑 65 public void returnResult(int tile) 66 { 67 shuduview.setSelectTile(tile); 68 dismiss(); 69 } 70 71 72 private void findView() { 73 // TODO Auto-generated method stub 74 key[0] = findViewById(R.id.btn_1); 75 key[1] = findViewById(R.id.btn_2); 76 key[2] = findViewById(R.id.btn_3); 77 key[3] = findViewById(R.id.btn_4); 78 key[4] = findViewById(R.id.btn_5); 79 key[5] = findViewById(R.id.btn_6); 80 key[6] = findViewById(R.id.btn_7); 81 key[7] = findViewById(R.id.btn_8); 82 key[8] = findViewById(R.id.btn_9); 83 } 84 }
四、MainActivty.java 在主类中调用MyView对象
1 package xqx.shudu; 2 import myview.*; 3 import android.os.Bundle; 4 import android.app.Activity; 5 import android.view.Menu; 6 7 public class MainActivity extends Activity { 8 9 @Override 10 protected void onCreate(Bundle savedInstanceState) { 11 super.onCreate(savedInstanceState); 12 setContentView(new ShuduView(this)); 13 // setContentView(R.layout.activity_main); 14 } 15 16 17 @Override 18 public boolean onCreateOptionsMenu(Menu menu) { 19 // Inflate the menu; this adds items to the action bar if it is present. 20 getMenuInflater().inflate(R.menu.main, menu); 21 return true; 22 } 23 24 }
五:布局文件
1 <?xml version="1.0" encoding="utf-8"?> 2 <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:layout_gravity="center_horizontal" 6 android:stretchColumns="*" 7 android:orientation="vertical" > 8 9 <TableRow > 10 <Button android:id="@+id/btn_1" 11 android:text="1"/> 12 <Button android:id="@+id/btn_2" 13 android:text="2"/> 14 <Button android:id="@+id/btn_3" 15 android:text="3"/> 16 </TableRow> 17 <TableRow > 18 <Button android:id="@+id/btn_4" 19 android:text="4"/> 20 <Button android:id="@+id/btn_5" 21 android:text="5"/> 22 <Button android:id="@+id/btn_6" 23 android:text="6"/> 24 </TableRow> 25 <TableRow > 26 <Button android:id="@+id/btn_7" 27 android:text="7"/> 28 <Button android:id="@+id/btn_8" 29 android:text="8"/> 30 <Button android:id="@+id/btn_9" 31 android:text="9"/> 32 </TableRow> 33 34 <Button 35 android:id="@+id/btn_cannel" 36 android:layout_width="wrap_content" 37 android:layout_height="wrap_content" 38 android:text="取消" /> 39 40 </TableLayout>
效果图: