1.先测量自定义View自身的宽高,然后保存
2.根据View的确定宽高来画棋盘上面的格子
3.与用户交互的时候落子,根据确定的宽高来确定黑白棋子的宽高
4.绘制棋子
5.处理5颗棋子连成线的逻辑
6.自定义View保存状态的标准写法
7.再来一局实现
----------------------------------------------------
效果图
布局xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.docwei.wuziqidemo.WuZiQiView
android:id="@+id/wuziqi"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"/>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:onClick="restart"
android:text="再来一局"/>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.docwei.wuziqidemo.WuZiQiView
android:id="@+id/wuziqi"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"/>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:onClick="restart"
android:text="再来一局"/>
</RelativeLayout>
代码第一步:先测量自定义View自身的宽高,然后保存
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获取在布局文件里面精确测量(match_parent或者具体dp值)的宽高
int widthSize=MeasureSpec.getSize(widthMeasureSpec);
int widthMode=MeasureSpec.getMode(widthMeasureSpec);
int heightSize=MeasureSpec.getSize(heightMeasureSpec);
int heightMode=MeasureSpec.getMode(heightMeasureSpec);
//如将该自定义控件放在其他的ViewGroup里面,尤其是ScrollView可能会出现测量模式不是精确测量
if(widthMode==MeasureSpec.UNSPECIFIED){
widthSize=heightSize;
}else if(heightMode==MeasureSpec.UNSPECIFIED){
heightSize=widthSize;
}
//要保证我们的棋盘是一个正方形,所以选取小的作为该正方形的边长
int width=Math.min(widthSize,heightSize);
setMeasuredDimension(width,width);//保存自身的宽高
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获取在布局文件里面精确测量(match_parent或者具体dp值)的宽高
int widthSize=MeasureSpec.getSize(widthMeasureSpec);
int widthMode=MeasureSpec.getMode(widthMeasureSpec);
int heightSize=MeasureSpec.getSize(heightMeasureSpec);
int heightMode=MeasureSpec.getMode(heightMeasureSpec);
//如将该自定义控件放在其他的ViewGroup里面,尤其是ScrollView可能会出现测量模式不是精确测量
if(widthMode==MeasureSpec.UNSPECIFIED){
widthSize=heightSize;
}else if(heightMode==MeasureSpec.UNSPECIFIED){
heightSize=widthSize;
}
//要保证我们的棋盘是一个正方形,所以选取小的作为该正方形的边长
int width=Math.min(widthSize,heightSize);
setMeasuredDimension(width,width);//保存自身的宽高
}
代码第二步:根据View的确定宽高来画棋盘上面的格子
代码第三步:.与用户交互的时候落子,根据确定的宽高来确定黑白棋子的宽高
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
panelWidth=w;
rawHeight=panelWidth*1.0f/(LINE_MAX);//左右各留一半行高的的空白
//黑白棋子的图片太大也不要紧,这里对图片的显示进行处理
int bitmapWidth= (int) (rawHeight*bitmap2rawHeight);
mWhiteBitmap=Bitmap.createScaledBitmap(mWhiteBitmap,bitmapWidth, bitmapWidth,false);
mBlackBitmap=Bitmap.createScaledBitmap(mBlackBitmap,bitmapWidth, bitmapWidth,false);
}
private void drawGrid(Canvas canvas) {
for(int i=0;i<LINE_MAX+1;i++){
float startX=rawHeight/2;
float endX=panelWidth-rawHeight/2;
float startY=rawHeight/2;
float endY=panelWidth-rawHeight/2;
canvas.drawLine(startX,startY+i*rawHeight,endX,startY+i*rawHeight,mPaint);
canvas.drawLine(startX+i*rawHeight,startY,startX+i*rawHeight,endY,mPaint);
}
}
代码第四步:绘制棋子
private void drawQiZi(Canvas canvas) {
for (int i=0,n=mWhitePoints.size();i<n;i++) {
Point point = mWhitePoints.get(i);//里面重写了equals方法
canvas.drawBitmap(mWhiteBitmap,(point.x+(1.0f/2-bitmap2rawHeight*1/2))*rawHeight,
(point.y+(1.0f/2-bitmap2rawHeight*1/2))*rawHeight,null);
}
for(int i=0,n=mBlackPoints.size();i<n;i++) {
Point point = mBlackPoints.get(i);//里面重写了equals方法
canvas.drawBitmap(mBlackBitmap,(point.x+(1.0f/2-bitmap2rawHeight*1/2))*rawHeight,(point.y+(1.0f/2-bitmap2rawHeight*1/2))*rawHeight,null);
}
//遍历每一个点,,这样真的好么
boolean isWhiteWin=check5InLine(mWhitePoints);
if(isWhiteWin){
isGameOver=true;
Toast.makeText(getContext(),"白棋胜利",Toast.LENGTH_SHORT).show();
}
boolean isBlackWin=check5InLine(mBlackPoints);
if(isBlackWin){
isGameOver=true;
Toast.makeText(getContext(),"黑棋胜利",Toast.LENGTH_SHORT).show();
}
}
private void drawQiZi(Canvas canvas) {
for (int i=0,n=mWhitePoints.size();i<n;i++) {
Point point = mWhitePoints.get(i);//里面重写了equals方法
canvas.drawBitmap(mWhiteBitmap,(point.x+(1.0f/2-bitmap2rawHeight*1/2))*rawHeight,
(point.y+(1.0f/2-bitmap2rawHeight*1/2))*rawHeight,null);
}
for(int i=0,n=mBlackPoints.size();i<n;i++) {
Point point = mBlackPoints.get(i);//里面重写了equals方法
canvas.drawBitmap(mBlackBitmap,(point.x+(1.0f/2-bitmap2rawHeight*1/2))*rawHeight,(point.y+(1.0f/2-bitmap2rawHeight*1/2))*rawHeight,null);
}
//遍历每一个点,,这样真的好么
boolean isWhiteWin=check5InLine(mWhitePoints);
if(isWhiteWin){
isGameOver=true;
Toast.makeText(getContext(),"白棋胜利",Toast.LENGTH_SHORT).show();
}
boolean isBlackWin=check5InLine(mBlackPoints);
if(isBlackWin){
isGameOver=true;
Toast.makeText(getContext(),"黑棋胜利",Toast.LENGTH_SHORT).show();
}
}
代码第五步:处理5颗棋子连成线的逻辑
private boolean check5InLine(ArrayList<Point> points) {
for(Point point:points){
if(checkHorizatol(point,points)) return true;
if(checkVertical(point,points)) return true;
if(checkLeftSlant(point,points)) return true;
if(chekcRigheSlant(point,points)) return true;
}
return false;
}
private boolean chekcRigheSlant(Point CurrentPoint,ArrayList<Point> points) {
int count=1;//当前粒是5粒中的1粒
for(int i=1;i<QIZI_IN_LINE;i++){
if(points.contains(new Point(CurrentPoint.x+i,CurrentPoint.y+i))){
count++;
}else{
break;//如果不是连续的,立即退出
}
}
if(count==QIZI_IN_LINE) return true;
for(int i=1;i<QIZI_IN_LINE;i++){
if(points.contains(new Point(CurrentPoint.x-i,CurrentPoint.y-i))){
count++;
}else{
break;//如果不是连续的,立即退出
}
}
if(count==QIZI_IN_LINE) return true;
return false;
}
private boolean checkLeftSlant(Point CurrentPoint,ArrayList<Point> points) {
int count=1;//当前粒是5粒中的1粒
for(int i=1;i<QIZI_IN_LINE;i++){
if(points.contains(new Point(CurrentPoint.x+i,CurrentPoint.y-i))){
count++;
}else{
break;//如果不是连续的,立即退出
}
}
if(count==QIZI_IN_LINE) return true;
for(int i=1;i<QIZI_IN_LINE;i++){
if(points.contains(new Point(CurrentPoint.x-i,CurrentPoint.y+i))){
count++;
}else{
break;//如果不是连续的,立即退出
}
}
if(count==QIZI_IN_LINE) return true;
return false;
}
private boolean checkVertical(Point CurrentPoint,ArrayList<Point> points) {
int count=1;//当前粒是5粒中的1粒
for(int i=1;i<QIZI_IN_LINE;i++){
if(points.contains(new Point(CurrentPoint.x,CurrentPoint.y+i))){
count++;
}else{
break;//如果不是连续的,立即退出
}
}
if(count==QIZI_IN_LINE) return true;
for(int i=1;i<QIZI_IN_LINE;i++){
if(points.contains(new Point(CurrentPoint.x,CurrentPoint.y-i))){
count++;
}else{
break;//如果不是连续的,立即退出
}
}
if(count==QIZI_IN_LINE) return true;
return false;
}
private boolean checkHorizatol(Point CurrentPoint,ArrayList<Point> points) {
int count=1;//当前粒是5粒中的1粒
for(int i=1;i<QIZI_IN_LINE;i++){
if(points.contains(new Point(CurrentPoint.x+i,CurrentPoint.y))){
count++;
}else{
break;//如果不是连续的,立即退出
}
}
if(count==QIZI_IN_LINE) return true;
for(int i=1;i<QIZI_IN_LINE;i++){
if(points.contains(new Point(CurrentPoint.x-i,CurrentPoint.y))){
count++;
}else{
break;//如果不是连续的,立即退出
}
}
if(count==QIZI_IN_LINE) return true;
return false;
}
/* private void check5InLine() {
//水平的5粒连成线,从当前粒向左或者向右遍历,有5粒在一条线上,就赢了
check5InLine(mWhitePoints);
check5InLine(mBlackPoints);
}*/
代码第六步:自定义View保存状态的标准写法
//是自定义控件的保存恢复状态的标准写法
@Override
protected Parcelable onSaveInstanceState() {
Bundle bundle=new Bundle();
bundle.putParcelable("superState",super.onSaveInstanceState());
bundle.putBoolean("isGameOver",isGameOver);
bundle.putParcelableArrayList("WhitePoints",mWhitePoints);
bundle.putParcelableArrayList("BlackPoints",mBlackPoints);
return bundle;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if(state instanceof Bundle){
Bundle bundle= (Bundle) state;
isGameOver=bundle.getBoolean("isGameOver");
mWhitePoints=bundle.getParcelableArrayList("WhitePoints");
mBlackPoints=bundle.getParcelableArrayList("BlackPoints");
state=bundle.getParcelable("superState");
}
super.onRestoreInstanceState(state);
}
代码第七步:再来一局实现
//再来一局
public void restart(){
isGameOver=false;
mWhitePoints.clear();
mBlackPoints.clear();
invalidate();
}