日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

安卓第二趴

發(fā)布時間:2025/3/21 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 安卓第二趴 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

今天是對昨天知識的補充

加上新的學(xué)習(xí)內(nèi)容

1.?昨天的內(nèi)容里,有的地方?jīng)]有說的很清楚,今天加以補充。

在說到背景圖的添加的時候,只是簡單的說了放在drawable文件下。但是沒有說明怎么在代碼中實現(xiàn)。

我們知道,我們所有的操作實際上就是在一個畫布上搞來搞去,那么背景圖,既然要作為大背景,理應(yīng)放在一個大的布局范圍。

我們放在RelativeLayout中:

?

這樣我們就可以看到效果圖了:

(和昨天的圖不一樣,因為我換了啊,我還會換的,看心情。。。)

?

2. ????View是我們自定義的。

這里的view相當(dāng)于是在整個大的畫布上圈出了一個范圍,畫過畫的人都知道,所有的畫都不要從一張紙的邊緣處就下筆,要有留白。

我們接下來的操作,比如說繪制網(wǎng)格等等就在這個圈出來的部分進行。

昨天我們只是簡單提了一下view定義了基本的繪圖操作,這里我們詳細說明一下:

基本操作由三個函數(shù)完成:draw()、measure()、layout()。其內(nèi)部又包含了三個子方法:onDraw()、onMeasure()、onLayout()

具體操作如下:

measure操作

? ? ?measure操作主要用于計算視圖的大小,即視圖的寬度和長度。在view中定義為final類型,要求子類不能修改。measure()函數(shù)中又會調(diào)用下面的函數(shù):onMeasure(),視圖大小的將在這里最終確定,也就是說measure只是對onMeasure的一個包裝,子類可以覆寫onMeasure()方法實現(xiàn)自己的計算視圖大小的方式,并通過setMeasuredDimension(width, height)保存計算結(jié)果。

layout操作

? ???layout操作用于設(shè)置視圖在屏幕中顯示的位置。在view中定義為final類型,要求子類不能修改。layout()函數(shù)中有兩個基本操作:

? ? ?(1)setFrame(l,t,r,b),l,t,r,b即子視圖在父視圖中的具體位置,該函數(shù)用于將這些參數(shù)保存起來;

? ? ?(2)onLayout(),在View中這個函數(shù)什么都不會做,提供該函數(shù)主要是為viewGroup類型布局子視圖用的;

draw操作

? ? ?draw操作利用前兩步得到的參數(shù),將視圖顯示在屏幕上,到這里也就完成了整個的視圖繪制工作。子類也不應(yīng)該修改該方法,因為其內(nèi)部定義了繪圖的基本操作:

? ? ?(1)繪制背景;

? ? ?(2)如果要視圖顯示漸變框,這里會做一些準備工作;

? ? ?(3)繪制視圖本身,即調(diào)用onDraw()函數(shù)。在view中onDraw()是個空函數(shù),也就是說具體的視圖都要覆寫該函數(shù)來實現(xiàn)自己的顯示(比如TextView在這里實現(xiàn)了繪制文字的過程)。而對于ViewGroup則不需要實現(xiàn)該函數(shù),因為作為容器是“沒有內(nèi)容“的,其包含了多個子view,而子View已經(jīng)實現(xiàn)了自己的繪制方法,因此只需要告訴子view繪制自己就可以了,也就是下面的dispatchDraw()方法;

? ? ?(4)繪制子視圖,即dispatchDraw()函數(shù)。在view中這是個空函數(shù),具體的視圖不需要實現(xiàn)該方法,它是專門為容器類準備的,也就是容器類必須實現(xiàn)該方法;

? ? ?(5)如果需要(應(yīng)用程序調(diào)用了setVerticalFadingEdge或者setHorizontalFadingEdge),開始繪制漸變框;

? ? ?(6)繪制滾動條;

? ? ? 從上面可以看出自定義View需要最少覆寫onMeasure()和onDraw()兩個方法。

????還記得我們在之前講JAVA的時候說過,抽象父類的所有方法在子類中都要實現(xiàn),這里有異曲同工之妙。

下面我們再聊一聊onMeasure():

onMeasure(int widthMeasureSpec, int heightMeasureSpec)中,兩個參數(shù)的作用: ??? ? ?widthMeasureSpec和heightMeasureSpec這兩個int類型的參數(shù),看名字應(yīng)該知道是跟寬和高有關(guān)系,但它們其實不是寬和高,而是由寬、高和各自方向上對應(yīng)的模式來合成的一個值:其中,在int類型的32位二進制位中,31-30這兩位表示模式,0~29這三十位表示寬和高的實際值.

其中模式一共有三種,被定義在Android中的View類的一個內(nèi)部類中:View.MeasureSpec:

①UNSPECIFIED:表示默認值,父控件沒有給子view任何限制。------二進制表示:00

②EXACTLY:表示父控件給子view一個具體的值,子view要設(shè)置成這些值的大小。

----二進制表示:01

③AT_MOST:表示父控件個子view一個最大的特定值,而子view不能超過這個值的大小。------二進制表示:10

?

那么問題來了,MeasureSpec是什么?

MeasureSpe描述了父View對子View大小的期望.里面包含了測量模式和大小.我們可以通過以下方式從MeasureSpec中提取模式和大小,該方法內(nèi)部是采用位移計算.

int specMode = MeasureSpec.getMode(measureSpec);//得到模式

int specSize = MeasureSpec.getSize(measureSpec);//得到大小

?

也可以通過MeasureSpec的靜態(tài)方法把大小和模式合成,該方法內(nèi)部只是簡單的相加.

MeasureSpec.makeMeasureSpec(specSize,specMode);

?

????每個View都包含一個ViewGroup.LayoutParams類或者其派生類,LayoutParams中包 含了View和它的父View之間的關(guān)系,而View大小正是View和它的父View共同決定的。

我們平常使用類似于RelativeLayout和LinearLayout的時候,在其內(nèi)部添加view的時候,不管是布局文件中加入還是在代碼中使用addView方法添加,實際上都會調(diào)用這個onMeasure方法,而measure和onMeasure中的兩個參數(shù),是由各級父控件往子控件/子view進行一層層傳遞的。我們可以在xml中定義Layout的寬和高的具體的值或?qū)捀叩奶畛浞绞?#xff1a;matchparent/wrapcontent,也可以在代碼中使用LayoutParams設(shè)置,而實際上這里設(shè)置的值就會對應(yīng)到上面的measure和onMeasure方法中的兩個參數(shù)的模式,對應(yīng)關(guān)系如下:

具體的值(如width=200dp)和matchparent/fillparent,對應(yīng)模式中的MeasureSpec.EXACTLY

包裹內(nèi)容(width=wrapcontent)則對應(yīng)模式中的MeasureSpec.AT_MOST。

一個view的寬高尺寸,只有在測量之后才能得到,也就是measure方法被調(diào)用之后。具體實現(xiàn)代碼如下:

第一個紅框框就是我們上面說的模式和大小組合才能知道這個view的大小。第二個紅框框是進行計算并保存計算結(jié)果。這里我們想要繪制的是一個正方形,所以取了寬和高中最小值作為width。中間的if和else if是判斷模式的,因為模式可能在設(shè)置的時候出現(xiàn)問題,所以這里進行簡單處理。

.????現(xiàn)在我們繪制棋盤,那我們需要知道棋盤的高度和寬度,以及每行格子數(shù)。那這些數(shù)據(jù)在哪里進行初始化呢?我們選擇在onSizeChanged()中進行設(shè)置。使用這個是因為當(dāng)布局發(fā)生變化時,可以回調(diào)onMeasure重新布局。具體代碼如下:

至于繪制操作我們肯定是放在onDraw()里面,我們使用了一個drawBoard()方法。昨天說過,繪制的時候是需要paint的,所以定義一下paint,此外還要在init中進行初始化(大小,風(fēng)格,抗鋸齒等等)。具體的代碼我們昨天已經(jīng)看過,這里就不再看了。這里就是要注意一下棋盤畫的時候應(yīng)該注意線的初始坐標和結(jié)束坐標,還有縱坐標的變化。

????繪制完棋盤我們就應(yīng)該繪制棋子了,但是棋子的位置我們并不確定,因為這是和用戶交互的,所以我們肯定要在onTouchEvent()函數(shù)中寫交互。但是在這之前,我們要在代碼中引入這兩個棋子的圖片(注意,這里是代碼中引入,和昨天的是不一樣的)。

????·首先得聲明一下兩個棋子:

mWhitePiece是我們棋子的名字。

然后進行棋子的初始化(在init中):

至于書寫格式,大家模仿就可以。

????接下來就是棋子的繪制了。這里要注意的:第一點,要注意棋子不能比我們繪制的格子還要大,大小得適宜;第二點,在繪制棋子的時候要考慮到兩個棋子之間的空隙,不能交叉,也不要緊貼,美觀一些。這就要求我們在繪制的時候一定多注意坐標的設(shè)置。

????為了滿足上面兩點,我們定義一個比例變量,讓棋子等于格子寬的3/4:

那么這里我們就又涉及到棋子尺寸大小的改變了。上面提到過了,布局改變放在onSizeChanged()中:

棋子的寬度我們是行高乘以3/4比例。紅框下面兩行是對白棋和黑棋的繪制,我們使用的是BitMap里的createScaledBitmap方法。

下面講棋子與用戶的交互:

先介紹一下運動事件:

再詳細介紹一下onTouchEvent()方法:

  • public boolean onTouchEvent (MotionEvent event)?

? ?? ??參數(shù)event:參數(shù)event為手機屏幕觸摸事件封裝類的對象,其中封裝了該事件的所有信息,例如觸摸的位置、觸摸的類型以及觸摸的時間等。該對象會在用戶觸摸手機屏幕時被創(chuàng)建。
? ?? ??返回值:該方法的返回值機理與鍵盤響應(yīng)事件的相同,同樣是當(dāng)已經(jīng)完整地處理了該事件且不希望其他回調(diào)方法再次處理時返回true,否則返回false。
? ?? ? 該方法并不像之前介紹過的方法只處理一種事件,一般情況下以下三種情況的事件全部由onTouchEvent方法處理,只是三種情況中的動作值不同。
? ?? ??屏幕被按下:當(dāng)屏幕被按下時,會自動調(diào)用該方法來處理事件,此時MotionEvent.getAction()的值為MotionEvent.ACTION_DOWN,如果在應(yīng)用程序中需要處理屏幕被按下的事件,只需重新該回調(diào)方法,然后在方法中進行動作的判斷即可。
? ?? ??屏幕被抬起:當(dāng)觸控筆離開屏幕時觸發(fā)的事件,該事件同樣需要onTouchEvent方法來捕捉,然后在方法中進行動作判斷。當(dāng)MotionEvent.getAction()的值為MotionEvent.ACTION_UP時,表示是屏幕被抬起的事件。
? ?? ??在屏幕中拖動:該方法還負責(zé)處理觸控筆在屏幕上滑動的事件,同樣是調(diào)用MotionEvent.getAction()方法來判斷動作值是否為MotionEvent.ACTION_MOVE再進行處理。

看上面的介紹我們知道了,在寫五子棋的時候,如果Action是Down形式的,那么手滑點歪的情況不容易解決,當(dāng)然,用戶更不可能在滑動的過程產(chǎn)生落子的行為(噗,,,突然污了,咳咳咳),所以我們使用的是UP形式。要注意,當(dāng)判斷可以處理該行為的時候,返回值應(yīng)該設(shè)為true,上面對于返回值的介紹很清楚了。

????那么這個事件怎么處理呢?用戶落子(我不行了,這個我可以笑好久),我們索要的有效信息是點擊的那個坐標。所以我們在設(shè)一個全局變量來記錄棋子坐標:

這種定義形式需要學(xué)習(xí)。

此外,我們還需要有一個變量來告訴我們到底是黑子在下還是白棋在下:

用布爾形式即可。那這句話的含義就是黑子先手或者是黑子正在下。

接下來我們就該接受用戶點擊的坐標值并進行是否落子的判斷了。

  • 第一點我們比較容易想到,就是簡單粗暴的直接獲取橫縱坐標;

  • 第二點是說寫一個方法,把這個點封裝起來,放到Point類的p中,而且大家看這個方法是獲得有效的坐標值,那有效的意思是什么呢?我們知道,有的人手粗,有的人手細,有的人就是喜歡用腳或者胳膊肘下棋,還有的人眼睛就是不大好使,那問題就來了,我怎么著都點不到那個行與列的交叉處,接近的位置難道就不認了?為了滿足用戶的這個需求,我們寫一個方法,獲得有效的坐標值:

    代碼很簡單,就是取整來減少誤差。只要不是手太粗、胳膊太粗、腳太粗、眼睛太不好使都不會有什么問題的。

  • 第四點我們也比較容易想到,得到了坐標值,就把棋子添加進去啊,這里就是判斷一下是黑子下還是白子下。與之有關(guān)的是,當(dāng)我們下完一個子之后,要把棋子的狀態(tài)恢復(fù)到原來的狀態(tài)去,也就是第五點的第二行的含義。

  • 在最后不要忘記了一定要加上第五點的invalidate(),用這個函數(shù)進行重繪;

  • 那么第三點是什么呢?實際上就是考慮是否全面的問題:用戶不可以在同一個點處重復(fù)落子。

    ?

那這里與用戶的交互就完成了,下來我們進行棋子的繪制:

這里代碼看起來多,但是重復(fù)性很大,黑子白子邏輯一樣的,繪制棋子這一塊比較麻煩的是坐標值得確定,要考慮間隙,考慮與格子的關(guān)系,大家可以自行畫圖對照代碼進行理解,這里我就不贅述了,不好說啊。。。

給大家看一點效果:(背景圖我很喜歡,但是當(dāng)五子棋的背景圖真是丑啊,棋子也沒有進行摳圖,湊活一下吧先)

視頻地址:https://v.qq.com/x/page/u132224hol2.html

006


原創(chuàng)不易,請多多支持與交流~

總結(jié)

以上是生活随笔為你收集整理的安卓第二趴的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。