我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android游戏开发之黑白棋

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android游戏开发之黑白棋

黑白棋介绍

黑白棋,又叫苹果棋,最早流行于西方国家。游戏通过相互翻转对方的棋子,最后以棋盘上谁的棋子多来判断胜负。黑白棋非常易于上手,但精通则需要考虑许多因素,比如角边这样的特殊位置、稳定度、行动力等。本游戏取名为黑白棋大师,提供了8种难度等级的选择,从菜鸟、新手、入门、棋手到棋士、大师、宗师、棋圣,助你不断提升棋力。

黑白棋游戏规则

游戏规则见黑白棋大师中的截图。

黑白棋大师游戏截图

游戏启动界面。

游戏过程中的一个截图。

开新局时的选项,选择先后手以及AI的水平。

几个关键的类

Rule

Rule类实现游戏规则相关的方法,包括

    1.判断某一步是否合法

    2.获取所有的合法走步

    3.走一步并翻转敌方棋子

    4.统计两方棋子个数

Algorithm

Algorithm类实现极小极大算法,包括

    1.局面评估函数,对当前局面打分,越高对max越有利,越低对min越有利

    2.min()方法

    3.max()方法

    4.获得一个好的走步

ReversiView

ReversiView继承自SurfaceView,实现棋盘的界面,在该类定义棋盘界面的绘制、更新等操作。

RenderThread

RenderThread继承自Thread,是控制ReversiView以一定fps更新、重绘界面的线程。

具体实现

棋盘表示

byte[][]
二维数组存储棋盘,-1表示有黑子,1表示有白子,0表示棋格为空

游戏规则类Rule的实现

提供几个关于游戏规则的静态方法。

判断某一个位置是否位于棋盘内


public static boolean isLegal(int row, int col) {
  return row >= 0 && row < 8 && col >= 0 && col < 8;
}

判断某一方在某个位置落子是否合法

即判断该子是否能与己方棋子在某个方向上夹住敌方棋子。


public static boolean isLegalMove(byte[][] chessBoard, Move move, byte chessColor) {
    int i, j, dirx, diry, row = move.row, col = move.col;
    if (!isLegal(row, col) || chessBoard[row][col] != Constant.NULL)
      return false;
    for (dirx = -1; dirx < 2; dirx++) {
      for (diry = -1; diry < 2; diry++) {
        if (dirx == 0 && diry == 0) continue;
        int x = col + dirx, y = row + diry;
        if (isLegal(y, x) && chessBoard[y][x] == (-chessColor)) {
          for (i = row + diry * 2, j = col + dirx * 2; isLegal(i, j); i += diry, j += dirx) {
            if (chessBoard[i][j] == (-chessColor)) {
              continue;
            } else if (chessBoard[i][j] == chessColor) {
              return true;
            } else {
              break;
            }
          }
        }
      }
    }
    return false;
}

某一方走一步子

将各个方向上被翻转的棋子的颜色改变,并返回这些棋子在棋盘的位置,方便显示翻转动画。


public static List<Move> move(byte[][] chessBoard, Move move, byte chessColor) {
  int row = move.row;
  int col = move.col;
  int i, j, temp, m, n, dirx, diry;
  List<Move> moves = new ArrayList<Move>();
  for (dirx = -1; dirx < 2; dirx++) {
    for (diry = -1; diry < 2; diry++) {
      if (dirx == 0 && diry == 0)
        continue;
      temp = 0;
      int x = col + dirx, y = row + diry;
      if (isLegal(y, x) && chessBoard[y][x] == (-chessColor)) {
        temp++;
        for (i = row + diry * 2, j = col + dirx * 2; isLegal(i, j); i += diry, j += dirx) {
          if (chessBoard[i][j] == (-chessColor)) {
            temp++;
            continue;
          } else if (chessBoard[i][j] == chessColor) {
            for (m = row + diry, n = col + dirx; m <= row + temp && m >= row - temp && n <= col + temp
                && n >= col - temp; m += diry, n += dirx) {
              chessBoard[m][n] = chessColor;
              moves.add(new Move(m, n));
            }
            break;
          } else
            break;
        }
      }
    }
  }
  chessBoard[row][col] = chessColor;
  return moves;
}

