实验4:Android界面设计

8.1 知识点

1.

2.

8.2 实例讲解

1. 设计仿微信导航界面

简要说明……
详细步骤……

2. 制作黑白棋游戏界面

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

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

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

  1. * 方法:获取每个格子对象
  2. * @param position 格子编号,位置下标
  3. * @return 格子类型的GameGroundEntity
  4. * */
  5. @Override
  6. public GridEntity getItem(int position) {

// 调用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等是图片的名字)

@param grid :格子对象

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

}


3.最后创建Activity,调用Playground。

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 引入即可。

  • net1314080903118_banner.xml

    <?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>

3.关键代码

定时切换用到一个类:ScheduledExecutorService

作用是定时执行任务,我们这里要做的定时任务是,5秒执行一次图片切换


    private void startAd() {
            scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
            // 当Activity显示出来后,每两秒切换一次图片显示
            scheduledExecutorService.scheduleAtFixedRate(new ScrollTask(), 1, 5,
                    TimeUnit.SECONDS);
        }

定义一个线程,滑动时通知handle响应,同时更改圆点索引号


    private class ScrollTask implements Runnable {

            @Override
            public void run() {
                synchronized (adViewPager) {
                    currentItem = (currentItem + 1) % imageViews.size();
                    handler.obtainMessage().sendToTarget();
                }
            }
        }

通过handle来通知ViewPager进行视图切换


    private Handler handler = new Handler() {
            public void handleMessage(android.os.Message msg) {
                adViewPager.setCurrentItem(currentItem);
            };
        };

异步线程加载网络图片,具体代码我封装在Net1314080903118MyRequest.java中,详情可查看最后的链接。

