自定义控件--五子棋

来源:互联网 发布:简单效果图制作软件 编辑:程序博客网 时间:2024/05/19 17:07

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>
代码第一步:先测量自定义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);//保存自身的宽高    }
代码第二步:根据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();        }    }
代码第五步:处理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();    }



2 0