获取某一方当前全部合法的落子位置


public static List<Move> getLegalMoves(byte[][] chessBoard, byte chessColor) {
  List<Move> moves = new ArrayList<Move>();
  Move move = null;
  for (int row = 0; row < 8; row++) {
    for (int col = 0; col < 8; col++) {
      move = new Move(row, col);
      if (Rule.isLegalMove(chessBoard, move, chessColor)) {
        moves.add(move);
      }
    }
  }
  return moves;
}

统计玩家和AI的棋子个数


public static Statistic analyse(byte[][] chessBoard, byte playerColor) {
  int PLAYER = 0;
  int AI = 0;
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {
      if (chessBoard[i][j] == playerColor)
        PLAYER += 1;
      else if (chessBoard[i][j] == (byte)-playerColor)
        AI += 1;
    }
  }
  return new Statistic(PLAYER, AI);
}

游戏算法类Algorithm的实现

极大过程和极小过程

这两个过程的函数形式为:

代码如下:
private static MinimaxResult max(byte[][] chessBoard, int depth, int alpha, int beta, byte chessColor, int difficulty);
private static MinimaxResult min(byte[][] chessBoard, int depth, int alpha, int beta, byte chessColor, int difficulty);

chessBoard为棋盘;depth为博弈树搜索深度;alpha和beta用于alpha-beta剪枝,在max方法中alpha不断更新为局面评分的较大值,在min方法中beta不断更新为局面评分的较小值,当alpha >= beta时就进行剪枝;chessColor表示棋子颜色;difficulty表示游戏难度,对应于不同的AI水平。

由于黑子先行,黑子总是调用max()方法,白子调用min()方法。

下面以极大过程为例。

如果深度为0,只要返回当前局面评分即可。如果双方均没有步可走,表示已经达到最终局面,返回该局面评分。如果仅单方无处可走,调用min递归即可。

正常情况下有步可走,遍历每个合法的走步,如果alpha大于等于beta,剪枝直接break,否则走步并递归。

best是当前max节点维护的一个最佳值,调用的min方法的alpha是取得alpha和best的较大值。


private static MinimaxResult max(byte[][] chessBoard, int depth, int alpha, int beta, byte chessColor, int difficulty) {
  if (depth == 0) {
    return new MinimaxResult(evaluate(chessBoard, difficulty), null);
  }
  List<Move> legalMovesMe = Rule.getLegalMoves(chessBoard, chessColor);
  if (legalMovesMe.size() == 0) {
    if (Rule.getLegalMoves(chessBoard, (byte)-chessColor).size() == 0) {
      return new MinimaxResult(evaluate(chessBoard, difficulty), null);
    }
    return min(chessBoard, depth, alpha, beta, (byte)-chessColor, difficulty);
  }
  byte[][] tmp = new byte[8][8];
  Util.copyBinaryArray(chessBoard, tmp);
  int best = Integer.MIN_VALUE;
  Move move = null;
  for (int i = 0; i < legalMovesMe.size(); i++) {
    alpha = Math.max(best, alpha);
    if(alpha >= beta){
      break;
    }
    Rule.move(chessBoard, legalMovesMe.get(i), chessColor);
    int value = min(chessBoard, depth - 1, Math.max(best, alpha), beta, (byte)-chessColor, difficulty).mark;
    if (value > best) {
      best = value;
      move = legalMovesMe.get(i);
    }
    Util.copyBinaryArray(tmp, chessBoard);
  }
  return new MinimaxResult(best, move);
}
private static MinimaxResult min(byte[][] chessBoard, int depth, int alpha, int beta, byte chessColor, int difficulty) {
  if (depth == 0) {
    return new MinimaxResult(evaluate(chessBoard, difficulty), null);
  }
  List<Move> legalMovesMe = Rule.getLegalMoves(chessBoard, chessColor);
  if (legalMovesMe.size() == 0) {
    if (Rule.getLegalMoves(chessBoard, (byte)-chessColor).size() == 0) {
      return new MinimaxResult(evaluate(chessBoard, difficulty), null);
    }
    return max(chessBoard, depth, alpha, beta, (byte)-chessColor, difficulty);
  }
  byte[][] tmp = new byte[8][8];
  Util.copyBinaryArray(chessBoard, tmp);
  int best = Integer.MAX_VALUE;
  Move move = null;
  for (int i = 0; i < legalMovesMe.size(); i++) {
    beta = Math.min(best, beta);
    if(alpha >= beta){
      break;
    }
    Rule.move(chessBoard, legalMovesMe.get(i), chessColor);
    int value = max(chessBoard, depth - 1, alpha, Math.min(best, beta), (byte)-chessColor, difficulty).mark;
    if (value < best) {
      best = value;
      move = legalMovesMe.get(i);
    }
    Util.copyBinaryArray(tmp, chessBoard);
  }
  return new MinimaxResult(best, move);
}

alpha-beta剪枝原理

先解释下alpha和beta的物理含义,alpha表示max节点迄今为止的最佳局面评分,beta表示min节点迄今为止的最佳局面评分。

举个例子见下图(数值为虚构),假设深度是两层,每个结点有两行数字,上方的两个数分别是alpha和beta,表示作为参数传到该层的alpha和beta。下方的数表示了该节点best的更新过程。

看图中第一个红色的叉号,该位置处会更新beta为正无穷和2的较小值,即2,导致alpha大于等于beta成立,发生剪枝,对应于min方法中相应位置处的break操作。

获得AI计算出的最佳走步

该方法用于AI走步以及提示功能。


public static Move getGoodMove(byte[][] chessBoard, int depth, byte chessColor, int difficulty) {
    if (chessColor == Constant.BLACK)
      return max(chessBoard, depth, Integer.MIN_VALUE, Integer.MAX_VALUE, chessColor, difficulty).move;
    else
      return min(chessBoard, depth, Integer.MIN_VALUE, Integer.MAX_VALUE, chessColor, difficulty).move;
}

局面评估函数

局面评估函数决定了AI水平的高低。对应于不同的AI等级,设计了不同的评估函数。

菜鸟级别只关注棋子个数,新手、入门、棋手3个级别不仅关注棋子的个数,而且关注特殊位置的棋子(边、角),棋士和大师级别在棋子个数、边角之外还考虑了行动力,即对方下轮可选的下子位置的个数,宗师和棋圣考虑稳定度和行动力。稳定度将在下一小节介绍。


private static int evaluate(byte[][] chessBoard, int difficulty) {
    int whiteEvaluate = 0;
    int blackEvaluate = 0;
    switch (difficulty) {
    case 1:
      for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
          if (chessBoard[i][j] == WHITE) {
            whiteEvaluate += 1;
          } else if (chessBoard[i][j] == BLACK) {
            blackEvaluate += 1;
          }
        }
      }
      break;
    case 2:
    case 3:
    case 4:
      for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
          if ((i == 0 || i == 7) && (j == 0 || j == 7)) {
            if (chessBoard[i][j] == WHITE) {
              whiteEvaluate += 5;
            } else if (chessBoard[i][j] == BLACK) {
              blackEvaluate += 5;
            }
          } else if (i == 0 || i == 7 || j == 0 || j == 7) {
            if (chessBoard[i][j] == WHITE) {
              whiteEvaluate += 2;
            } else if (chessBoard[i][j] == BLACK) {
              blackEvaluate += 2;
            }
          } else {
            if (chessBoard[i][j] == WHITE) {
              whiteEvaluate += 1;
            } else if (chessBoard[i][j] == BLACK) {
              blackEvaluate += 1;
            }
          }
        }
      }
      break;
    case 5:
    case 6:
      for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
          if ((i == 0 || i == 7) && (j == 0 || j == 7)) {
            if (chessBoard[i][j] == WHITE) {
              whiteEvaluate += 5;
            } else if (chessBoard[i][j] == BLACK) {
              blackEvaluate += 5;
            }
          } else if (i == 0 || i == 7 || j == 0 || j == 7) {
            if (chessBoard[i][j] == WHITE) {
              whiteEvaluate += 2;
            } else if (chessBoard[i][j] == BLACK) {
              blackEvaluate += 2;
            }
          } else {
            if (chessBoard[i][j] == WHITE) {
              whiteEvaluate += 1;
            } else if (chessBoard[i][j] == BLACK) {
              blackEvaluate += 1;
            }
          }
        }
      }
      blackEvaluate = blackEvaluate * 2 + Rule.getLegalMoves(chessBoard, BLACK).size();
      whiteEvaluate = whiteEvaluate * 2 + Rule.getLegalMoves(chessBoard, WHITE).size();
      break;
    case 7:
    case 8:
      
      for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9; j++) {
          int weight[] = new int[] { 2, 4, 6, 10, 15 };
          if (chessBoard[i][j] == WHITE) {
            whiteEvaluate += weight[getStabilizationDegree(chessBoard, new Move(i, j))];
          } else if (chessBoard[i][j] == BLACK) {
            blackEvaluate += weight[getStabilizationDegree(chessBoard, new Move(i, j))];
          }
        }
      }
      
      blackEvaluate += Rule.getLegalMoves(chessBoard, BLACK).size();
      whiteEvaluate += Rule.getLegalMoves(chessBoard, WHITE).size();
      break;
    }
    return blackEvaluate - whiteEvaluate;
}

