老师视频教程结束了,但是游戏并未完成。下面便开始自己动手完善部分功能
需要完善的功能:
1、设置给定的数独数据数字不可改变
2、设置给定的数独数据数字和玩家填入的数字颜色不同,方便区分
3、判断填写后的数独是否符合数独游戏规则
4、数字选择兑对话框添加清除和取消按钮,并每次选择时显示所有的数字(原来思路是只显示符合规则的数字,这样当出现错误之后,后面的某些位置无法选择数字)
解决方法:
1、设置给定的数独数据数字不可改变
我的思路,因为初始化的数据数字是给定的,而数据是放在一个字符串里的,如下:0代表需要玩家输入的,非0则是给定的
1 private final String str = "061030020050008107000007034009006078003279500570300902190760000802400060640010250";
这样只需要在开一个整型数组来标记,0表示玩家需要填写的,1代表是系统给定的数独数据数字
在Game.java类中
实现根据数独数据字符串获得一个整型数组(isdata[]),
并给一个获取数组方法,
1 public int getIsData(int x,int y){ 2 return isdata[y*9+x]; 3 }
1 //根据字符串数据生成整型数组 2 public int[] fromPuzzleString(String str2) { 3 // TODO Auto-generated method stub 4 // shudu[] = new int[str2.length()]; 5 for(int i=0;i<shudu.length;i++) 6 { 7 shudu[i]=str2.charAt(i)-'0'; //吧字符转换为数字] 8 if(shudu[i]!=0) 9 { 10 isdata[i]=1; 11 } 12 } 13 14 return shudu; 15 }
若字符串某字符为'0'则整型数组对应数字0,若字符串某数字不为'0'则整型数组对应数字1,
然后在调用对话框的时候判断试下是不是玩家输入的单元格即可
1 if(game.getIsData(selectx,selecty)!=1) //如果不是系统初始给定的,则调用对话框,提供数字选择 2 { 3 SelectDialog seldia = new SelectDialog(getContext(),used,this); 4 seldia.show(); 5 }
2、设置给定的数独数据数字和玩家填入的数字颜色不同,方便区分
我的思路,因为给定的数据数字是给定的
1 private final String str = "061030020050008107000007034009006078003279500570300902190760000802400060640010250";
在Game.java类中
还是通过数组isdata[]
1 //根据字符串数据生成整型数组 2 public int[] fromPuzzleString(String str2) { 3 // TODO Auto-generated method stub 4 5 for(int i=0;i<shudu.length;i++) 6 { 7 shudu[i]=str2.charAt(i)-'0'; //吧字符转换为数字] 8 if(shudu[i]!=0) 9 { 10 isdata[i]=1; 11 } 12 } 13 14 return shudu; 15 }
在ShuduView类中
得到isdata[]整型数组,若为0,则表示该单元格是玩家填写的数字,用白色画笔构写数字
若为1,则表示该单元格是给定的数独数据的数字,用黑色画笔构写数字
具体代码:
1 //绘制数字-原始数据 2 Paint numberpaint_data = new Paint(); 3 numberpaint_data.setColor(Color.BLACK); //黑色字体 4 numberpaint_data.setStyle(Style.STROKE); 5 numberpaint_data.setTextSize((float) (height*0.75)); 6 numberpaint_data.setTextAlign(Align.CENTER);//居中对齐 7 //绘制数字-玩家填写数据 8 Paint numberpaint_new = new Paint(); 9 numberpaint_new.setColor(Color.WHITE); //白色字体 10 numberpaint_new.setStyle(Style.STROKE); 11 numberpaint_new.setTextSize((float) (height*0.75)); 12 numberpaint_new.setTextAlign(Align.CENTER);//居中对齐 13 14 FontMetrics fm = numberpaint_data.getFontMetrics(); 15 float x = width/2; 16 float y = height/2-(fm.ascent-fm.descent)/2;//获取画笔写数字的位置 17 // 计算文字高度 18 float fontHeight = fm.bottom - fm.top; 19 // 计算文字baseline 20 float textBaseY = height - (height - fontHeight) / 2 - fm.bottom; 21 //canvas.drawText("1", 3*width+x, textBaseY, numberpaint); 22 //绘制数字 23 for(int i=0;i<9;i++) 24 { 25 for(int j=0; j<9;j++) 26 { 27 if(game.getIsData(i, j)==1) //如果isdata[]数组对应位置的数字为1,则是系统初始化的数字,用黑色画笔,否则为玩家填写数字,用白色画笔 28 canvas.drawText(game.getTitlStringe(i,j), i*width+x, j*height+textBaseY, numberpaint_data); 29 else 30 canvas.drawText(game.getTitlStringe(i,j), i*width+x, j*height+textBaseY, numberpaint_new); 31 } 32 }
3、判断填写后的数独是否符合数独游戏规则
在给定初始数据时
1 private final String str = "061030020050008107000007034009006078003279500570300902190760000802400060640010250"; //初始化数据 2 private final String str_da = "761934825354628197928157634219546378483279516576381942195762483832495761647813259"; //答案数据
判断是否完成数独方法
1 private void judge() { 2 // TODO Auto-generated method stub 3 StringBuffer a = new StringBuffer((String) game.getStr_da()); 4 int[] b = game.getShuduku(); 5 StringBuffer c = new StringBuffer(); 6 for(int i=0;i<b.length;i++) 7 { 8 c.append(b[i]); 9 } 10 // String c= String.valueOf(b); 11 if(a.toString().equals(c.toString())) //注意StringBuffer不用直接用a.equals(c)这样对比的是对象 12 { 13 AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); 14 builder.setTitle("~~通知~~"); 15 builder.setIcon(R.drawable.app_xin); 16 builder.setMessage("恭喜通关!!!"); 17 builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { 18 @Override 19 public void onClick(DialogInterface arg0, int arg1) { 20 // TODO Auto-generated method stub 21 } 22 }); 23 AlertDialog dialog = builder.create(); 24 dialog.show(); //显示、 25 } 26 } 27 }
4、数字选择兑对话框添加清除和取消按钮
(1)、先修改数字选择对话框布局文件
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 <LinearLayout 35 android:layout_width="wrap_content" 36 android:layout_height="wrap_content" 37 android:orientation="horizontal" 38 > 39 <Button //添加清除按钮 40 android:layout_weight="1" 41 android:id="@+id/btn_0" 42 android:layout_width="wrap_content" 43 android:layout_height="wrap_content" 44 android:text="清除" /> 45 <Button //添加修改按钮 46 android:layout_weight="1" 47 android:id="@+id/btn_cannel" 48 android:layout_width="wrap_content" 49 android:layout_height="wrap_content" 50 android:text="取消" /> 51 52 53 </LinearLayout> 54 </TableLayout>
(2)、SelectDialog.java文件中 修改响应事件
1 //为按钮设置监听器 2 public void setListener() 3 { 4 for(int i = 0; i<key.length; i++) 5 { 6 final int t = i; 7 key[i].setOnClickListener(new View.OnClickListener() 8 { 9 10 @Override 11 public void onClick(View v) 12 { 13 // TODO Auto-generated method stub 14 returnResult(t); //传值为选择的数字为,0--9,当为0时 即清除按钮 15 } 16 }); 17 } 18 } 19 20 //对话框将选择的数据传递给View对象,让其处理业务逻辑 21 public void returnResult(int tile) 22 { 23 shuduview.setSelectTile(tile); 24 dismiss(); 25 } 26 27 28 private void findView() { 29 // TODO Auto-generated method stub 30 key[0] = findViewById(R.id.btn_0); 31 key[1] = findViewById(R.id.btn_1); 32 key[2] = findViewById(R.id.btn_2); 33 key[3] = findViewById(R.id.btn_3); 34 key[4] = findViewById(R.id.btn_4); 35 key[5] = findViewById(R.id.btn_5); 36 key[6] = findViewById(R.id.btn_6); 37 key[7] = findViewById(R.id.btn_7); 38 key[8] = findViewById(R.id.btn_8); 39 key[9] = findViewById(R.id.btn_9); 40 back = findViewById(R.id.btn_cannel); 41 }
(3)、Game.java 文件中修改
public boolean setTileIfValid(int x, int y, int value) 将选择的数字显示出来 { // int[] tiles = getused(x, y);//得到不可用的数据 // if (value != 0) // { // for (int t : tiles) // { // if (t == value) // return false; // } // } setSelectNum(x, y, value);//将对应的值value绘制在xy对应的格子中 calAllused();//重新计算所有格子的不可用数据 return true; }
总代码
1、
1 package xqx.shudu; 2 3 import myview.ShuduView; 4 import android.app.AlertDialog; 5 import android.content.DialogInterface; 6 import android.util.Log; 7 import android.widget.Toast; 8 9 public class Game { 10 11 //数独数据初始化 12 private final String str = "061030020050008107000007034009006078003279500570300902190760000802400060640010250"; 13 private final String str_da = "761934825354628197928157634219546378483279516576381942195762483832495761647813259"; 14 private int shuduku[]=new int[9*9]; 15 public int shudu[] = new int[81]; 16 public int[] getShuduku() { 17 return shuduku; 18 } 19 20 public void setShuduku(int[] shuduku) { 21 this.shuduku = shuduku; 22 } 23 24 public int[] getShudu() { 25 return shudu; 26 } 27 28 public void setShudu(int[] shudu) { 29 this.shudu = shudu; 30 } 31 32 private int isdata[] = new int[9*9];//标记是否为原始数据 33 //用来存储每个单元格不可填写的数字 34 //1维 x坐标 2维 y坐标 3维 不可填写数字 35 private int used[][][]=new int[9][9][]; 36 public Game(){ 37 shuduku = fromPuzzleString(str); 38 calAllused(); 39 } 40 41 //根据字符串数据生成整型数组 42 public int[] fromPuzzleString(String str2) { 43 // TODO Auto-generated method stub 44 // shudu[] = new int[str2.length()]; 45 for(int i=0;i<shudu.length;i++) 46 { 47 shudu[i]=str2.charAt(i)-'0'; //吧字符转换为数字] 48 if(shudu[i]!=0) 49 { 50 isdata[i]=1; 51 } 52 } 53 54 return shudu; 55 } 56 57 //根据九宫格坐标返回该坐标所应该填写的数字 58 public int getTitile(int x,int y){ 59 return shuduku[y*9+x]; 60 } 61 public int getIsData(int x,int y){ 62 return isdata[y*9+x]; 63 } 64 public String getTitlStringe(int x,int y){ 65 int v = getTitile(x, y); 66 if(v==0){ 67 return ""; 68 } 69 else 70 { 71 return String.valueOf(v); 72 } 73 } 74 75 //计算某单元格已经不可填写的数字 76 public int[] calUsed(int x,int y){ 77 int c[]= new int[9]; 78 79 //判断y这一列,如果遍历他自己 ,跳过,如果遍历单元格数字不为0,则放入数组中 80 for(int i=0;i<9;i++) 81 { 82 if(i==y) 83 continue; 84 int t = getTitile(x, i); 85 if(t!=0) 86 c[t-1]=t; 87 } 88 //判断x这一行,如果遍历他自己 ,跳过,如果遍历单元格数字不为0,则放入数组中 89 for(int i=0;i<9;i++) 90 { 91 if(i==x) 92 continue; 93 int t = getTitile(i, y); 94 if(t!=0) 95 c[t-1]=t; 96 } 97 //判断该单元格所在的九宫格出现的数字并放入不可填写数字数组当中 98 int startx = (x/3)*3; 99 int starty = (y/3)*3; 100 for(int i=startx;i<startx+3;i++) 101 { 102 for(int j=starty;j<starty+3;j++) 103 { 104 if(i==x&&j==y) 105 continue; 106 int t = getTitile(i, j); 107 if(t!=0) 108 { 109 c[t-1]=t; 110 } 111 } 112 } 113 114 int nused = 0; 115 for(int t:c){ 116 if(t!=0) 117 nused++; 118 } 119 int c1[] = new int[nused]; 120 nused=0; 121 for(int t:c){ 122 if(t!=0) 123 { 124 c1[nused++]=t; 125 } 126 } 127 128 return c; 129 } 130 131 //计算所有单元格不可用数字数组 132 public void calAllused(){ 133 for(int x=0;x<9;x++) 134 { 135 for(int y=0;y<9;y++){ 136 used[x][y]=calUsed(x, y); 137 } 138 } 139 } 140 141 //得到该单元格不可用数字 142 public int[] getused(int x,int y){ 143 return used[x][y]; 144 } 145 //接收KeyDialog中点击的数字 146 public boolean setTileIfValid(int x, int y, int value) 147 { 148 int[] tiles = getused(x, y);//得到不可用的数据 149 150 151 // if (value != 0) 152 // { 153 // for (int t : tiles) 154 // { 155 // if (t == value) 156 // return false; 157 // } 158 // } 159 setSelectNum(x, y, value);//将对应的值value绘制在xy对应的格子中 160 calAllused();//重新计算所有格子的不可用数据 161 162 return true; 163 } 164 165 //在数独数组中更改填写后的数字 166 private void setSelectNum(int x, int y, int num) { 167 // TODO Auto-generated method stub 168 shuduku[y*9+x]=num; 169 } 170 //判断是否正确完成数独游戏 171 private void judge() { 172 173 } 174 175 public String getStr() { 176 return str; 177 } 178 179 public String getStr_da() { 180 return str_da; 181 } 182 } 183
2、
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.util.Log; 18 import android.view.LayoutInflater; 19 import android.view.MotionEvent; 20 import android.view.View; 21 import android.widget.TextView; 22 import android.widget.Toast; 23 24 public class ShuduView extends View{ 25 //记录单元格的高度和宽度 26 private float width; 27 private float height; 28 private Game game = new Game(); 29 int selectx; 30 int selecty; 31 public ShuduView(Context context) { 32 super(context); 33 // TODO Auto-generated constructor stub 34 } 35 @Override 36 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 37 // TODO Auto-generated method stub 38 //计算当前单元格的宽度和高度 39 this.width = w/9f;//每一格的宽度 40 this.height = h/9f;//每一格的高度 41 super.onSizeChanged(w, h, oldw, oldh); 42 } 43 @Override 44 protected void onDraw(Canvas canvas) { 45 // TODO Auto-generated method stub 46 //1、绘制背景 47 Paint bgpaint = new Paint(); 48 bgpaint.setColor(Color.GRAY); 49 //绘制背景色 50 canvas.drawRect(0, 0, getWidth(), getHeight(), bgpaint); 51 52 Paint drakpaint = new Paint(); 53 drakpaint.setColor(Color.WHITE); 54 55 Paint whitepaint = new Paint(); 56 whitepaint.setColor(Color.BLACK); 57 58 for (int i = 0; i < 9; i++) { 59 //绘制横向的单元格线 60 canvas.drawLine(0, i*height, getWidth(), i*height, whitepaint); 61 canvas.drawLine(0, i*height+1, getWidth(), i*height+1, whitepaint); 62 //绘制纵向的单元格的线 63 canvas.drawLine(i*width, 0, i*width, getHeight(), whitepaint); 64 canvas.drawLine(i*width+1, 0, i*width+1, getHeight(), whitepaint); 65 } 66 //绘制横竖各三条分割线 67 for (int i = 0; i < 9; i++) { 68 if(i%3!=0) 69 { 70 continue; 71 } 72 //绘制横向的单元格线 73 canvas.drawLine(0, i*height, getWidth(), i*height, drakpaint); 74 canvas.drawLine(0, i*height+1, getWidth(), i*height+1, drakpaint); 75 //绘制纵向的单元格的线 76 canvas.drawLine(i*width, 0, i*width, getHeight(), drakpaint); 77 canvas.drawLine(i*width+1, 0, i*width+1, getHeight(), drakpaint); 78 } 79 //绘制数字-原始数据 80 Paint numberpaint_data = new Paint(); 81 numberpaint_data.setColor(Color.BLACK); 82 numberpaint_data.setStyle(Style.STROKE); 83 numberpaint_data.setTextSize((float) (height*0.75)); 84 numberpaint_data.setTextAlign(Align.CENTER);//居中对齐 85 //绘制数字-玩家填写数据 86 Paint numberpaint_new = new Paint(); 87 numberpaint_new.setColor(Color.WHITE); 88 numberpaint_new.setStyle(Style.STROKE); 89 numberpaint_new.setTextSize((float) (height*0.75)); 90 numberpaint_new.setTextAlign(Align.CENTER);//居中对齐 91 92 FontMetrics fm = numberpaint_data.getFontMetrics(); 93 float x = width/2; 94 float y = height/2-(fm.ascent-fm.descent)/2; 95 // 计算文字高度 96 float fontHeight = fm.bottom - fm.top; 97 // 计算文字baseline 98 float textBaseY = height - (height - fontHeight) / 2 - fm.bottom; 99 //canvas.drawText("1", 3*width+x, textBaseY, numberpaint); 100 //绘制数字 101 for(int i=0;i<9;i++) 102 { 103 for(int j=0; j<9;j++) 104 { 105 if(game.getIsData(i, j)==1) 106 canvas.drawText(game.getTitlStringe(i,j), i*width+x, j*height+textBaseY, numberpaint_data); 107 else 108 canvas.drawText(game.getTitlStringe(i,j), i*width+x, j*height+textBaseY, numberpaint_new); 109 } 110 } 111 super.onDraw(canvas); 112 } 113 //触摸事件 114 @Override 115 public boolean onTouchEvent(MotionEvent event) { 116 // TODO Auto-generated method stub 117 if(event.getAction()!=MotionEvent.ACTION_DOWN) 118 { 119 return super.onTouchEvent(event); 120 } 121 122 //得到点击位置的x,y坐标 123 selectx = (int) (event.getX()/width); 124 selecty = (int) (event.getY()/height); 125 126 int used[] = game.getused(selectx,selecty); 127 // StringBuffer strbuf = new StringBuffer(); 128 // for(int i=0;i<used.length;i++) 129 // { 130 // strbuf.append(used[i]+"、"); 131 // } 132 133 if(game.getIsData(selectx,selecty)!=1) 134 { 135 SelectDialog seldia = new SelectDialog(getContext(),used,this); 136 seldia.show(); 137 } 138 return true; 139 140 } 141 142 //View类接受KeyDialog传递过来的数据,调用业务逻辑Game类,进行处理 143 public void setSelectTile(int tile) 144 { 145 if(game.setTileIfValid(selectx,selecty,tile)) 146 { 147 invalidate();//重新绘制View对象 148 judge(); 149 } 150 } 151 private void judge() { 152 // TODO Auto-generated method stub 153 StringBuffer a = new StringBuffer((String) game.getStr_da()); 154 int[] b = game.getShuduku(); 155 StringBuffer c = new StringBuffer(); 156 for(int i=0;i<b.length;i++) 157 { 158 c.append(b[i]); 159 } 160 // String c= String.valueOf(b); 161 if(a.toString().equals(c.toString())) 162 { 163 AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); 164 builder.setTitle("~~通知~~"); 165 builder.setIcon(R.drawable.app_xin); 166 builder.setMessage("恭喜通关!!!"); 167 builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { 168 @Override 169 public void onClick(DialogInterface arg0, int arg1) { 170 // TODO Auto-generated method stub 171 } 172 }); 173 AlertDialog dialog = builder.create(); 174 dialog.show(); //显示、 175 } 176 } 177 178 179 180 }
3、
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[10]; 16 private int used[]; 17 private View back; 18 public SelectDialog(Context context, int used[],ShuduView shuduview) { 19 20 21 super(context); 22 this.used=used; 23 this.shuduview = shuduview; 24 // TODO Auto-generated constructor stub 25 } 26 27 @Override 28 protected void onCreate(Bundle savedInstanceState) { 29 // TODO Auto-generated method stub 30 super.onCreate(savedInstanceState); 31 setTitle("选择填入的数字"); 32 setContentView(R.layout.shudu_diolag);//设置布局文件 33 findView(); 34 35 // for(int i=0;i<used.length;i++) 36 // { 37 // if(used[i]!=0) 38 // { 39 // key[used[i]-1].setVisibility(View.INVISIBLE); 40 // } 41 // } 42 //为对话框中所有内容设置监听器 43 setListener(); 44 45 back.setOnClickListener(new View.OnClickListener() { 46 @Override 47 public void onClick(View arg0) { 48 // TODO Auto-generated method stub 49 dismiss(); 50 } 51 }); 52 } 53 54 //为按钮设置监听器 55 public void setListener() 56 { 57 for(int i = 0; i<key.length; i++) 58 { 59 final int t = i; 60 key[i].setOnClickListener(new View.OnClickListener() 61 { 62 63 @Override 64 public void onClick(View v) 65 { 66 // TODO Auto-generated method stub 67 returnResult(t); 68 } 69 }); 70 } 71 } 72 73 //对话框将选择的数据传递给View对象,让其处理业务逻辑 74 public void returnResult(int tile) 75 { 76 shuduview.setSelectTile(tile); 77 dismiss(); 78 } 79 80 81 private void findView() { 82 // TODO Auto-generated method stub 83 key[0] = findViewById(R.id.btn_0); 84 key[1] = findViewById(R.id.btn_1); 85 key[2] = findViewById(R.id.btn_2); 86 key[3] = findViewById(R.id.btn_3); 87 key[4] = findViewById(R.id.btn_4); 88 key[5] = findViewById(R.id.btn_5); 89 key[6] = findViewById(R.id.btn_6); 90 key[7] = findViewById(R.id.btn_7); 91 key[8] = findViewById(R.id.btn_8); 92 key[9] = findViewById(R.id.btn_9); 93 back = findViewById(R.id.btn_cannel); 94 } 95 }
4、
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 }
5、
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 <LinearLayout 35 android:layout_width="wrap_content" 36 android:layout_height="wrap_content" 37 android:orientation="horizontal" 38 > 39 <Button 40 android:layout_weight="1" 41 android:id="@+id/btn_0" 42 android:layout_width="wrap_content" 43 android:layout_height="wrap_content" 44 android:text="清除" /> 45 <Button 46 android:layout_weight="1" 47 android:id="@+id/btn_cannel" 48 android:layout_width="wrap_content" 49 android:layout_height="wrap_content" 50 android:text="取消" /> 51 52 53 </LinearLayout> 54 </TableLayout>
效果图: