自定义view之 五子棋

自定义view

public class GobangPanel extends View {

    private int mPanelWidth;   //五子棋宽度
    private float mLineHeight;	//边框线高度
    private int MAX_LINE = 10;		//最大行数
    private int MAX_COUNT_IN_LINE=5;		//数量为5的时候就胜利了

    private Paint mPaint = new Paint();				//画笔

    private Bitmap mWhitePiece;				//白棋
    private Bitmap mBlackPiece;				//黑棋					

    private float ratioPieceOfLineHeight = 3 * 1.0f / 4;

    //白棋先手,当前轮到白棋
    private boolean mIsWhite = true;
    private ArrayList<Point> mWhiteArray = new ArrayList<>();
    private ArrayList<Point> mBlackArray = new ArrayList<>();

    private boolean mIsGameOver;
    private boolean mIsWhiteWinner;

    public GobangPanel(Context context,  AttributeSet attrs) {
        super(context, attrs);
        //setBackgroundColor(0x44ff0000);
        init();
    }

    private void init() {
        mPaint.setColor(0x88000000);
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setStyle(Paint.Style.STROKE);

        mWhitePiece = BitmapFactory.decodeResource(getResources(), R.mipmap.stone_w2);
        mBlackPiece = BitmapFactory.decodeResource(getResources(), R.mipmap.stone_b1);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);

        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        int width = Math.min(widthSize, heightSize);

        if (widthMode == MeasureSpec.UNSPECIFIED) {
            width = heightSize;
        } else if (heightMode == MeasureSpec.UNSPECIFIED) {
            width = widthSize;
        }
        setMeasuredDimension(width, width);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        mPanelWidth = w;
        mLineHeight = mPanelWidth * 1.0f / MAX_LINE;

        int pieceWidth = (int) (mLineHeight * ratioPieceOfLineHeight);

        mWhitePiece = Bitmap.createScaledBitmap(mWhitePiece, pieceWidth, pieceWidth, false);
        mBlackPiece = Bitmap.createScaledBitmap(mBlackPiece, pieceWidth, pieceWidth, false);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mIsGameOver){
            return false;
        }
        int action = event.getAction();
        if (action == MotionEvent.ACTION_UP) {
            int x = (int) event.getX();
            int y = (int) event.getY();

            Point p = getValidPoint(x, y);

            if (mWhiteArray.contains(p) || mBlackArray.contains(p)) {
                return false;
            }

            if (mIsWhite) {
                mWhiteArray.add(p);
            } else {
                mBlackArray.add(p);
            }
            invalidate();
            mIsWhite = !mIsWhite;
        }
        return true;
    }

    private Point getValidPoint(int x, int y) {
        return new Point((int) (x / mLineHeight), (int) (y / mLineHeight));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        drawBoard(canvas);
        drawPieces(canvas);
        checkGameOver();
    }

    private void checkGameOver() {
        boolean whiteWin= checkFiveInLine(mWhiteArray);
        boolean blackWin= checkFiveInLine(mBlackArray);

        if (whiteWin||blackWin){
            mIsGameOver=true;
            mIsWhiteWinner=whiteWin;

            String text=mIsWhiteWinner?"白棋胜利":"黑棋胜利";
            Toast.makeText(getContext(),text,Toast.LENGTH_SHORT).show();
        }
    }

    private boolean checkFiveInLine(List<Point> points) {
        for (Point p:points){
            int x=p.x;
            int y=p.y;

            boolean win= checkHorizontal(x,y,points);
            if (win){
                return true;
            }
            win= checkVetical(x,y,points);
            if (win){
                return true;
            }
            win= checkLeftDiagonal(x,y,points);
            if (win){
                return true;
            }
            win= checkRightDiagonal(x,y,points);
            if (win){
                return true;
            }
        }
        return false;
    }

    /**
     * 判断x,x位置的棋子,是否横向有相邻的五个一致
     * @param x
     * @param y
     * @param points
     * @return
     */
    private boolean checkHorizontal(int x, int y, List<Point> points) {
        int count=1;
        //左
        for (int i=1;i<MAX_COUNT_IN_LINE;i++){
            if (points.contains(new Point(x-i,y))){
                count++;
            }else {
                break;
            }
        }
        if (count==MAX_COUNT_IN_LINE){
            return true;
        }
        //右
        for (int i=1;i<MAX_COUNT_IN_LINE;i++){
            if (points.contains(new Point(x+i,y))){
                count++;
            }else {
                break;
            }
        }

        if (count==MAX_COUNT_IN_LINE){
            return true;
        }
        return false;
    }

    private boolean checkVetical(int x, int y, List<Point> points) {
        int count=1;
        //上
        for (int i=1;i<MAX_COUNT_IN_LINE;i++){
            if (points.contains(new Point(x,y-i))){
                count++;
            }else {
                break;
            }
        }
        if (count==MAX_COUNT_IN_LINE){
            return true;
        }
        //下
        for (int i=1;i<MAX_COUNT_IN_LINE;i++){
            if (points.contains(new Point(x,y+i))){
                count++;
            }else {
                break;
            }
        }

        if (count==MAX_COUNT_IN_LINE){
            return true;
        }
        return false;
    }

    private boolean checkLeftDiagonal(int x, int y, List<Point> points) {
        int count=1;
        //左
        for (int i=1;i<MAX_COUNT_IN_LINE;i++){
            if (points.contains(new Point(x-i,y+i))){
                count++;
            }else {
                break;
            }
        }
        if (count==MAX_COUNT_IN_LINE){
            return true;
        }
        //右
        for (int i=1;i<MAX_COUNT_IN_LINE;i++){
            if (points.contains(new Point(x+i,y-i))){
                count++;
            }else {
                break;
            }
        }

        if (count==MAX_COUNT_IN_LINE){
            return true;
        }
        return false;
    }

    private boolean checkRightDiagonal(int x, int y, List<Point> points) {
        int count=1;
        //左
        for (int i=1;i<MAX_COUNT_IN_LINE;i++){
            if (points.contains(new Point(x-i,y-i))){
                count++;
            }else {
                break;
            }
        }
        if (count==MAX_COUNT_IN_LINE){
            return true;
        }
        //右
        for (int i=1;i<MAX_COUNT_IN_LINE;i++){
            if (points.contains(new Point(x+i,y+i))){
                count++;
            }else {
                break;
            }
        }

        if (count==MAX_COUNT_IN_LINE){
            return true;
        }
        return false;
    }

    private void drawPieces(Canvas canvas) {
        for (int i = 0, n = mWhiteArray.size(); i < n; i++) {
            Point whitePoint = mWhiteArray.get(i);
            canvas.drawBitmap(mWhitePiece, (whitePoint.x + (1 - ratioPieceOfLineHeight) / 2) * mLineHeight, (whitePoint.y + (1 - ratioPieceOfLineHeight) / 2) * mLineHeight, null);
        }
        for (int i = 0, n = mBlackArray.size(); i < n; i++) {
            Point blackPoint = mBlackArray.get(i);
            canvas.drawBitmap(mBlackPiece, (blackPoint.x + (1 - ratioPieceOfLineHeight) / 2) * mLineHeight, (blackPoint.y + (1 - ratioPieceOfLineHeight) / 2) * mLineHeight, null);
        }
    }

    private void drawBoard(Canvas canvas) {
        int w = mPanelWidth;
        float lineHeight = mLineHeight;

        //绘制横线
        for (int i = 0; i < MAX_LINE; i++) {
            int startX = (int) (lineHeight / 2);
            int endX = (int) (w - lineHeight / 2);
            int y = (int) ((0.5 + i) * lineHeight);
            canvas.drawLine(startX, y, endX, y, mPaint);
        }
        //绘制竖线
        for (int i = 0; i < MAX_LINE; i++) {
            int startY = (int) (lineHeight / 2);
            int endY = (int) (w - lineHeight / 2);
            int x = (int) ((0.5 + i) * lineHeight);
            canvas.drawLine(x, startY, x, endY, mPaint);
        }
    }

    public void start(){
        mWhiteArray.clear();
        mBlackArray.clear();
        mIsGameOver=false;
        mIsWhiteWinner=false;
        invalidate();
    }

    private static final String INSTANCE="instance";
    private static final String INSTANCE_GAME_OVER="instance_game_over";
    private static final String INSTANCE_WHITE_ARRAY="instance_white_array";
    private static final String INSTANCE_BLACK_ARRAY="instance_black_array";

    @Override
    protected Parcelable onSaveInstanceState() {
        Bundle bundle=new Bundle();
        bundle.putParcelable(INSTANCE,super.onSaveInstanceState());
        bundle.putBoolean(INSTANCE_GAME_OVER,mIsGameOver);
        bundle.putParcelableArrayList(INSTANCE_WHITE_ARRAY,mWhiteArray);
        bundle.putParcelableArrayList(INSTANCE_BLACK_ARRAY,mBlackArray);
        return bundle;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        if (state instanceof Bundle){
            Bundle bundle= (Bundle) state;
            mIsGameOver=bundle.getBoolean(INSTANCE_GAME_OVER);
            mWhiteArray=bundle.getParcelableArrayList(INSTANCE_WHITE_ARRAY);
            mBlackArray=bundle.getParcelableArrayList(INSTANCE_BLACK_ARRAY);
            super.onRestoreInstanceState(bundle.getParcelable(INSTANCE));
            return;
        }
        super.onRestoreInstanceState(state);
    }
}

创建menu文件夹 创建menu_main.xml

<item android:id="@+id/action_settings"
    android:title="@string/one_more_game"
    android:orderInCategory="100"
    android:showAsAction="never"/>

values 里面的 strings.xml

<string name="app_name" tools:ignore="ExtraTranslation">五子棋</string>
<string name="one_more_game">再来一局</string>

activity_mian.xml

<com.example.asus.gobang.GobangPanel
    android:id="@+id/gobang"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_centerInParent="true" />
## MainActivity.java public class MainActivity extends Activity {
private GobangPanel gobangPanel;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    gobangPanel=findViewById(R.id.gobang);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_main,menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int id=item.getItemId();
    if (id== R.id.action_settings){
        gobangPanel.start();
        return true;
    }
    return super.onOptionsItemSelected(item);
}

}

@mipmap/bg 背景图

在这里插入图片描述

stone_b1 黑棋图片

在这里插入图片描述

stone_w2 白棋图片

在这里插入图片描述

效果图

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
TypeArray 是 Android 中的一个特殊的资源类型,用于在 XML 中声明自定义 View 的属性。使用 TypeArray 可以方便地在 XML 布局中指定 View 的属性,而不需要在 Java 代码中进行硬编码。 使用 TypeArray 的步骤如下: 1. 在 res/values/attrs.xml 文件中定义自定义 View 的属性。 ```xml <resources> <declare-styleable name="MyCustomView"> <attr name="customAttr1" format="integer" /> <attr name="customAttr2" format="string" /> <attr name="customAttr3" format="boolean" /> </declare-styleable> </resources> ``` 2. 在自定义 View 的构造函数中获取 TypedArray 对象,并从中获取属性值。 ```java public class MyCustomView extends View { private int customAttr1; private String customAttr2; private boolean customAttr3; public MyCustomView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyCustomView); customAttr1 = a.getInt(R.styleable.MyCustomView_customAttr1, 0); customAttr2 = a.getString(R.styleable.MyCustomView_customAttr2); customAttr3 = a.getBoolean(R.styleable.MyCustomView_customAttr3, false); a.recycle(); } } ``` 在上面的代码中,`context.obtainStyledAttributes(attrs, R.styleable.MyCustomView)` 用于获取 TypedArray 对象,`R.styleable.MyCustomView` 是在 attrs.xml 文件中定义的自定义属性集合,`a.getInt()`、`a.getString()`、`a.getBoolean()` 用于从 TypedArray 对象中获取属性值,最后需要调用 `a.recycle()` 来回收 TypedArray 对象。 3. 在 XML 布局中使用自定义 View,并设置属性值。 ```xml <com.example.MyCustomView android:layout_width="match_parent" android:layout_height="wrap_content" app:customAttr1="123" app:customAttr2="hello" app:customAttr3="true" /> ``` 在上面的代码中,`app:customAttr1`、`app:customAttr2`、`app:customAttr3` 是在 attrs.xml 文件中定义的自定义属性名,可以在 XML 布局中使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值