稳定度计算

我们知道,在黑白棋中,棋盘四角的位置一旦占据是不可能再被翻转的,因此这几个位置上的子必然是稳定子,而边上的子只有可能沿边的方向被翻转,稳定的程度高于中间的位置上的子。

因此,试图给每个子定义一个稳定度,描述该子不被翻转的稳定程度。

一共有四个方向,即左-右,上-下,左上-右下,右上-左下。举个例子,下面代码中的 (drow[0][0], dcol[0][0])表示向左移动一个单位的向量,(drow[0][1], dcol[0][1])表示向右移动一个单位的向量。

对于棋盘中某个子的位置,向左找到第一个不是该颜色的位置(可以是出界),再向右找到第一个不是该颜色的位置(可以是出界),如果这两个位置至少有一个出界,或者两个均为敌方棋子,稳定度加1。

对于另外三个方向作同样操作。可以看到,角上的棋子的稳定度必然为4,其他位置则根据具体情况并不恒定不变。


private static int getStabilizationDegree(byte[][] chessBoard, Move move) {
    int chessColor = chessBoard[move.row][move.col];
    int drow[][], dcol[][];
    int row[] = new int[2], col[] = new int[2];
    int degree = 0;
    drow = new int[][] { { 0, 0 }, { -1, 1 }, { -1, 1 }, { 1, -1 } };
    dcol = new int[][] { { -1, 1 }, { 0, 0 }, { -1, 1 }, { -1, 1 } };
    for (int k = 0; k < 4; k++) {
      row[0] = row[1] = move.row;
      col[0] = col[1] = move.col;
      for (int i = 0; i < 2; i++) {
        while (Rule.isLegal(row[i] + drow[k][i], col[i] + dcol[k][i])
            && chessBoard[row[i] + drow[k][i]][col[i] + dcol[k][i]] == chessColor) {
          row[i] += drow[k][i];
          col[i] += dcol[k][i];
        }
      }
      if (!Rule.isLegal(row[0] + drow[k][0], col[0] + dcol[k][0])
          || !Rule.isLegal(row[1] + drow[k][1], col[1] + dcol[k][1])) {
        degree += 1;
      } else if (chessBoard[row[0] + drow[k][0]][col[0] + dcol[k][0]] == (-chessColor)
          && chessBoard[row[1] + drow[k][1]][col[1] + dcol[k][1]] == (-chessColor)) {
        degree += 1;
      }
    }
    return degree;
}

以上就是Android黑白棋游戏实现过程及代码解析的全部内容,相信本文对大家开发Android黑白棋游戏很有帮助,谢谢大家对编程网的支持。

您可能感兴趣的文章:Android 重力传感器在游戏开发中的应用Android游戏开发:实现手势操作切换图片的实例Android游戏开发 自定义手势--输入法手势技术安卓(Android)游戏开发音效代码Android游戏开发学习之引擎用法实例详解Android游戏开发学习②焰火绽放效果实现方法Android游戏开发学习①弹跳小球实现方法Android游戏开发实践之人物移动地图的平滑滚动处理Android 游戏开发之Canvas画布的介绍及方法Android 游戏开发入门简单示例


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android游戏开发之黑白棋

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android游戏开发之黑白棋

黑白棋介绍 黑白棋,又叫苹果棋,最早流行于西方国家。游戏通过相互翻转对方的棋子,最后以棋盘上谁的棋子多来判断胜负。黑白棋非常易于上手,但精通则需要考虑许多因素,比如角边这样的特殊位置、稳定度、行动力等。本游戏取名为黑白棋大师,提供了8种难度
2022-06-06

Android 之游戏开发流程

游戏开发流程在不同的项目中会有一些差异,但是一般来说,Android 游戏开发流程可以大致分为以下几个步骤:1. 设计阶段:在这个阶段,你需要确定游戏的类型,玩法以及整体的游戏设计。你可以创建一个游戏概念,制定游戏规则,设计游戏界面和角色等
2023-09-28

Android开发之经典游戏贪吃蛇

前言 这款游戏实现的思路和源码参考了Google自带的Snake的例子,其中修改了一些个人认为还不够完善的地方,加入了一些新的功能,比如屏幕上的方向操作盘,暂停按钮,开始按钮,退出按钮。另外,为了稍微增加些用户体验,除了游戏的主界面,本人自
2022-06-06

微信小程序开发之实现别踩白块游戏

这篇文章主要为大家详细介绍了如何通过微信小程序开发一个简单的别踩白块游戏,文中的示例代码讲解详细,感兴趣的小伙伴可以和小编一起学习一下
2023-02-07

Android实现疯狂连连看游戏之开发游戏界面(二)

连连看的游戏界面十分简单,大致可以分为两个区域: --游戏主界面区 --控制按钮和数据显示区1、开发界面布局本程序使用一个RelativeLayout作为整体的界面布局元素,界面布局上面是一个自定义组件,下面是一个水平排列的LinearLa
2022-06-06

C#游戏开发之实现贪吃蛇游戏

这篇文章主要为大家详细介绍了C#如何实现经典贪吃蛇游戏,文中的示例代码讲解详细,对我们学习C#有一定的帮助,感兴趣的小伙伴可以跟随小编一起了解一下
2023-01-04

C#游戏开发之实现华容道游戏

这篇文章主要为大家详细介绍了C#如何实现经典华容道游戏,文中的示例代码讲解详细,对我们学习C#有一定的帮助,感兴趣的小伙伴可以跟随小编一起了解一下
2023-01-04

探索Unity3D游戏引擎,开启游戏开发之旅(Unity3D游戏引擎在游戏开发中的应用与探索)

Unity3D是一款跨平台游戏引擎,广泛应用于各类游戏开发,包括3D、2D、移动、VR和AR游戏。其优势在于跨平台支持、强大的图形渲染、物理引擎、友好的用户界面和丰富的工具集。探索Unity3D可通过在线教程、官方文档、社区论坛、资产商店和创建游戏原型等方式,帮助开发人员深入了解引擎的工作原理并将其应用于游戏开发中。
探索Unity3D游戏引擎,开启游戏开发之旅(Unity3D游戏引擎在游戏开发中的应用与探索)
2024-04-02

Python开发游戏之井字游戏的实战步骤

最近正在学习Python,所以最近做了一个关于Python的实例,下面这篇文章主要给大家介绍了关于Python开发游戏之井字游戏的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
2023-02-04

C#游戏开发之实现俄罗斯方块游戏

这篇文章主要为大家详细介绍了C#如何实现经典俄罗斯方块游戏,文中的示例代码讲解详细,对我们学习C#有一定的帮助,感兴趣的小伙伴可以跟随小编一起了解一下
2023-01-05

怎么使用Vue开发一个五子棋小游戏

这篇文章主要讲解了“怎么使用Vue开发一个五子棋小游戏”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么使用Vue开发一个五子棋小游戏”吧!1.绘制游戏区域和游戏元素开始写代码之前,一定要记
2023-07-02

Android 游戏开发之Canvas画布的介绍及方法

Canvas,在英语中,这个单词的意思是帆布。在Android中,则把Canvas当做画布,只要我们借助设置好的画笔(Paint类)就可以在画布上绘制我们想要的任何东西;另外它也是显示位图(Bitmap类)的核心类。随用户的喜好,Canva
2022-06-06

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录