自定义View+五子棋的简单实现

先看一张效果图:



首先我们要想实现以上的效果,就要先绘制棋盘和棋子。用系统中的组件是很难实现的,那么就需要我们自定义组件。

绘制棋盘:

在绘制棋盘之前,我们先应该测量棋盘的大小,然后再进行绘制。所以一定要重写onMeasure()和onDraw()方法。

第一步:

重写view的onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法,代码如下:



MeasureSpec类:
主要是封装父布局对子布局的一个布局要求,主要有三种模式。UNSPECIFIED(未指定),父元素不对子元素施加任何束缚,子元素可以得到任意想要的大小;
EXACTLY(完全),父元素决定子元素的确切大小,子元素将被限定在给定的边界里而忽略它本身大小;AT_MOST(至多),子元素至多达到指定大小的值。
它有三个常用的方法,分别为:
getMode()根据提供的测量值(格式)提取模式(上述三个模式之一)
getSize()根据提供的测量值(格式)提取大小值
makeMeasureSpec()根据提供的大小值和模式创建一个测量值
setMeasuredDimension():设置自定义view的大小
注意:当自定义的view的外面套上Linerlayout,而Linerlayout外面又套上ScrollView时,Linerlayout的高度设置成warp_content,
这时heightMode可能为UNSPECIFIED,那么heightSize可能就为0。所以Math.min(widthSize,heightSize)可能取值为0,那么width就可能取值为0,这样就会造成无法显示自定义view的尴尬,所以要进行
if(widthMode==MeasureSpec.UNSPECIFIED){
    width=heightSize;
}else if(heightMode==MeasureSpec.UNSPECIFIED){
    width=widthSize;
}
这样的判断。

View中有一个onSizeChanged(int w, int h, int oldw, int old)方法,这个是系统回调方法,是系统调用的,这个方法会在这个view的大小发生改变是被系统调用,我们要记住的就是view大小变化,这个方法就被执行就可以了。

在五子棋的绘制中,我们在此方法中初始化了棋盘的宽度,行高,以及对棋子的图片进行了缩放。代码如下:

protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    mWidthPanel=w;
    mHeightLine=mWidthPanel*1.0f/MAX_LINE;

    int pieceWidth= (int) (mHeightLine * roatePieceOfLineHeight);
    //createScaledBitmap缩放一个bitmap
    mWhitePiece=Bitmap.createScaledBitmap(mWhitePiece,pieceWidth,pieceWidth,false);
    mBlackPiece=Bitmap.createScaledBitmap(mBlackPiece,pieceWidth,pieceWidth,false);
}
MAX_LINE:自定义的常量,表示行数。
第二步:
重写view的 onDraw (Canvas canvas)方法,代码如下:


drawBoard(canvas):绘制棋盘。

drawPiece(canvas):绘制棋子。

既然讲到绘制棋子,那么我们应该怎样会绘制棋子呢!?我们知道棋子是在动态绘制的,也就说我们触摸棋盘规定的位置就会出现一颗棋子,而且棋子是根据坐标坐标集合来绘制的。所以我们可以在onTouchEvent(MotionEvent event)事件里面记录棋子的坐标,由于有两种颜色的棋子,所以需要准备两个集合。代码如下:

这里要注意onTouchEvent中的ACTION_DOWN必须返回true,这表明onTouchEvent会处理点击事件,否则表明,触摸事件不被响应,通过里面的代码逻辑的第一句话我哦们也可以知道,当游戏结束的时候,返回false,这时候不可以再在棋盘上下棋子。对于view的触摸事件处理机制,将在下一篇文章中介绍。
棋子绘制之后,接下来就是一些逻辑处理了,这里就不再啰嗦,在源码中会有具体实现。
这样一个简单的五子棋就实现了,最后还有一点,就是当重新绘制界面的时候,我们要向保持上一个界面的状态的时候,该怎么做。
我们知道在Activity中,我们要向在保存上一次的状态,需要在onPause中做状态保存,然后在onCreate中获取保存的状态即可。而对于自定义的View,我们也可以重写里面的onSaveInstanceState()和onRestoreInstanceState(Parcelable state)方法来保存和恢复状态。
这里我们要保存的就是棋子的坐标和游戏是否结束的判断。代码如下:


注意:当完成上述操作之后,我们发现还是无法保存状态,这是因为我们需要在主布局中给添加的自定义View设置id,为什么??
其实我也不知道原因,哈哈。不过我在网上搜索之后,看到下面这篇文章写的很详细易懂。网址:
android中正确保存View状态
这里大致总结下:
首先看看保存和恢复的示意图:

保存状态时,安卓framework调用saveHierarchyState(SparseArray<Parcelable> container)方法,saveHierarchyState会调用dispatchSaveInstanceState() ,而在dispatchSaveInstanceState()内部又会调用onSaveInstanceState()方法。

onSaveInstanceState()返回一个代表当前状态的Parcelable,这个Parcelable被保存在container参数中,container参数是一个键值对的map集合。View的ID是键Parcelable是值。至此我们就应该明白了为什么我们需要给View设置id了,这个id是标识当前view的唯一标识,如果这个id我们就无法识别当前view,也无法保存当前view的状态。

下面给出五子棋实现的源码:





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值