实验4:Android界面设计

    8.2 实例讲解

    简要说明:我做的是一个黑白棋的应用,在主界面是用垂直布局来弄的,中间会涉及到几个相对布局和表格布局,还是相对来说比较简单的。
    详细步骤:

    1. android:background=”/net13140803138background” //一开始用了这一句调用了drawable里的背景图片作为背景。
    2. android:orientation=”vertical”//然后这里是说明我是垂直方向进行线性布局。
    3. 然后我就开始按照布局放控件了,其中:
      <ImageView这一部分代码即我最上面的一个ImageView,调用了drawable/net13140803138top图片。
      1. android:layout_width="0dp"
      2. android:layout_weight="2"
      3. android:layout_height="match_parent"
      4. android:scaleType="fitCenter"
      5. android:src="@drawable/net13140803138daojian"
      6. />
    1. </LinearLayout>

    这里我是用了一个水平方向的线性布局,这里值得一提的是,我放了3个位置,但是我只放了一个控件,调用了drawable/net13140803138daojian图片,如果我后面增加了新的功能,可以有位置添加进去。

    1. 这里则是由12个黑白棋子组成的一个布局,由12个黑白棋图片组成,代码会有点长,但是代码其实是比较简单的

      1. <GridLayout
      2. android:layout_width="wrap_content"
      3. android:layout_height="wrap_content"
      4. android:rowCount="3"
      5. android:columnCount="4"
      6. android:layout_centerInParent="true"
      7. >
      8. <ImageView
      9. android:id="@+id/iv1"
      10. android:layout_width="/width_of_chess1" android:layout_margin="@dimen/chess_margin1"
      11. android:layout_height="/width_of_chess1"
      12. android:scaleType="fitCenter"
      13. android:src="@drawable/net13140803138white_chess"/>
      14. <ImageView
      15. android:id="@+id/iv2"
      16. android:layout_width="/width_of_chess1" android:layout_margin="@dimen/chess_margin1"
      17. android:scaleType="fitCenter"
      18. android:layout_height="/width_of_chess1"
      19. android:src="@drawable/net13140803138black_chess"
      20. />
      21. <ImageView
      22. android:id="@+id/iv3"
      23. android:layout_width="/width_of_chess1" android:layout_margin="@dimen/chess_margin1"
      24. android:scaleType="fitCenter"
      25. android:layout_height="/width_of_chess1"
      26. android:src="@drawable/net13140803138black_chess"
      27. />
      28. <ImageView
      29. android:id="@+id/iv4"
      30. android:layout_width="/width_of_chess1" android:layout_margin="@dimen/chess_margin1"
      31. android:scaleType="fitCenter"
      32. android:src="/net13140803138white_chess"
      33. android:layout_height="@dimen/width_of_chess1" />
      34. <ImageView
      35. android:id="@+id/iv5"
      36. android:layout_width="/width_of_chess1" android:layout_margin="@dimen/chess_margin1"
      37. android:scaleType="fitCenter"
      38. android:layout_height="/width_of_chess1"
      39. android:src="@drawable/net13140803138black_chess"/>
      40. <ImageView
      41. android:id="@+id/iv6"
      42. android:layout_width="/width_of_chess1" android:layout_margin="@dimen/chess_margin1"
      43. android:scaleType="fitCenter"
      44. android:layout_height="/width_of_chess1"
      45. android:src="@drawable/net13140803138white_chess"
      46. />
      47. <ImageView
      48. android:id="@+id/iv7"
      49. android:layout_width="/width_of_chess1" android:layout_margin="@dimen/chess_margin1"
      50. android:scaleType="fitCenter"
      51. android:layout_height="/width_of_chess1"
      52. android:src="@drawable/net13140803138white_chess"
      53. />
      54. <ImageView
      55. android:id="@+id/iv8"
      56. android:layout_width="/width_of_chess1" android:layout_margin="@dimen/chess_margin1"
      57. android:scaleType="fitCenter"
      58. android:src="/net13140803138black_chess"
      59. android:layout_height="@dimen/width_of_chess1" />
      60. <ImageView
      61. android:id="@+id/iv9"
      62. android:layout_width="/width_of_chess1" android:layout_margin="@dimen/chess_margin1"
      63. android:scaleType="fitCenter"
      64. android:layout_height="/width_of_chess1"
      65. android:src="@drawable/net13140803138black_chess"/>
      66. <ImageView
      67. android:id="@+id/iv10"
      68. android:layout_width="/width_of_chess1" android:layout_margin="@dimen/chess_margin1"
      69. android:scaleType="fitCenter"
      70. android:layout_height="/width_of_chess1"
      71. android:src="@drawable/net13140803138white_chess"
      72. />
      73. <ImageView
      74. android:id="@+id/iv11"
      75. android:scaleType="fitCenter"
      76. android:layout_width="/width_of_chess1" android:layout_margin="@dimen/chess_margin1"
      77. android:layout_height="/width_of_chess1"
      78. android:src="@drawable/net13140803138black_chess"
      79. />
      80. <ImageView
      81. android:id="@+id/iv12"
      82. android:layout_width="/width_of_chess1" android:layout_margin="@dimen/chess_margin1"
      83. android:scaleType="fitCenter"
      84. android:src="/net13140803138white_chess"
      85. android:layout_height="@dimen/width_of_chess1" />
    1. </GridLayout>
    2. </RelativeLayout>

    这一段的代码我是用了一个相对布局,里面在用一个表格布局放在这个相对布局的中间,调用了12个ImageView放在表格布局里面,其中,调用了drawable/net13140803138white_chess和drawable/net13140803138black_chess两个黑白棋子的图片。

    1. 这里我要加一个声音的开关放在右下角,所以要加一个相对布局

      1. <CheckBox
      2. android:id="@+id/soundSwitch"
      3. android:layout_alignParentRight="true"
      4. android:layout_width="wrap_content"
      5. android:layout_height="wrap_content"
      6. android:text="Sound"
      7. android:textColor="#FF000000"/>


      所以这里我用了一个相对布局,然后放一个CheckBox在这相对布局里面。

    2. <ImageButton
      1. android:layout_width="match_parent"
      2. android:layout_height="0dp"
      3. android:layout_weight="1"
      4. android:contentDescription="/app_name"
      5. android:id="@+id/startButton"
      6. android:src="@drawable/net13140803138start"
      7. android:scaleType="fitXY"
      8. android:background="#00000000"
      9. android:layout_marginBottom="6dp"/>
      这里也是调用了一个ImageButton作为一个开始按钮,其中调用了drawable/net13140803138start图片。
      至此,我的主界面就完成了。
      ```
    1. ###3. 制作练练看游戏界面
    2. 简要说明:海贼王连连看游戏主界面是由Net1314080903126main.xml 文件通过调用Net1314080903126CtrlView.java Net1314080903126GameView.java
    3. Net1314080903126OnePieceGame.java 来显示主界面的以及游戏规则和游戏玩法的等。
    4. 详细步骤:
    5. 1. 游戏的主界面是通过Net1314080903126main.xml 来显示的,代码:
    6. <?xml version="1.0" encoding="utf-8"?>
    7. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    8. android:orientation="vertical" android:layout_width="match_parent"
    9. android:layout_height="wrap_content">
    10. <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    11. android:layout_width="fill_parent" android:layout_height="wrap_content">
    12. <TableRow>
    13. <ProgressBar android:id="@+id/pb" android:layout_width="fill_parent"
    14. android:layout_height="wrap_content" style="?android:attr/progressBarStyleHorizontal"
    15. android:layout_weight="9"/>
    16. <TextView android:layout_height="wrap_content" android:layout_width="wrap_content"
    17. android:text="@string/remain_time" android:layout_weight="1"/>
    18. <TextView android:layout_height="wrap_content" android:layout_width="wrap_content"
    19. android:id="@+id/show_remainTime" android:layout_weight="1"/>
    20. </TableRow>
    21. </TableLayout>
    22. <edu.hzuapps.androidworks.homeworks.net1314080903126.Net1314080903126CtrlView
    23. android:id="@+id/cv"
    24. android:layout_width="wrap_content" android:layout_height="fill_parent" />
    25. </LinearLayout>
    26. 其中:<edu.hzuapps.androidworks.homeworks.net1314080903126.Net1314080903126CtrlView
    27. android:id="@+id/cv"
    28. android:layout_width="wrap_content" android:layout_height="fill_parent" />
    29. 这是显示海贼王人物的以及人物界面布局。
    30. 然后:<TableRow>
    31. <ProgressBar android:id="@+id/pb" android:layout_width="fill_parent"
    32. android:layout_height="wrap_content" style="?android:attr/progressBarStyleHorizontal"
    33. android:layout_weight="9"/>
    34. <TextView android:layout_height="wrap_content" android:layout_width="wrap_content"
    35. android:text="@string/remain_time" android:layout_weight="1"/>
    36. <TextView android:layout_height="wrap_content" android:layout_width="wrap_content"
    37. android:id="@+id/show_remainTime" android:layout_weight="1"/>
    38. </TableRow>
    39. 这是显示时间进度条的,以及时间 剩余时间(秒)和倒计时300.
    40. 这是海贼王连连看的界面的大致介绍。
    41. 2. 下面详细解释一下海贼王连连看。
    42. 1). public class Net1314080903126GameView extends View {
    43. public final int row = 10;
    44. public float width;
    45. public float height;
    46. private int selY;
    47. private int selX;
    48. public boolean isLine = false;
    49. public int grid[][] = new int[row][col];
    50. private Rect selRect = new Rect();
    51. public int lineType = 0;
    52. public final int V_LINE = 1;
    53. public final int H_LINE = 1;
    54. public final int ONE_C_LINE = 2;
    55. public int much = 0;
    56. Point[] p;
    57. public int[] imageType = new int[] { R.drawable.net1314080903126aa, R.drawable.net1314080903126bb,
    58. R.drawable.net1314080903126cc, R.drawable.net1314080903126dd, R.drawable.net1314080903126ee, R.drawable.net1314080903126ff,
    59. R.drawable.net1314080903126gg, R.drawable.net1314080903126hh, R.drawable.net1314080903126ii, R.drawable.net1314080903126jj,
    60. R.drawable.net1314080903126kk, R.drawable.net1314080903126ll, R.drawable.net1314080903126mm, R.drawable.net1314080903126nn,
    61. R.drawable.net1314080903126oo, R.drawable.net1314080903126pp};
    62. public Bitmap[] image;
    63. public List<Integer> type = new ArrayList<Integer>();
    64. 这个是Net1314080903126GameView.java文件中,调用图片。public final int row = 10;
    65. public final int col = 10;图片的布局分布十行十列显示。以及显示大小尺寸。调用drawable文件下的图片显示在界面上。
    66. (2). <TextView android:layout_height="wrap_content" android:layout_width="wrap_content"
    67. android:text="@string/remain_time" android:layout_weight="1"/>
    68. 这是显示剩余时间(秒)
    69. (3). <ProgressBar android:id="@+id/pb" android:layout_width="fill_parent"
    70. android:layout_height="wrap_content" style="?android:attr/progressBarStyleHorizontal"
    71. android:layout_weight="9"/>
    72. 这是显示倒计时时间进度条的。
    73. (4). <TextView android:layout_height="wrap_content" android:layout_width="wrap_content"
    74. android:id="@+id/show_remainTime" android:layout_weight="1"/>
    75. 这是显示300时间的跑秒。
    76. (5).public boolean onCreateOptionsMenu(Menu menu) {
    77. // TODO Auto-generated method stub
    78. menu.add(0, START_ID, 0, R.string.newgame);
    79. menu.add(0, REARRARY_ID, 0, R.string.rearrage);
    80. menu.add(0, END_ID, 0, R.string.exit);
    81. return super.onCreateOptionsMenu(menu);
    82. }
    83. 这是页面上方选项菜单,可以选择(新游戏,重排列以及退出游戏)这三个功能。
    84. (6).public AlertDialog dialogForSucceed() {
    85. AlertDialog.Builder builder = new AlertDialog.Builder(this);
    86. builder.setIcon(R.drawable.icon).setMessage(R.string.succeedInfo)
    87. .setPositiveButton(R.string.next,
    88. new DialogInterface.OnClickListener() {
    89. @Override
    90. public void onClick(DialogInterface dialog,
    91. int which) {
    92. // TODO Auto-generated method stub
    93. dormant = dormant - 300;
    94. newPlay();
    95. }
    96. }).setNeutralButton(R.string.again_challenge,
    97. new DialogInterface.OnClickListener() {
    98. @Override
    99. public void onClick(DialogInterface dialog,
    100. int which) {
    101. // TODO Auto-generated method stub
    102. newPlay();
    103. }
    104. });
    105. return builder.create();
    106. }
    107. public AlertDialog dialogForFail() {
    108. AlertDialog.Builder builder = new AlertDialog.Builder(this);
    109. builder.setIcon(R.drawable.icon).setMessage(R.string.failInfo)
    110. .setPositiveButton(R.string.again_challenge,
    111. new DialogInterface.OnClickListener() {
    112. @Override
    113. public void onClick(DialogInterface dialog,
    114. int which) {
    115. // TODO Auto-generated method stub
    116. newPlay();
    117. }
    118. }).setNegativeButton(R.string.exit,
    119. new DialogInterface.OnClickListener() {
    120. @Override
    121. public void onClick(DialogInterface dialog,
    122. int which) {
    123. // TODO Auto-generated method stub
    124. isCancel=false;
    125. finish();
    126. }
    127. });
    128. return builder.create();
    129. }
    130. 这是显示300秒内完成游戏提示通往下一关,以及没有完成游戏提示你不气馁。
    131. 以上就是海贼王练练看看游戏界面的详细实现过程。
    132. ###4. 制作扫雷游戏界面
    133. 简要说明:这里介绍的是扫雷游戏的初始界面和游戏进行界面的实现方法,它是通过获取每个格子的id值来调用显示相应的背景图片。
    134. 详细步骤:
    135. 1. 先获取每个格子对象,再给每个格子对象编号或下标获取id值,代码如下:

    public int getCount() {
    return levellevel;
    }
    /*

    // 调用GameGroundEntity中的getEntity方法获取格子对象
    return gameGround.getEntity(position);
    }
    /**

    1. * 方法:通过适配器给每个格子对象编号或下标获取id
    2. * @return long类型,在java中,byteshort可自动转换为intint可自动转换为long
    3. * */
    4. @Override
    5. public long getItemId(int position) {
    6. return position;
    7. }
    1. 2.设置格子对象的背景图片, 不同状态下设置不同的背景图片(i00,i13等是图片的名字)
    1. * */
    2. public int getRes(GridEntity grid){

    // 设置格子对象的背景图片的ID为0
    int resID=0;
    // 判断,如果格子对象被标记了且标记正确
    if(grid.isFlag()&&!grid.isFlagWrong()){
    resID=R.drawable.i_flag;
    }
    // 判断,如果格子对象被标记了但标记不正确
    else if(grid.isFlag()&&grid.isFlagWrong()){
    resID=R.drawable.i14;
    }
    // 判断,如果格子对象没有被点击,isShow()属性为false
    else if(!grid.isShow()){
    resID=R.drawable.i00;
    }
    // 判断,格子对象是地雷且非自动显示
    else if(grid.isBoom()&&!grid.isAutoShow()){
    resID=R.drawable.i13;
    }
    // 判断,格子对象是地雷,自动显示
    else if(grid.isBoom()&&grid.isAutoShow()){
    resID=R.drawable.i12;
    }
    // 判断,格子周围没有地雷,是空白格
    else if(grid.getBoomsCount()==0){
    resID=R.drawable.i09;
    }
    // 判断,格子中卫有地雷,个数为1-8个
    else if(grid.getBoomsCount()!=0){
    // 动态拼接图片名,格式为图片名称,图片类型,资源所在包名
    resID=context.getResources().getIdentifier(“i0”+grid.getBoomsCount(),”drawable”,context.getPackageName());
    }
    return resID;
    }

    1. 源代码:!https://github.com/hzuapps/android-labs/tree/master/app/src/main/java/edu/hzuapps/androidworks/homeworks/com1314080901110
    2. ###5. 制作围住神经猫游戏界面
    3. 简要说明:简单版的围住神经猫游戏的背景是一排排的圆圈,可以用二维数组创建,而这些圆圈有三种状态,分别为猫可以走并可以设置路障的位置(灰色),猫所处的位置(红色),猫不能走并已开启路障的位置(橘色),这些状态定义在Dot类中,显然其应该有坐标XY;游戏的背景等我都放在Playground类中,背景是基于SurfaceView开发的,而里面还有很多功能,如猫和已设路障的初始化位置,猫如何躲路障,如何判断路可走,判断处在边界位置等等;最后在Activity中调用Playground
    4. 详细步骤:
    5. 1. 建立Dot类,用来记录每个场景中的元素它的X,Y坐标点的状态。并不会直接参与界面的响应和界面的绘制。每一个点都是一个抽象的对象,需要把每一个点抽象为一个类,然后让每一个圆圈继承于这个类,或者直接把它实现为这个类的实例。每个点有三个状态:灰色-猫可走的路径;橘色-路障的状态
    6. 无法改变;红色-猫当前的位置。

    public class Net1314080903142Dot {

    1. int x,y;//当前点的X,Y坐标
    2. int status;//记录这个点的状态
    3. //三个表征圆点状态静态常量
    4. public static final int STATUS_ON = 1;//已经开启路障的状态
    5. public static final int STATUS_OFF = 0;//代表灰色可走路径
    6. public static final int STATUS_IN = 9;//猫当前的位置
    7. //三个数字不同即可,具体用哪个数字无所谓
    8. //指定X,Y坐标
    9. public Net1314080903142Dot(int x, int y) {
    10. super();
    11. this.x = x;
    12. this.y = y;
    13. status = STATUS_OFF;
    14. }
    15. //指定geter和sette方法
    16. public int getX() {
    17. return x;
    18. }
    19. public void setX(int x) {
    20. this.x = x;
    21. }
    22. public int getY() {
    23. return y;
    24. }
    25. public void setY(int y) {
    26. this.y = y;
    27. }
    28. public int getStatus() {
    29. return status;
    30. }
    31. public void setStatus(int status) {
    32. this.status = status;
    33. }
    34. //同时设置X,Y坐标的方法
    35. public void setXY(int x,int y) {
    36. this.y = y;
    37. this.x = x;
    38. }

    }

    1. 2.建立Playground类,用来绘制界面还有实现游戏的各种算法。以下只详细介绍界面的绘制还有每个圆圈状态转化的过程。

    public class Net1314080903142Playground extends SurfaceView implements OnTouchListener{
    //界面的响应和界面的绘制在SurfaceView完成,触摸事件的响应通过OnTouchListener接口实现

    1. private static int WIDTH = 40;
    2. private static final int ROW = 10;//行高:每行储存10个元素
    3. private static final int COL = 10;//列宽:每列储存10个元素
    4. private static final int BLOCKS = 15;//默认添加的路障数量
    5. private Dot Net1314080903142matrix[][];//声明二维数组来存放点元素
    6. private Dot Net1314080903142cat;//声明猫这个点
    7. public Net1314080903142Playground(Context context) {
    8. super(context);//使用Context创建当前类构造函数
    9. getHolder().addCallback(callback);//将Callback对象指定给getholder
    10. matrix = new Net1314080903142Dot[ROW][COL];//将行高,列宽传递进去,指定数组大小
    11. for (int i = 0; i < ROW; i++) {//循环添加数据
    12. for (int j = 0; j < COL; j++) {
    13. matrix[i][j] = new Net1314080903142Dot(j, i);/*X,Y坐标值和行列值是相反的。
    14. 即通过查找列值获得X坐标,查找行值获得Y坐标*/
    15. }
    16. setOnTouchListener(this);//设定为自己的触摸监听器
    17. initGame();//调用游戏初始化
    18. }
    19. //坐标反转:封装一个getDot函数实现X,Y坐标反过来传递,所有的操作通过X,Y调用
    20. private Net1314080903142Dot getDot(int x,int y) {
    21. return matrix[y][x];
    22. }
    23. //实现猫移动到下一个点
    24. private void MoveTo(Net1314080903142Dot one) {
    25. one.setStatus(Net1314080903142Dot.STATUS_IN);//one的状态设置为猫所处的点
    26. getDot(cat.getX(), cat.getY()).setStatus(Net1314080903142Dot.STATUS_OFF);;//将猫当前点的状态复位
    27. cat.setXY(one.getX(), one.getY());//将猫移动到新的点
    28. }
    29. //猫的移动
    30. private void move() {
    31. if (isAtEdge(cat)) {
    32. lose();return;/猫处于游戏边缘,失败
    33. }
    34. Vector<Net1314080903142Dot> avaliable = new Vector<Net1314080903142Dot>();//avaliable容器记录可用点
    35. Vector<Net1314080903142Dot> positive = new Vector<Net1314080903142Dot>();//positive容器记录这个方向上可以直接到达屏幕边缘的路径
    36. HashMap<Net1314080903142Dot, Integer> al = new HashMap<Net1314080903142Dot, Integer>();//al容器记录方向
    37. for (int i = 1; i < 7; i++) {//如果当前猫被6个邻点围住
    38. Net1314080903142Dot n = getNeighbour(cat, i);
    39. if (n.getStatus() == Net1314080903142Dot.STATUS_OFF) {
    40. avaliable.add(n);//如果相邻点可用,把它添加到avaliable记录器中
    41. al.put(n, i);//为al传入方向i
    42. if (getDistance(n, i) > 0) {
    43. positive.add(n);//当它有一个路径可以直接到达屏幕边缘,把n传递进positive中
    44. }
    45. }
    46. }
    47. //移动算法的优化
    48. if (avaliable.size() == 0) {
    49. win();//周围的6个点都不可走,没有可用点,成功围住猫
    50. }else if (avaliable.size() == 1) {
    51. MoveTo(avaliable.get(0));//只有一个方向可走,可用点有一个,移动到这个可用点上
    52. }else{//有多个方向可走
    53. Net1314080903142Dot best = null;
    54. if (positive.size() != 0 ) {//存在可以直接到达屏幕边缘的走向
    55. System.out.println("向前进");
    56. int min = 999;//999远大于场景中的所有可用步长,其他数也可
    57. for (int i = 0; i < positive.size(); i++) {
    58. int a = getDistance(positive.get(i), al.get(positive.get(i)));
    59. if (a < min) {
    60. min = a;//把最短路径长度传给min
    61. best = positive.get(i);//选出拥有最短路径的点
    62. }
    63. }
    64. MoveTo(best);
    65. }else {//所有方向都存在路障
    66. System.out.println("躲路障");
    67. int max = 0;
    68. for (int i = 0; i < avaliable.size(); i++) {
    69. int k = getDistance(avaliable.get(i), al.get(avaliable.get(i)));
    70. if (k <= max) {//所有方向都存在路障,距离k为负数
    71. max = k;
    72. best = avaliable.get(i);//选出拥有最短路径的点
    73. }
    74. }
    75. MoveTo(best);//移动到最短路径的下一点
    76. }
    77. }
    78. }
    79. //实现界面绘制,在redraw方法中将所有元素以图形化显示出来,也就是将它绘制在Canvas对象上
    80. private void redraw() {
    81. Canvas c = getHolder().lockCanvas();//锁定画布
    82. c.drawColor(Color.LTGRAY);//设置颜色为浅灰色
    83. Paint paint = new Paint();//创建Paint对象
    84. paint.setFlags(Paint.ANTI_ALIAS_FLAG);//开启抗锯齿,优化视频质量
    85. //用两个For循环嵌套将所有的点显示到界面中来
    86. for (int i = 0; i < ROW; i++) {
    87. int offset = 0;//引入偏移量
    88. if (i%2 != 0) {
    89. offset = WIDTH/2;//对偶数行进行缩进
    90. }
    91. for (int j = 0; j < COL; j++) {
    92. Net1314080903142Dot one = getDot(j, i);//将坐标赋值给内部变量one
    93. //由于每个点对应的三种状态颜色不一样,要用一个switch语句
    94. switch (one.getStatus()) {
    95. case Net1314080903142Dot.STATUS_OFF:
    96. paint.setColor(0xFFEEEEEE);//STATUS_OFF状态时设置颜色为浅灰色
    97. break;
    98. case Net1314080903142Dot.STATUS_ON:
    99. paint.setColor(0xFFFFAA00);//STATUS_ON状态时设置颜色为橘色
    100. break;
    101. case Net1314080903142Dot.STATUS_IN:
    102. paint.setColor(0xFFFF0000);//STATUS_IN状态时设置颜色为红色
    103. break;
    104. default:
    105. break;
    106. }
    107. c.drawOval(new RectF(one.getX()*WIDTH+offset, one.getY()*WIDTH,
    108. (one.getX()+1)*WIDTH+offset, (one.getY()+1)*WIDTH), paint);
    109. /*在Canvas画布上画椭圆并界定它的上下左右边界宽度且有错位*/
    110. }
    111. }
    112. getHolder().unlockCanvasAndPost(c);//取消Canvas的锁定,吧绘图内容更新到界面上
    113. }
    114. //为Surfaceview添加Callback
    115. Callback callback = new Callback() {//声明并实例化一个Callback接口
    116. @Override
    117. public void surfaceDestroyed(SurfaceHolder arg0) {
    118. // TODO Auto-generated method stub
    119. }
    120. @Override
    121. public void surfaceCreated(SurfaceHolder arg0) {
    122. // TODO Auto-generated method stub
    123. redraw();//执行redraw函数,在界面第一次显示时将指定的内容显示到界面上
    124. }
    125. @Override
    126. //使用surfaceChanged方法来适配不同的屏幕尺寸
    127. public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
    128. //surfacechanged方法包含四个参数:SurfaceHolder holder,int format,int width,int height
    129. // TODO Auto-generated method stub
    130. WIDTH = arg2/(COL+1);//需要修改width,即arg2。
    131. redraw();//重绘界面
    132. }
    133. };
    134. //游戏初始化:分别对可走路径位置,猫的位置和路障位置进行初始化
    135. private void initGame() {
    136. //用for循环将所有点设置为STATUS_OFF,即可用状态
    137. for (int i = 0; i < ROW; i++) {
    138. for (int j = 0; j < COL; j++) {
    139. matrix[i][j].setStatus(Net1314080903142Dot.STATUS_OFF);
    140. }
    141. }
    142. cat = new Net1314080903142Dot(4, 5);//设置猫的起始点
    143. getDot(4, 5).setStatus(Net1314080903142Dot.STATUS_IN);//把猫的起始点的状态设置为STATUS_IN,才能记录猫的位置
    144. //用for循环随机的指定15个点的坐标作为路障
    145. for (int i = 0; i < BLOCKS;) {
    146. int x = (int) ((Math.random()*1000)%COL);
    147. int y = (int) ((Math.random()*1000)%ROW);//随机获取1对坐标点
    148. if (getDot(x, y).getStatus() == Net1314080903142Dot.STATUS_OFF) {//对当前可用路径点进行选择
    149. getDot(x, y).setStatus(Net1314080903142Dot.STATUS_ON);//并把这个点设置为路障
    150. i++;//循环内自加避免当前路障被重复添加
    151. //System.out.println("Block:"+i);
    152. }
    153. }
    154. }
    155. @Override
    156. //触摸事件的处理
    157. public boolean onTouch(View arg0, MotionEvent e) {
    158. if (e.getAction() == MotionEvent.ACTION_UP) {/当用户触摸之后手离开屏幕释放的瞬间才对事件进行响应
    159. // Toast.makeText(getContext(), e.getX()+":"+e.getY(), Toast.LENGTH_SHORT).show();
    160. //将屏幕的坐标转换为游戏的坐标
    161. int x,y;
    162. y = (int) (e.getY()/WIDTH);//横向状态下,奇、偶数行有坐标偏移,而纵向的Y值是不变的,将y进行转换
    163. if (y%2 == 0) {
    164. x = (int) (e.getX()/WIDTH);//奇数行直接将屏幕的X坐标转换成游戏的X坐标
    165. }else {
    166. x = (int) ((e.getX()-WIDTH/2)/WIDTH);//偶数行偏移半个元素宽度,故需减去WIDTH/2
    167. }
    168. //数组越界异常时,对坐标进行保护
    169. if (x+1 > COL || y+1 > ROW) {
    170. initGame();//触摸超出边界时初始化游戏
    171. }else if(getDot(x, y).getStatus() == Net1314080903142Dot.STATUS_OFF){
    172. getDot(x, y).setStatus(Net1314080903142Dot.STATUS_ON);//当这个点可用时被点击之后设定为路障状态
    173. move();
    174. }
    175. redraw();//将改变更新到界面
    176. }
    177. return true;
    178. }

    }

    public class Net1314080903142Activity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        setContentView(new Net1314080903142Playground(this));//Context把MainActivity的this传递进去
    }
    

    }

    
    备注:实现该游戏的其他算法未列出,有兴趣的可以在该网站看全部代码:https://github.com/hzuapps/android-labs/issues/139
    
    ###6. 自动滚动Banner图片
    
    ####简要说明:
    本程序实现的是图片轮播banner,主要运用得到的控件为ViewPager,具体有以下功能:
    
    >a.定时功能,每隔5S切换下一张图片。
    
    >b.手动切换,可手势左右滑动选择上一张或下一张图片。
    >
    >c.跳转功能,点击跳转对应Activity
    
    ####详细步骤
    
    1.指示器圆点,有两个状态,分别为选中和为选中。用两个shape实现。存放在drawable文件夹下
    
    
    - 未选中状态:net1314080903118_dot_normal.xml
    
    ```xml
    
        <?xml version="1.0" encoding="utf-8"?>
        <shape xmlns:android="http://schemas.android.com/apk/res/android"
            android:shape="oval" >
    
            <solid android:color="#33000000" />
    
            <corners android:radius="5dip" />
    
        </shape>
    
    • 选中状态:net1314080903118_dot_press.xml
    
        <?xml version="1.0" encoding="utf-8"?>
        <shape xmlns:android="http://schemas.android.com/apk/res/android"
            android:shape="oval" >
    
            <solid android:color="#aaFFFFFF" />
    
            <corners android:radius="5dip" />
    
        </shape>
    

    2.布局文件,主要用于显示图片的是ViewPager,九个View分别对应九个圆点,即可同时存放九张图片用于轮播。View的background使用上面定义的选中未选中状态。这里我单独抽取出来,使用时在主布局文件用 include 引入即可。

    
        <?xml version="1.0" encoding="utf-8"?>
        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" >
    
            <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="160dp" >
    
                <android.support.v4.view.ViewPager
                    android:id="@+id/vp"
                    android:layout_width="match_parent"
                    android:layout_height="160dp" />
    
    
                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="10dip"
                    android:layout_gravity="bottom|center_horizontal"
                    android:layout_marginBottom="10dp"
                    android:gravity="center" >
    
                    <View
                        android:id="@+id/v_dot0"
                        android:layout_width="5dip"
                        android:layout_height="5dip"
                        android:background="@drawable/net1314080903118_dot_press"
                        android:layout_marginLeft="1.5dip"
                        android:layout_marginRight="1.5dip"
                        android:visibility="invisible" />
    
                    <View
                        android:id="@+id/v_dot1"
                        android:layout_width="5dip"
                        android:layout_height="5dip"
                        android:background="@drawable/net1314080903118_dot_normal"
                        android:layout_marginLeft="1.5dip"
                        android:layout_marginRight="1.5dip"
                        android:visibility="invisible"/>
    
                    <View
                        android:id="@+id/v_dot2"
                        android:layout_width="5dip"
                        android:layout_height="5dip"
                        android:background="@drawable/net1314080903118_dot_normal"
                        android:layout_marginLeft="1.5dip"
                        android:layout_marginRight="1.5dip"
                        android:visibility="invisible"/>
    
                    <View
                        android:id="@+id/v_dot3"
                        android:layout_width="5dip"
                        android:layout_height="5dip"
                        android:background="@drawable/net1314080903118_dot_normal"
                        android:layout_marginLeft="1.5dip"
                        android:layout_marginRight="1.5dip"
                        android:visibility="invisible"/>
    
                    <View
                        android:id="@+id/v_dot4"
                        android:layout_width="5dip"
                        android:layout_height="5dip"
                        android:background="@drawable/net1314080903118_dot_normal"
                        android:layout_marginLeft="1.5dip"
                        android:layout_marginRight="1.5dip"
                        android:visibility="invisible" />
                    <View
                        android:id="@+id/v_dot5"
                        android:layout_width="5dip"
                        android:layout_height="5dip"
                        android:background="@drawable/net1314080903118_dot_normal"
                        android:layout_marginLeft="1.5dip"
                        android:layout_marginRight="1.5dip"
                        android:visibility="invisible" />
                    <View
                        android:id="@+id/v_dot6"
                        android:layout_width="5dip"
                        android:layout_height="5dip"
                        android:background="@drawable/net1314080903118_dot_normal"
                        android:layout_marginLeft="1.5dip"
                        android:layout_marginRight="1.5dip"
                        android:visibility="invisible" />
                    <View
                        android:id="@+id/v_dot7"
                        android:layout_width="5dip"
                        android:layout_height="5dip"
                        android:background="@drawable/net1314080903118_dot_normal"
                        android:layout_marginLeft="1.5dip"
                        android:layout_marginRight="1.5dip"
                        android:visibility="invisible" />
                    <View
                        android:id="@+id/v_dot8"
                        android:layout_width="5dip"
                        android:layout_height="5dip"
                        android:background="@drawable/net1314080903118_dot_normal"
                        android:layout_marginLeft="1.5dip"
                        android:layout_marginRight="1.5dip"
                        android:visibility="invisible" />
                </LinearLayout>
            </FrameLayout>
    
        </LinearLayout>
    
    
        private void startAd() {
                scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
                // 当Activity显示出来后,每两秒切换一次图片显示
                scheduledExecutorService.scheduleAtFixedRate(new ScrollTask(), 1, 5,
                        TimeUnit.SECONDS);
            }
    
    
        private class ScrollTask implements Runnable {
    
                @Override
                public void run() {
                    synchronized (adViewPager) {
                        currentItem = (currentItem + 1) % imageViews.size();
                        handler.obtainMessage().sendToTarget();
                    }
                }
            }
    
    
        private Handler handler = new Handler() {
                public void handleMessage(android.os.Message msg) {
                    adViewPager.setCurrentItem(currentItem);
                };
            };
    

    4.具体代码如下: