自定义控件--五子棋


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();
    }



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值