4.具体代码如下:


    public class BannerTestActivity extends AppCompatActivity {

        private Context mContext;
        private ViewPager adViewPager;
        private List<ImageView> imageViews;// 滑动的图片集合
        private List<View> dots; // 图片标题正文的那些点
        private List<View> dotList;

        private int currentItem = 0; // 当前图片的索引号
        // 定义的五个指示点
        private View dot0,dot1,dot2,dot3,dot4,dot5,dot6,dot7,dot8;

        // 定时任务
        private ScheduledExecutorService scheduledExecutorService;

        // 轮播banner的数据
        private List<String> mDataList = null;

        private Handler handler = new Handler() {
            public void handleMessage(android.os.Message msg) {
                adViewPager.setCurrentItem(currentItem);
            };
        };

        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.net1314080903118);
            setTitle("Net1314080903118");
            mContext = BannerTestActivity.this;
            initDatas();
            initView();
            startAd();
        }

        /**
         * 添加九张图片的数据,用作模拟数据
         */
        private void initDatas() {
            mDataList = new ArrayList<>();
            mDataList.add("http://image.wufazhuce.com/Fi7nIAI3UFK4x42mwu4g18O3s8JO");
            mDataList.add("http://image.wufazhuce.com/Fn8JdRZ1g9IVbfSxrdAD6zYFVz3h");
            mDataList.add("http://image.wufazhuce.com/FjJPOSVbypiddiRbyHrws7AN6NlX");
            mDataList.add("http://image.wufazhuce.com/FiyEgeiSFJFLrOQxerXZOY-50LQr");
            mDataList.add("http://image.wufazhuce.com/Fg-EwcAuXvdd2ZvOQI8ym4EToRot");
            mDataList.add("http://image.wufazhuce.com/Fi7nIAI3UFK4x42mwu4g18O3s8JO");
            mDataList.add("http://image.wufazhuce.com/Fn8JdRZ1g9IVbfSxrdAD6zYFVz3h");
            mDataList.add("http://image.wufazhuce.com/FjJPOSVbypiddiRbyHrws7AN6NlX");
            mDataList.add("http://image.wufazhuce.com/FiyEgeiSFJFLrOQxerXZOY-50LQr");
            mDataList.add("http://image.wufazhuce.com/Fg-EwcAuXvdd2ZvOQI8ym4EToRot");
            mDataList.add("http://image.wufazhuce.com/Fi7nIAI3UFK4x42mwu4g18O3s8JO");
        }


        private void initView() {
            imageViews = new ArrayList<ImageView>();
            // 点
            dots = new ArrayList<View>();
            dotList = new ArrayList<View>();
            dot0 = findViewById(R.id.v_dot0);
            dot1 = findViewById(R.id.v_dot1);
            dot2 = findViewById(R.id.v_dot2);
            dot3 = findViewById(R.id.v_dot3);
            dot4 = findViewById(R.id.v_dot4);
            dot5 = findViewById(R.id.v_dot5);
            dot6 = findViewById(R.id.v_dot6);
            dot7 = findViewById(R.id.v_dot7);
            dot8 = findViewById(R.id.v_dot8);
            dots.add(dot0);
            dots.add(dot1);
            dots.add(dot2);
            dots.add(dot3);
            dots.add(dot4);
            dots.add(dot5);
            dots.add(dot6);
            dots.add(dot7);
            dots.add(dot8);

            adViewPager = (ViewPager) findViewById(R.id.vp);

            loadViewPager();
        }

        private void addDynamicView() {
            // 动态添加图片和下面指示的圆点
            // 初始化图片资源
            for (int i = 0; i < mDataList.size(); i++) {
                ImageView imageView = new ImageView(mContext);
                new Net1314080903118MyRequest(mContext).getImage(mDataList.get(i),imageView);
                imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
                imageViews.add(imageView);
                dots.get(i).setVisibility(View.VISIBLE);
                dotList.add(dots.get(i));
            }

        }


        /**
         * 定时任务,5s更换一次
         */
        private void startAd() {
            scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
            // 当Activity显示出来后,每两秒切换一次图片显示
            scheduledExecutorService.scheduleAtFixedRate(new ScrollTask(), 1, 5,
                    TimeUnit.SECONDS);
        }


        /**
         * 自定义线程,滑动时通知handle响应
         */
        private class ScrollTask implements Runnable {

            @Override
            public void run() {
                synchronized (adViewPager) {
                    currentItem = (currentItem + 1) % imageViews.size();
                    handler.obtainMessage().sendToTarget();
                }
            }
        }

        @Override
        public void onStop() {
            super.onStop();
            // 当Activity不可见的时候停止切换
            scheduledExecutorService.shutdown();
        }

        /**
         * 重写ViewPager,改变圆点是否选中状态
         * 在这里我们不需要重写ViewPager的滑动动作
         */
        private class MyPageChangeListener implements ViewPager.OnPageChangeListener {

            private int oldPosition = 0;

            @Override
            public void onPageScrollStateChanged(int arg0) {

            }

            @Override
            public void onPageScrolled(int arg0, float arg1, int arg2) {

            }

            @Override
            public void onPageSelected(int position) {
                currentItem = position;
                dots.get(oldPosition).setBackgroundResource(R.drawable.net1314080903118_dot_normal);
                dots.get(position).setBackgroundResource(R.drawable.net1314080903118_dot_press);
                oldPosition = position;
            }
        }

        private void loadViewPager() {
            addDynamicView();
            // 设置填充ViewPager页面的适配器
            adViewPager.setAdapter(new Net1314080903118MyAdapter(mContext,mDataList, imageViews));
            // 设置一个监听器,当ViewPager中的页面改变时调用
            adViewPager.setOnPageChangeListener(new MyPageChangeListener());
        }

        /**
         * 自定义ViewPager的适配器,具体点击图片的跳转逻辑在instantiateItem中实现
         */
        public class Net1314080903118MyAdapter extends PagerAdapter {

            private List<String> DataList;
            private List<ImageView> imageList;
            private Context mContext;

            public Net1314080903118MyAdapter(Context context,List<String> adList,List<ImageView> imageViews){
                this.DataList = adList;
                this.imageList = imageViews;
                this.mContext = context;
            }

            @Override
            public int getCount() {
                return DataList.size();
            }

            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                ImageView iv = imageList.get(position);
                ((ViewPager) container).addView(iv);
                // 在这个方法里面设置图片的点击事件
                iv.setOnClickListener(new View.OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        // 处理跳转逻辑
                    }
                });
                return iv;
            }

            @Override
            public void destroyItem(View arg0, int arg1, Object arg2) {
                ((ViewPager) arg0).removeView((View) arg2);
            }

            @Override
            public boolean isViewFromObject(View arg0, Object arg1) {
                return arg0 == arg1;
            }

            @Override
            public void restoreState(Parcelable arg0, ClassLoader arg1) {

            }

            @Override
            public Parcelable saveState() {
                return null;
            }

            @Override
            public void startUpdate(View arg0) {

            }

            @Override
            public void finishUpdate(View arg0) {

            }

        }
    }

备注:完整代码请访问以下链接

https://github.com/hzuapps/android-labs/issues/139