• 自定义控件:数独游戏(一)


    主要学习内容:

    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>

    效果图:

  • 相关阅读:
    员工年龄排序之桶排序
    滑动窗口中最大值
    开机自动启动Tomcat
    基于RXTX的串口通讯 windows64位系统可用
    一些SQL
    Java 实现文件上传、下载、打包、文件copy、文件夹copy。
    Page-encoding specified in XML prolog (UTF-8) is different from that specified in page directive (utf-8)
    Java -> 把Excel表格中的数据写入数据库与从数据库中读出到本地 (未完善)
    (转)解决:本地计算机 上的 OracleOraDb10g_home1TNSListener服务启动后停止
    PHP、Java对称加密中的AES加密方法
  • 原文地址:https://www.cnblogs.com/xqxacm/p/4678572.html
Copyright © 2020-2023  润新知