欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android Studio做超好玩的拼圖游戲 附送詳細(xì)注釋源碼

 更新時間:2021年08月19日 17:09:55   作者:振華OPPO  
這篇文章主要介紹了用Android Studio做的一個超好玩的拼圖游戲,你是0基礎(chǔ)Android小白也能包你學(xué)會,另外附送超詳細(xì)注釋的源碼,建議收藏!

一、項(xiàng)目概述

之前有不少粉絲私信我說,能不能用Android原生的語言開發(fā)一款在手機(jī)上運(yùn)行的游戲呢?

說實(shí)話,使用java語言直接開發(fā)游戲這個需求有點(diǎn)難,因?yàn)橐恍┍容^復(fù)雜的游戲都是通過cocos2D或者Unity3D等游戲引擎開發(fā)出來的,然后再移植到Android手機(jī)當(dāng)中,使用完整的游戲引擎開發(fā)的過程比較簡單,而且界面比較流暢,觀感和體驗(yàn)度都很好。

所以直接使用java開發(fā)的游戲并不多。當(dāng)然,雖說不多但也有。簡單些的比如:2048、拼圖游戲、貪吃蛇、推箱子等,復(fù)雜點(diǎn)的比如:斗地主,這些都可以用java語言開發(fā)。因?yàn)檫@些游戲刷新界面次數(shù)比較少,是可以用java開發(fā)出來的。

所以在這篇博客里面,我們就來開發(fā)一款簡單的拼圖游戲,這款拼圖游戲就和我們小時候玩的游戲是一樣的,這里面的涉及到的算法不多,可以很容易學(xué)會,是作為入門Android的一個非常好的實(shí)例。

二、開發(fā)環(huán)境

在這里插入圖片描述

三、需求分析

我們先來看下最終要實(shí)現(xiàn)的效果:

可以看到游戲開始后,開始計(jì)時,然后下面是被打亂的九宮格圖片,最后一塊是空白的,因?yàn)橐舫隹臻g移動,中間是重新開始按鈕,點(diǎn)擊就會重新計(jì)時而且拼圖碎片重新打亂,最底下是原圖,方便大家對照著進(jìn)行拼湊。當(dāng)你拼圖完成后,上面的第九塊拼圖會立刻顯示出來補(bǔ)齊整張圖片,然后彈出對話框,告訴你拼圖成功,用時為多少多少秒,點(diǎn)擊確認(rèn)即可。
在這里插入圖片描述

所以我們分為六個步驟來實(shí)現(xiàn):

  1. 拼圖游戲布局繪制
  2. 拼圖游戲時間計(jì)時
  3. 拼圖游戲打亂顯示
  4. 拼圖游戲碎片位置切換
  5. 拼圖游戲成功的條件
  6. 拼圖游戲重新開始

我們來看下需要準(zhǔn)備的圖片素材:

這里先是一張小熊的樣圖,命名就是yangtu。然后就是將它按九宮格裁剪成的九張圖片,命名格式我來解釋下:我們看第八張我選中的圖片,它的名字為img_xiaoxiong_02x01。這里解釋下為什么是02x01,這就可以看做一個三行三列的二維數(shù)組,排列方式就和下面一樣。數(shù)組行和列下標(biāo)都是從0開始,所以第八張就是在第2行第1列,所以就是02x01,其他的也以此類推。
大家可以自己選圖片進(jìn)行裁剪命名,當(dāng)然也可以直接下載我的源碼,里面就有這些圖片。

在這里插入圖片描述

下面我們就一起來實(shí)現(xiàn)這個拼圖游戲吧~

四、實(shí)現(xiàn)過程

1、拼圖游戲布局繪制

我們首先來分析下游戲的layout布局

再來看下最終實(shí)現(xiàn)的效果圖,先分析一下怎么繪制布局,實(shí)現(xiàn)一個項(xiàng)目的第一步是將布局按照自己期望的樣子完成。

因?yàn)檫@是一個上下結(jié)構(gòu),所以我們用一個線性布局(LinearLayout)來實(shí)現(xiàn)最合適,方向(orientation)設(shè)置為豎直方向(vertical)??梢钥吹竭@個拼圖分為三行三列,所以我們直接將每一行分為一個小的LinearLayout,一共三個,然后在每個小的LinearLayout里面水平放三個圖片按鈕,這樣就實(shí)現(xiàn)了,思路有了,我們來繪制吧。

在這里插入圖片描述

我們來繪制游戲的layout布局

從上至下的第一個布局是顯示時間的TextView,我們將它的id設(shè)置為pt_tv_time,layout_width和layout_height都設(shè)置為wrap_content,就是適應(yīng)內(nèi)容大小,然后text文本內(nèi)容設(shè)為“時間:0”,這個是方便測試寫上文本的,因?yàn)檫厡懘a可以邊看旁邊的效果變化。

然后layout_gravity設(shè)置為"center",就是設(shè)置自己在父容器(頂層的LinearLayout)中居中,這里補(bǔ)充下知識點(diǎn):

  • gravity是設(shè)置自身內(nèi)部元素的對齊方式。比如一個TextView,則是設(shè)置內(nèi)部文字的對齊方式。如果是ViewGroup組件如LinearLayout的話,則為設(shè)置它內(nèi)部view組件的對齊方式。
  • layout_gravity是設(shè)置自身相當(dāng)于父容器的對齊方式。比如,一個TextView設(shè)置layout_gravity屬性,則表示這TextView相對于父容器的對齊方式。

再來改變下字體大小,設(shè)置textSize為20sp,sp是像素,補(bǔ)充下單位的知識點(diǎn):

  • dp: device independent pixels(設(shè)備獨(dú)立像素),不同設(shè)備有不同的顯示效果,和設(shè)備硬件有關(guān)。
  • px: pixels(像素).,不同設(shè)備顯示效果相同,這個用的比較多。
  • pt: point,是一個標(biāo)準(zhǔn)的長度單位,1pt=1/72英寸,用于印刷業(yè),非常簡單易用。
  • sp: scaled pixels(放大像素),主要用于字體顯示best for textsize。

最后設(shè)置字體顏色為#FF0000,即紅色。一般是通過colors.xml資源來引用,這里因?yàn)榧t色比較好表示就直接設(shè)置了。

TextView代碼如下:

<TextView
        android:id="@+id/pt_tv_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="時間 : 0"
        android:layout_gravity="center"
        android:textSize="20sp"
        android:textColor="#FF0000"/>

設(shè)置完成后,我們來看下效果圖:

在這里插入圖片描述

接著我們來繪制九宮格拼圖,先設(shè)置第一行這三個小圖片的外布局,依然是LinearLayout,設(shè)置它的id="@+id/pt_line1",就表示第一行。

orientation選擇的是水平方向,因?yàn)槊恳恍惺撬椒胖玫?,layout_gravity設(shè)置為"center",表示居中,代碼如下。

<LinearLayout
        android:id="@+id/pt_line1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_gravity="center">
        
</LinearLayout>

設(shè)置第一張圖片,選擇的控件是ImageButton,顧名思義:圖片按鈕,正常按鈕就規(guī)規(guī)矩矩的,而圖片按鈕就很好看,一張圖片也可以進(jìn)行點(diǎn)擊,這里設(shè)置它的id="@+id/pt_ib_00x00",方便在MainActivity里面調(diào)用。

00x00不用我多說了吧,上面解釋過了,將九宮格看成3X3的二維數(shù)組,那么行列下標(biāo)就是0行0列,這里每行數(shù)和列數(shù)都用2位數(shù)字表示而已。

設(shè)置src="@mipmap/img_xiaoxiong_00x00",就是將我們剛剛準(zhǔn)備的圖片資源復(fù)制到這個mipmap文件夾中進(jìn)行引用,每個id編號和圖片的名稱是對應(yīng)的。

在這里插入圖片描述

再設(shè)置個onClick方法,方法名為"onClick",我們后面會在MainActivity里面進(jìn)行編寫點(diǎn)擊事件。第一張圖片的代碼如下:

<ImageButton
            android:id="@+id/pt_ib_00x00"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/img_xiaoxiong_00x00"
            android:padding="0dp"
            android:onClick="onClick"/>

依次類推,第二張和第三張圖片,我只要改下id和src就可以了,所以直接放上第一個小LinearLayout的代碼:

<LinearLayout
        android:id="@+id/pt_line1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_gravity="center">
        <ImageButton
            android:id="@+id/pt_ib_00x00"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/img_xiaoxiong_00x00"
            android:padding="0dp"
            android:onClick="onClick"/>
        <ImageButton
            android:id="@+id/pt_ib_00x01"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/img_xiaoxiong_00x01"
            android:padding="0dp"
            android:onClick="onClick"/>
        <ImageButton
            android:id="@+id/pt_ib_00x02"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/img_xiaoxiong_00x02"
            android:padding="0dp"
            android:onClick="onClick"/>
    </LinearLayout>

來看下顯示效果:

在這里插入圖片描述

那第二行和第三行是不是也一樣照葫蘆畫瓢,沒錯,直接復(fù)制第一行的代碼,然后修改id和src就行。這里直接給出三個LinearLayout的代碼:

<LinearLayout
        android:id="@+id/pt_line1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_gravity="center">
        <ImageButton
            android:id="@+id/pt_ib_00x00"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/img_xiaoxiong_00x00"
            android:padding="0dp"
            android:onClick="onClick"/>
        <ImageButton
            android:id="@+id/pt_ib_00x01"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/img_xiaoxiong_00x01"
            android:padding="0dp"
            android:onClick="onClick"/>
        <ImageButton
            android:id="@+id/pt_ib_00x02"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/img_xiaoxiong_00x02"
            android:padding="0dp"
            android:onClick="onClick"/>
    </LinearLayout>

    <LinearLayout
        android:id="@+id/pt_line2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_gravity="center">
        <ImageButton
            android:id="@+id/pt_ib_01x00"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/img_xiaoxiong_01x00"
            android:padding="0dp"
            android:onClick="onClick"/>
        <ImageButton
            android:id="@+id/pt_ib_01x01"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/img_xiaoxiong_01x01"
            android:padding="0dp"
            android:onClick="onClick"/>
        <ImageButton
            android:id="@+id/pt_ib_01x02"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/img_xiaoxiong_01x02"
            android:padding="0dp"
            android:onClick="onClick"/>
    </LinearLayout>

    <LinearLayout
        android:id="@+id/pt_line3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_gravity="center">
        <ImageButton
            android:id="@+id/pt_ib_02x00"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/img_xiaoxiong_02x00"
            android:padding="0dp"
            android:onClick="onClick"/>
        <ImageButton
            android:id="@+id/pt_ib_02x01"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/img_xiaoxiong_02x01"
            android:padding="0dp"
            android:onClick="onClick"/>
        <ImageButton
            android:id="@+id/pt_ib_02x02"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/img_xiaoxiong_02x02"
            android:padding="0dp"
            android:onClick="onClick"
            android:visibility="invisible"/>
    </LinearLayout>

有一點(diǎn)需要注意的,不知道有沒有同學(xué)發(fā)現(xiàn)——第三行的第三張圖片,也就是右下角的那張圖片,它有個屬性,其他的圖片都沒有:visibility=“invisible”,這是干什么的呢?

這個其實(shí)就是設(shè)置控件是否可見,默認(rèn)情況下控件都是可見的(visible),只有設(shè)置visibility="invisible"后,這個控件才不顯示出來,我們來看下整體效果:

在這里插入圖片描述

OK,九宮格完成后,下面是一個重新開始的Button。

這個比較簡單了,主要設(shè)置了onClick=“restart”,這個后面會在MainActivity里面編寫重新開始游戲的邏輯,還設(shè)置了android:layout_marginTop=“20dp”,這是設(shè)置此控件與上面控件邊距相隔20dp,為了和九宮格保持一定間距,代碼如下:

<Button
        android:id="@+id/pt_btn_restart"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="restart"
        android:layout_gravity="center"
        android:text="重新開始"
        android:layout_marginTop="20dp"/>

顯示效果:

在這里插入圖片描述

最后就是我們的樣圖了,有了我們上面的經(jīng)驗(yàn),這個應(yīng)該很容易就畫出來了,放置圖片的控件我們一般使用ImageView,然后設(shè)置src="@mipmap/yangtu",就顯示了我們的樣圖,最后為了保持距離美,設(shè)置layout_marginTop=“20dp”,代碼如下:

    <ImageView
        android:id="@+id/pt_iv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:src="@mipmap/yangtu"
        android:layout_marginTop="20dp"/>

好了,我們來看下效果圖:

在這里插入圖片描述

至此,我們的布局就繪制完成了!

我們來編寫下MainActivity的基本框架

可以先來看下什么都沒有的MainActivity。里面只有onClick()和restart()兩個新的方法,這是在上面布局中設(shè)置的方法,onClick是圖片按鈕的點(diǎn)擊事件,restart是重新開始按鈕的點(diǎn)擊事件,這兩個方法的具體實(shí)現(xiàn)邏輯會在下面講到。

public class MainActivity extends AppCompatActivity {
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		   super.onCreate(savedInstanceState);
		// 設(shè)置要顯示的視圖
		   setContentView(R.layout.activity_main);
		}
	// 圖片按鈕的點(diǎn)擊事件	    
	public void onClick(View view) {
	
	}
	/* 重新開始按鈕的點(diǎn)擊事件*/
    public void restart(View view) {
    
  	}
}	  	

這里我們要做的是把所有在布局中用到的控件定義好,然后初始化這些控件

先來定義九個圖片按鈕,命名方法也是00,01這樣的橫縱坐標(biāo),一個重啟按鈕和一個顯示時間的文本框

//  定義九個圖片按鈕,命名方法也是00,01這樣的橫縱坐標(biāo)
    ImageButton ib00,ib01,ib02,ib10,ib11,ib12,ib20,ib21,ib22;
//   一個重啟按鈕
    Button restartBtn;
//  一個顯示時間的文本框
    TextView timeTv;

然后我們在onCreate中定義一個initView()方法,這個方法是用來初始化控件的

//      初始化layout控件的方法
        initView();

然后創(chuàng)建該方法,在該方法里面初始化定義的控件,通過findViewById()進(jìn)行綁定控件,將聲明的變量和layout中對應(yīng)的控件進(jìn)行綁定,實(shí)現(xiàn)引用的效果,代碼如下:

/* 初始化控件:綁定9個圖片按鈕,1個顯示時間的文本框,1個重啟按鈕*/
    private void initView() {
        ib00 = findViewById(R.id.pt_ib_00x00);
        ib01 = findViewById(R.id.pt_ib_00x01);
        ib02 = findViewById(R.id.pt_ib_00x02);
        ib10 = findViewById(R.id.pt_ib_01x00);
        ib11 = findViewById(R.id.pt_ib_01x01);
        ib12 = findViewById(R.id.pt_ib_01x02);
        ib20 = findViewById(R.id.pt_ib_02x00);
        ib21 = findViewById(R.id.pt_ib_02x01);
        ib22 = findViewById(R.id.pt_ib_02x02);
        timeTv = findViewById(R.id.pt_tv_time);
        restartBtn = findViewById(R.id.pt_btn_restart);
    }

初始化的完整代碼,可以作為模板:

public class MainActivity extends AppCompatActivity {
//  定義九個圖片按鈕,命名方法也是00,01這樣的橫縱坐標(biāo)
    ImageButton ib00,ib01,ib02,ib10,ib11,ib12,ib20,ib21,ib22;
//   一個重啟按鈕
    Button restartBtn;
//  一個顯示時間的文本框
    TextView timeTv;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		   super.onCreate(savedInstanceState);
		// 設(shè)置要顯示的視圖
		   setContentView(R.layout.activity_main);
		   initView();
		}
	private void initView() {
        ib00 = findViewById(R.id.pt_ib_00x00);
        ib01 = findViewById(R.id.pt_ib_00x01);
        ib02 = findViewById(R.id.pt_ib_00x02);
        ib10 = findViewById(R.id.pt_ib_01x00);
        ib11 = findViewById(R.id.pt_ib_01x01);
        ib12 = findViewById(R.id.pt_ib_01x02);
        ib20 = findViewById(R.id.pt_ib_02x00);
        ib21 = findViewById(R.id.pt_ib_02x01);
        ib22 = findViewById(R.id.pt_ib_02x02);
        timeTv = findViewById(R.id.pt_tv_time);
        restartBtn = findViewById(R.id.pt_btn_restart);
    }
	// 圖片按鈕的點(diǎn)擊事件	    
	public void onClick(View view) {
	
	}
	/* 重新開始按鈕的點(diǎn)擊事件*/
    public void restart(View view) {
    
  	}
}	  	

2、拼圖游戲時間計(jì)時

完成基本工作后,我們思考下——如何實(shí)現(xiàn)時間的計(jì)時操作,這就相當(dāng)于計(jì)時器的功能。這里我們可以用Handler消息機(jī)制來實(shí)現(xiàn),補(bǔ)充下知識點(diǎn):

  • Handler:作用就是發(fā)送與處理信息
  • Message:Handler接收與處理的消息對象

當(dāng)我們的子線程想修改Activity中的UI組件時,我們可以新建一個Handler對象,通過這個對象向主線程發(fā)送信息;而我們發(fā)送的信息會先到主線程的MessageQueue進(jìn)行等待,由Looper按先入先出順序取出,再根據(jù)message對象的what屬性分發(fā)給對應(yīng)的Handler進(jìn)行處理!

簡單來說:Handler就是用來發(fā)送消息和處理消息的一種機(jī)制,上面這段話可能聽起來有些懵,不過沒關(guān)系,其實(shí)沒有這么深奧,下面會讓大家明白怎么使用它來實(shí)現(xiàn)計(jì)時的。

先定義個時間變量,初值為0,因?yàn)閺?開始計(jì)時

//    定義計(jì)數(shù)時間的變量
    int time = 0;

然后定義發(fā)送和處理消息的對象handler,我們來重寫handleMessage方法,在方法里面我們進(jìn)行了if判斷,如果這條消息的what值為1,那么時間time就+1,然后timeTv顯示時間為time秒,然后繼續(xù)向自己發(fā)送消息。

handler.sendEmptyMessageDelayed(1,1000)這句話的意思就是:延時1000毫秒后發(fā)送參數(shù)what為1的空信息,這樣它自己就能循環(huán)接收自己發(fā)的消息,實(shí)現(xiàn)計(jì)時的功能了,就這么簡單。

當(dāng)然最開始要發(fā)送它一條消息,讓它這個方法運(yùn)轉(zhuǎn)起來,我們在onCreate這個方法里面加上了一條
handler.sendEmptyMessageDelayed(1,1000); 這樣在游戲一開始過了1s,handler就發(fā)送了一條what為1的空消息。然后它自己又立馬接收到了,進(jìn)行時間加1,又自己發(fā)送給自己消息,實(shí)現(xiàn)計(jì)時!

這是定義的handler的代碼:

//  定義發(fā)送和處理消息的對象handler
    Handler handler = new Handler(){
        @Override
//      重寫handleMessage方法,根據(jù)msg中what的值判斷是否執(zhí)行后續(xù)操作
        public void handleMessage(Message msg) {
            if (msg.what==1) {
                time++;
                timeTv.setText("時間 : "+time+" 秒");
//               指定延時1000毫秒后發(fā)送參數(shù)what為1的空信息
                handler.sendEmptyMessageDelayed(1,1000);
            }

        }
    };

這是在onCreate方法里面定義的一條消息

handler.sendEmptyMessageDelayed(1,1000);

我們來看下運(yùn)行效果:

在這里插入圖片描述

除此之外,我們還需要在重新開始游戲后進(jìn)行重新計(jì)時,這里又要怎么實(shí)現(xiàn)呢?

這里我們只需要在restart方法里面先停止handler的消息發(fā)送,保證時間不會再繼續(xù)+1了,然后將時間重新歸0,顯示當(dāng)前時間,最后每隔1s發(fā)送參數(shù)what為1的消息msg,這樣就實(shí)現(xiàn)了重新開始計(jì)時,代碼如下:

/* 重新開始按鈕的點(diǎn)擊事件*/
    public void restart(View view) {
//       停止handler的消息發(fā)送
        handler.removeMessages(1);
//       將時間重新歸0,并且重新開始計(jì)時
        time = 0;
        timeTv.setText("時間 : "+time+" 秒");
//      每隔1s發(fā)送參數(shù)what為1的消息msg
        handler.sendEmptyMessageDelayed(1,1000);
    }

點(diǎn)擊重新開始后的實(shí)現(xiàn)效果:

在這里插入圖片描述

至此,我們的計(jì)時功能就實(shí)現(xiàn)了!

3、拼圖游戲打亂顯示

首先定義一個image數(shù)組,里面存放每張碎片(九宮格圖片)的id,int型數(shù)組是可以存放圖片的id的,但是不能存放圖片,注意這個區(qū)別。

//    將每張碎片的id存放到數(shù)組中,便于進(jìn)行統(tǒng)一的管理,int型數(shù)組存放的肯定是int型變量
    private int[]image = {R.mipmap.img_xiaoxiong_00x00,R.mipmap.img_xiaoxiong_00x01,R.mipmap.img_xiaoxiong_00x02,
        R.mipmap.img_xiaoxiong_01x00,R.mipmap.img_xiaoxiong_01x01,R.mipmap.img_xiaoxiong_01x02,
       R.mipmap.img_xiaoxiong_02x00,R.mipmap.img_xiaoxiong_02x01,R.mipmap.img_xiaoxiong_02x02};

再聲明一個imageIndex數(shù)組,它來存放上面圖片數(shù)組的下標(biāo),一共九張圖片,所以下標(biāo)為0-8,它存儲的也就是0-8。我們?yōu)榱俗屔厦婢艔垐D片被打亂,所以,這里的下標(biāo)等下會被打亂。

//    聲明上面圖片數(shù)組下標(biāo)的數(shù)組,隨機(jī)排列這個數(shù)組,九張圖片,下標(biāo)為0-8
    private int[]imageIndex = new int[image.length];

下面我們寫一個函數(shù)disruptRandom( ),來實(shí)現(xiàn)進(jìn)入游戲拼圖就打亂顯示的效果

先給下標(biāo)數(shù)組每個元素賦值,下標(biāo)是i,值就為i,就是imageIndex[i] = i。

//      給下標(biāo)數(shù)組每個元素賦值,下標(biāo)是i,值就為i
        for (int i = 0; i < imageIndex.length; i++) {
            imageIndex[i] = i;
        }

然后進(jìn)行20次for循環(huán),隨機(jī)選擇兩個角標(biāo)對應(yīng)的值進(jìn)行交換。先定義兩個角標(biāo)rand1和rand2,
rand1 = (int)(Math.random()*(imageIndex.length-1));這里我來重點(diǎn)解釋一下:
Math.random()產(chǎn)生的隨機(jī)數(shù)為0~1之間的小數(shù) 此處說的0~1是包含左不包含右,即包含0不包含1!

ps:我在這里卡了2h至少,因?yàn)檫@個小細(xì)節(jié)點(diǎn)沒注意到,所以一定不能想當(dāng)然,要查資料以求準(zhǔn)確。

Math.random()的值域?yàn)閇0,1),然后imageIndex.length-1就是8其實(shí),*8那就是[0,8),再int取整最終值域?yàn)閧0,1,2,3,4,5,6,7},因?yàn)閕nt取整只會取整數(shù)位,不會四舍五入!

再用do-while循環(huán)實(shí)現(xiàn)了rand2的生成,之所以在do-while里面生成rand2,是為了判斷二次生成的角標(biāo)和第一次是否相同,不同則break立刻跳出循環(huán),執(zhí)行swap交換;若第二次生成的與第一次相同,則重新進(jìn)入do-while循環(huán)生成rand2,這部分代碼如下:

//        規(guī)定20次,隨機(jī)選擇兩個角標(biāo)對應(yīng)的值進(jìn)行交換
        int rand1,rand2;
        for (int j = 0; j < 20; j++) {
//            隨機(jī)生成第一個角標(biāo)
//            Math.random()產(chǎn)生的隨機(jī)數(shù)為0~1之間的小數(shù) 此處說的0~1是包含左不包含右,即包含0不包含1
//            Math.random()的值域?yàn)閇0,1),然后*8就是[0,8),再int取整最終值域?yàn)閧0,1,2,3,4,5,,6,7}
            rand1 = (int)(Math.random()*(imageIndex.length-1));
//            第二次隨機(jī)生成的角標(biāo),不能和第一次隨機(jī)生成的角標(biāo)相同,如果相同,就不方便交換了
            do {
                rand2 = (int)(Math.random()*(imageIndex.length-1));
//             判斷第一次和第二次生成的角標(biāo)是否相同,不同則break立刻跳出循環(huán),執(zhí)行swap交換
                if (rand1!=rand2) {
                    break;
                }
//             若第二次生成的與第一次相同,則重新進(jìn)入do-while循環(huán)生成rand2
            }while (true);
            swap(rand1,rand2);
    }

這里的swap方法很簡單,就是交換兩個數(shù)的值,只不過這里參數(shù)是數(shù)組的下標(biāo):

//  交換數(shù)組指定角標(biāo)(0-7這八個自然數(shù))上的數(shù)據(jù)
    private void swap(int rand1, int rand2) {
        int temp = imageIndex[rand1];
        imageIndex[rand1] = imageIndex[rand2];
        imageIndex[rand2] = temp;
    }

這里有個整個游戲的一個核心點(diǎn):我們打亂的拼圖下標(biāo)是{0,1,2,3,4,5,6,7}這八個,第九張拼圖的下標(biāo)是不參與打亂的,有同學(xué)問為什么?是因?yàn)榈诰艔垐D片是不顯示出來的,而且不會參與到拼圖中,所以我們是將第九個圖片按鈕就設(shè)置成第九張圖片,然后invisible。

最后我們將每個圖片按鈕設(shè)置圖片,這時候 imageIndex[i]就是被打亂的下標(biāo),有可能是這樣的順序:{2,6,5,4,1,7,0,3,8},也有可能是這樣的順序{1,3,0,5,2,7,4,6,8}等等,不管怎么樣, imageIndex[8]一直是8,上面解釋過。代碼如下:

//       ib00是綁定的第一塊圖片按鈕,設(shè)置圖片資源,
//       imageIndex[i]就是被打亂的下標(biāo),然后image[x]就表示對應(yīng)下標(biāo)為x的圖片的id
        ib00.setImageResource(image[imageIndex[0]]);
        ib01.setImageResource(image[imageIndex[1]]);
        ib02.setImageResource(image[imageIndex[2]]);
        ib10.setImageResource(image[imageIndex[3]]);
        ib11.setImageResource(image[imageIndex[4]]);
        ib12.setImageResource(image[imageIndex[5]]);
        ib20.setImageResource(image[imageIndex[6]]);
        ib21.setImageResource(image[imageIndex[7]]);
        ib22.setImageResource(image[imageIndex[8]]);

綜上,disruptRandom()的整體邏輯代碼如下:

//  隨機(jī)打亂數(shù)組當(dāng)中元素,以不規(guī)則的形式進(jìn)行圖片顯示
    private void disruptRandom() {
//      給下標(biāo)數(shù)組每個元素賦值,下標(biāo)是i,值就為i
        for (int i = 0; i < imageIndex.length; i++) {
            imageIndex[i] = i;
        }
//        規(guī)定20次,隨機(jī)選擇兩個角標(biāo)對應(yīng)的值進(jìn)行交換
        int rand1,rand2;
        for (int j = 0; j < 20; j++) {
//            隨機(jī)生成第一個角標(biāo)
//            Math.random()產(chǎn)生的隨機(jī)數(shù)為0~1之間的小數(shù) 此處說的0~1是包含左不包含右,即包含0不包含1
//            Math.random()的值域?yàn)閇0,1),然后*8就是[0,8),再int取整最終值域?yàn)閧0,1,2,3,4,5,,6,7}
            rand1 = (int)(Math.random()*(imageIndex.length-1));
//            第二次隨機(jī)生成的角標(biāo),不能和第一次隨機(jī)生成的角標(biāo)相同,如果相同,就不方便交換了
            do {
                rand2 = (int)(Math.random()*(imageIndex.length-1));
//             判斷第一次和第二次生成的角標(biāo)是否相同,不同則break立刻跳出循環(huán),執(zhí)行swap交換
                if (rand1!=rand2) {
                    break;
                }
//             若第二次生成的與第一次相同,則重新進(jìn)入do-while循環(huán)生成rand2
            }while (true);
//            交換兩個角標(biāo)上對應(yīng)的值
            swap(rand1,rand2);
        }
//        隨機(jī)排列到指定的控件上
//        ib00是綁定的第一塊圖片按鈕,設(shè)置圖片資源,imageIndex[i]就是被打亂的圖片數(shù)組下標(biāo),然后image[x]就表示對應(yīng)下標(biāo)為x的圖片的id
        ib00.setImageResource(image[imageIndex[0]]);
        ib01.setImageResource(image[imageIndex[1]]);
        ib02.setImageResource(image[imageIndex[2]]);
        ib10.setImageResource(image[imageIndex[3]]);
        ib11.setImageResource(image[imageIndex[4]]);
        ib12.setImageResource(image[imageIndex[5]]);
        ib20.setImageResource(image[imageIndex[6]]);
        ib21.setImageResource(image[imageIndex[7]]);
        ib22.setImageResource(image[imageIndex[8]]);

    }

實(shí)現(xiàn)效果:

在這里插入圖片描述

4、拼圖游戲碎片位置切換

我們完成亂序后,這時候拼圖碎片還不能移動,所以我們要設(shè)置點(diǎn)擊事件,來移動拼圖。

拼圖移動的規(guī)則也要注意一下:只有和空白區(qū)域在同一行或者同一列相鄰的拼圖才能移動,只要知道了這個邏輯,實(shí)現(xiàn)起來就不難了。

我們來編寫九個圖片按鈕的onClick()方法

這里因?yàn)榫艂€id不同的imagebutton點(diǎn)擊事件的邏輯相同,所以我們使用switch 語句來編寫,根據(jù)它們的id來執(zhí)行移動,按照從左到右、從上到下的順序進(jìn)行了case設(shè)置。移動我們定義了move()函數(shù),將它單獨(dú)封裝成了一個方法,下面就會講到。點(diǎn)擊事件的代碼如下:

 public void onClick(View view) {
        int id = view.getId();
//        九個按鈕執(zhí)行的點(diǎn)擊事件的邏輯應(yīng)該是相同的,如果有空格在周圍,可以改變圖片顯示的位置,否則點(diǎn)擊事件不響應(yīng)
        switch (id) {
            case R.id.pt_ib_00x00:
                move(R.id.pt_ib_00x00,0);
                break;
            case R.id.pt_ib_00x01:
                move(R.id.pt_ib_00x01,1);
                break;
            case R.id.pt_ib_00x02:
                move(R.id.pt_ib_00x02,2);
                break;
            case R.id.pt_ib_01x00:
                move(R.id.pt_ib_01x00,3);
                break;
            case R.id.pt_ib_01x01:
                move(R.id.pt_ib_01x01,4);
                break;
            case R.id.pt_ib_01x02:
                move(R.id.pt_ib_01x02,5);
                break;
            case R.id.pt_ib_02x00:
                move(R.id.pt_ib_02x00,6);
                break;
            case R.id.pt_ib_02x01:
                move(R.id.pt_ib_02x01,7);
                break;
            case R.id.pt_ib_02x02:
                move(R.id.pt_ib_02x02,8);
                break;
        }
    }

我們來編寫九個圖片按鈕的move()方法

先定義變量,imageX是每行的圖片個數(shù),imageY是每列的圖片個數(shù),imgCount是圖片的總數(shù)目,也就是9個。blankSwap是空白區(qū)域的位置,就是8,這里的位置我們還是按照從左到右、從上到下的順序排列的,第一張圖片的位置是0,對照九宮格應(yīng)該理解了吧。

blankImgid就是空白區(qū)域的按鈕id,我們這里直接固定了R.id.pt_ib_02x02,就是第九個圖片按鈕,它一直是空白區(qū)域!

//     每行的圖片個數(shù)
    private int imageX = 3;
//     每列的圖片個數(shù)
    private int imageY = 3;

//    圖片的總數(shù)目
    private int imgCount = imageX*imageY;
//    空白區(qū)域的位置
    private int blankSwap = imgCount-1;
//    初始化空白區(qū)域的按鈕id
    private int blankImgid = R.id.pt_ib_02x02;

定義完要用到的變量,我們來寫move方法,這里我每句都寫上了注釋,這里就不再贅述了。
強(qiáng)調(diào)幾點(diǎn):

1.可以移動的條件有兩個:

  1. 在同一行,列數(shù)相減,絕對值為1,可移動
  2. 在同一列,行數(shù)相減,絕對值為1,可以移動

2.兩個參數(shù): imagebuttonId是被選中的圖片的id,site是該圖片在9宮格的位置(0-8)

3.將移動后的圖片按鈕設(shè)為不可見的,即顯示為空白區(qū)域

4.移動之前是不可見的,移動之后將圖標(biāo)按鈕設(shè)置為可見

5.進(jìn)行移動后將改變角標(biāo)的過程記錄到存儲圖片位置的數(shù)組當(dāng)中

    /*表示移動指定位置的按鈕的函數(shù),將圖片和空白區(qū)域進(jìn)行交換*/
    //imagebuttonId是被選中的圖片的id,site是該圖片在9宮格的位置(0-8)
    private void move(int imagebuttonId, int site) {
//        判斷選中的圖片在第幾行,imageX為3,所以進(jìn)行取整運(yùn)算
        int sitex = site / imageX;
//        判斷選中的圖片在第幾列,imageY為3,所以進(jìn)行取模運(yùn)算
        int sitey = site % imageY;
//        獲取空白區(qū)域的坐標(biāo),blankx為行坐標(biāo),blanky為列坐標(biāo)
        int blankx = blankSwap / imageX;
        int blanky = blankSwap % imageY;
//        可以移動的條件有兩個
//        1.在同一行,列數(shù)相減,絕對值為1,可移動   2.在同一列,行數(shù)相減,絕對值為1,可以移動
        int x = Math.abs(sitex-blankx);
        int y = Math.abs(sitey-blanky);
        if ((x==0&&y==1)||(y==0&&x==1)){
//            通過id,查找到這個可以移動的按鈕
            ImageButton clickButton = findViewById(imagebuttonId);
//            將這個選中的圖片設(shè)為不可見的,即顯示為空白區(qū)域
            clickButton.setVisibility(View.INVISIBLE);
//            查找到空白區(qū)域的按鈕
            ImageButton blankButton = findViewById(blankImgid);
//            將空白區(qū)域的按鈕設(shè)置為圖片,image[imageIndex[site]就是剛剛選中的圖片,因?yàn)檫@在上面disruptRandom()設(shè)置過
            blankButton.setImageResource(image[imageIndex[site]]);
//            移動之前是不可見的,移動之后將控件設(shè)置為可見
            blankButton.setVisibility(View.VISIBLE);
//            將改變角標(biāo)的過程記錄到存儲圖片位置的數(shù)組當(dāng)中
            swap(site,blankSwap);
//            新的空白區(qū)域位置更新等于傳入的點(diǎn)擊按鈕的位置
            blankSwap = site;
//            新的空白圖片id更新等于傳入的點(diǎn)擊按鈕的id
            blankImgid = imagebuttonId;
        }

    }

運(yùn)行效果:

在這里插入圖片描述
在這里插入圖片描述

5、拼圖游戲成功的條件

上面我們已經(jīng)實(shí)現(xiàn)了拼圖碎片進(jìn)行移動的效果,但是并沒有拼圖游戲成功的效果和提示,所以,我們要在剛剛的move方法的最后加上一個判斷的方法judgeGameOver();顧名思義:判斷游戲結(jié)束。

我們來實(shí)現(xiàn)一下判斷游戲結(jié)束的邏輯

在方法里面先定義一個loop標(biāo)志位,然后要遍歷下標(biāo)數(shù)組,判斷是否它的imageIndex[i]==i,就是說所有拼圖的下標(biāo)全部對應(yīng)正確的位置。比如:第1張圖片的下標(biāo)是0,imageIndex[0]的值也是0,顯示第一張圖片。所有圖片都滿足,也就是說此時拼圖成功。如果一個不滿足,則未成功,所有l(wèi)oop置為false,繼續(xù)判斷。

	boolean loop = true;   //定義標(biāo)志位loop
    for (int i = 0; i < imageIndex.length; i++) {
         if (imageIndex[i]!=i) {
                loop = false;
                break;
            }
      }

如果拼圖成功了,則handler.removeMessages(1)進(jìn)行停止計(jì)時,
而且設(shè)置ib00.setClickable(false)禁止玩家繼續(xù)移動按鈕,
還有就是第九塊空白區(qū)域顯示出圖片,即下標(biāo)為8的第九張拼圖。

  if (loop) {
//            拼圖成功了
//            停止計(jì)時
            handler.removeMessages(1);
//            拼圖成功后,禁止玩家繼續(xù)移動按鈕
            ib00.setClickable(false);
            ib01.setClickable(false);
            ib02.setClickable(false);
            ib10.setClickable(false);
            ib11.setClickable(false);
            ib12.setClickable(false);
            ib20.setClickable(false);
            ib21.setClickable(false);
            ib22.setClickable(false);
//            拼圖成功后,第九塊空白顯示出圖片,即下標(biāo)為8的第九張圖片
            ib22.setImageResource(image[8]);
            ib22.setVisibility(View.VISIBLE);

我們再來實(shí)現(xiàn)一下游戲結(jié)束時的對話框

對話框要用到AlertDialog.Builder對象,它的使用就是固定套路,我來補(bǔ)充知識點(diǎn):

  1. 第一步:創(chuàng)建AlertDialog.Builder對象
  2. 第二步:設(shè)置對話框的內(nèi)容:setMessage()方法來指定顯示的內(nèi)容
  3. 第三步:調(diào)用setPositive/Negative/NeutralButton()設(shè)置:確定,取消,中立按鈕
  4. 第四歩:調(diào)用create()方法創(chuàng)建這個對象
  5. 第五歩:調(diào)用show()方法來顯示我們的AlertDialog對話框

非常簡單,按照上面的流程,我們來設(shè)置下對話框:

//            彈出提示用戶成功的對話框,并且設(shè)置確實(shí)的按鈕

//           第一步:創(chuàng)建AlertDialog.Builder對象
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
//          調(diào)用setIcon()設(shè)置圖標(biāo),setTitle()或setCustomTitle()設(shè)置標(biāo)題
//           第二步:設(shè)置對話框的內(nèi)容:setMessage()方法來指定顯示的內(nèi)容
            builder.setMessage("恭喜,拼圖成功!您用的時間為"+time+"秒")
//           第三步:調(diào)用setPositive/Negative/NeutralButton()設(shè)置:確定,取消,中立按鈕
                    .setPositiveButton("確認(rèn)",null);
//           第四歩:調(diào)用create()方法創(chuàng)建這個對象
            AlertDialog dialog = builder.create();
//           第五歩:調(diào)用show()方法來顯示我們的AlertDialog對話框
            dialog.show();

實(shí)現(xiàn)效果:

在這里插入圖片描述

6、拼圖游戲重新開始

我們在上面實(shí)現(xiàn)了拼圖游戲成功的條件和提示了,現(xiàn)在到了最后一步——如何讓游戲重新開始?

我們來看下拼圖成功后,點(diǎn)擊重新開始,目前只能重新計(jì)時,拼圖并沒有打亂,而且第九塊還沒有隱藏,所以,接下來我們的思路很明確,在重新開始的restart方法中編寫打亂和隱藏圖片的邏輯。

在這里插入圖片描述

我們來實(shí)現(xiàn)重新開始游戲時的按鈕狀態(tài)還原

首先,這些按鈕已經(jīng)被設(shè)置成不可點(diǎn)擊了,所以我們先要將它們設(shè)置為可以點(diǎn)擊,就是設(shè)置ib00.setClickable(true),因?yàn)檫@部分代碼都是一樣的,所以我們將它單獨(dú)封裝成一個restore方法。

另外,還要還原被點(diǎn)擊的圖片按鈕變成初始化的模樣, ImageButton clickBtn = findViewById(blankImgid)其實(shí)就是綁定最后一次被隱藏的那塊拼圖,然后clickBtn.setVisibility(View.VISIBLE)將它顯示出來。ImageButton blankBtn = findViewById(R.id.pt_ib_02x02)就是綁定的第九塊拼圖,blankBtn.setVisibility(View.INVISIBLE)設(shè)置為不可見。最后blankImgid = R.id.pt_ib_02x02來初始化空白區(qū)域的按鈕id。

restore()的代碼如下:

//       狀態(tài)還原函數(shù),我們把它封裝起來
    private void restore() {
        //      拼圖游戲重新開始,允許移動碎片按鈕
        ib00.setClickable(true);
        ib01.setClickable(true);
        ib02.setClickable(true);
        ib10.setClickable(true);
        ib11.setClickable(true);
        ib12.setClickable(true);
        ib20.setClickable(true);
        ib21.setClickable(true);
        ib22.setClickable(true);
//        還原被點(diǎn)擊的圖片按鈕變成初始化的模樣
        ImageButton clickBtn = findViewById(blankImgid);
        clickBtn.setVisibility(View.VISIBLE);
//        默認(rèn)隱藏第九張圖片
        ImageButton blankBtn = findViewById(R.id.pt_ib_02x02);
        blankBtn.setVisibility(View.INVISIBLE);
//        初始化空白區(qū)域的按鈕id
        blankImgid = R.id.pt_ib_02x02;
        blankSwap = imgCount - 1;
    }

最后,我們在restart()中實(shí)現(xiàn)重新開始的邏輯

  1. 將狀態(tài)還原 將拼圖重新打亂
  2. 停止handler的消息發(fā)送
  3. 將時間重新歸0,并且重新開始計(jì)時
  4. 每隔1s發(fā)送參數(shù)what為1的消息msg
    /* 重新開始按鈕的點(diǎn)擊事件*/
    public void restart(View view) {
//        將狀態(tài)還原
         restore();
//       將拼圖重新打亂
        disruptRandom();
//       停止handler的消息發(fā)送
        handler.removeMessages(1);
//       將時間重新歸0,并且重新開始計(jì)時
        time = 0;
        timeTv.setText("時間 : "+time+" 秒");
//      每隔1s發(fā)送參數(shù)what為1的消息msg
        handler.sendEmptyMessageDelayed(1,1000);
    }

重新開始游戲后的效果:

在這里插入圖片描述

至此,拼圖游戲的所有功能已經(jīng)實(shí)現(xiàn)完畢,我先休息下,手腕已經(jīng)打酸了。如果你看到這里,我真的很欣慰,說明你是個很有耐心而且熱愛Android的學(xué)生,有熱情有耐心,再困難的東西都可以學(xué)會。

五、運(yùn)行效果

Android Studio實(shí)現(xiàn)拼圖游戲

六、項(xiàng)目總結(jié)

這次實(shí)現(xiàn)的拼圖游戲,說它簡單,其實(shí)它實(shí)現(xiàn)起來也并不是那么簡單,還是會有很多比較難的邏輯點(diǎn),需要思考才能寫出來;說它難,其實(shí)也不算難,比起來我前面發(fā)的那些項(xiàng)目【天氣預(yù)報】、【飲食搭配】來說邏輯實(shí)現(xiàn)還是比較簡單的,畢竟它只有一個MainActivity和一個layout。所以,說一個項(xiàng)目的難易得看你選的參照物了。

這篇文章一共25000多個字,820行,我寫這篇文章,不連上寫代碼時間,前后一共11個小時,前面構(gòu)思和注釋了4個小時,然后具體寫了7個小時,中間只有喝水a(chǎn)nd上廁所??梢哉f我完全是按照開發(fā)這款拼圖游戲的邏輯順序來寫下這篇教程。就是我們平時怎么開發(fā)Android項(xiàng)目,這篇博客就是怎么寫的。

我之所以寫的這么詳細(xì),也是因?yàn)楝F(xiàn)在網(wǎng)上缺少一個從頭到尾講實(shí)現(xiàn)過程的Android項(xiàng)目的教程,因?yàn)檫@實(shí)在太花時間了,我深有體會,極少有人一步一步地去把實(shí)現(xiàn)過程寫出來,但是我還是決定寫下這篇教程,為了讓更多的人喜歡上Android,讓更多的人對Android不再陌生,讓小白們不再望而卻步,讓小白們有個很好的實(shí)現(xiàn)案例,這是我的想法。

當(dāng)然,我也是正在學(xué)習(xí)Android的選手之一,才疏學(xué)淺,知識淺薄,文章中難免會有紕漏和錯誤,還希望大佬們批評指正。

七、項(xiàng)目源碼

這次的拼圖游戲項(xiàng)目是一個非常好的Android實(shí)現(xiàn)案例,涉及到很多常用的控件和知識點(diǎn),希望大家拿到源碼后,能對照著教程和注釋好好學(xué)習(xí)掌握。

源碼幾乎每條語句我都加上了注釋,這么良心的博主,點(diǎn)個三連支持下吧,源碼就送你啦,祝大家身體健康,學(xué)習(xí)愉快~

鏈接:拼圖游戲源碼

面向陽光時,陰影在你背后。背向陽光時,陰影在你眼前。世界從未改變,改變的只是我們面對世界的方向!加油!你值得更好!

到此這篇關(guān)于帶你用Android Studio做超好玩的拼圖游戲,0基礎(chǔ)小白也能包你學(xué)會,附送帶有超詳細(xì)注釋源碼的文章就介紹到這了,更多相關(guān)Android拼圖游戲內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android實(shí)現(xiàn)文件的分割和組裝

    Android實(shí)現(xiàn)文件的分割和組裝

    這篇文章主要介紹了Android實(shí)現(xiàn)文件的分割和組裝,針對UDP大數(shù)據(jù)包的分割傳輸與組裝有著非常實(shí)用的價值,需要的朋友可以參考下
    2014-09-09
  • android tv列表焦點(diǎn)記憶實(shí)現(xiàn)的方法

    android tv列表焦點(diǎn)記憶實(shí)現(xiàn)的方法

    本篇文章主要介紹了android tv列表焦點(diǎn)記憶實(shí)現(xiàn)的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04
  • Android使用GridLayout繪制自定義日歷控件

    Android使用GridLayout繪制自定義日歷控件

    這篇文章主要為大家詳細(xì)介紹了Android使用GridLayout繪制自定義日歷控件的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • 詳解flutter engine 那些沒被釋放的東西

    詳解flutter engine 那些沒被釋放的東西

    這篇文章主要介紹了詳解flutter engine 那些沒被釋放的東西,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • 在RecyclerView中實(shí)現(xiàn)button的跳轉(zhuǎn)功能

    在RecyclerView中實(shí)現(xiàn)button的跳轉(zhuǎn)功能

    本次實(shí)驗(yàn)就是在RecyclerView中添加一個button控件并實(shí)現(xiàn)監(jiān)聽,使鼠標(biāo)點(diǎn)擊時可以跳轉(zhuǎn)到另外一個設(shè)計(jì)好的界面,對RecyclerView實(shí)現(xiàn)button跳轉(zhuǎn)功能感興趣的朋友一起看看吧
    2021-10-10
  • 利用DrawerLayout和觸摸事件分發(fā)實(shí)現(xiàn)抽屜側(cè)滑效果

    利用DrawerLayout和觸摸事件分發(fā)實(shí)現(xiàn)抽屜側(cè)滑效果

    這篇文章主要為大家詳細(xì)介紹了利用DrawerLayout和觸摸事件分發(fā)實(shí)現(xiàn)抽屜側(cè)滑效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • 詳解基于Android的Appium+Python自動化腳本編寫

    詳解基于Android的Appium+Python自動化腳本編寫

    這篇文章主要介紹了詳解基于Android的Appium+Python自動化腳本編寫,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Android實(shí)現(xiàn)簡單的文件下載與上傳

    Android實(shí)現(xiàn)簡單的文件下載與上傳

    今天小編就為大家分享一篇關(guān)于Android實(shí)現(xiàn)簡單的文件下載與上傳,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • Kotlin協(xié)程基礎(chǔ)元素梳理分析

    Kotlin協(xié)程基礎(chǔ)元素梳理分析

    這篇文章我們來講協(xié)程的基礎(chǔ)元素,畢竟協(xié)程是一個很強(qiáng)大的設(shè)計(jì)模式,深入了解需要花很多的時間,我們先從簡單開始,其實(shí)學(xué)會了簡單的使用,基本已經(jīng)可以滿足我們平時的開發(fā)需要了,話不多說,開始
    2022-11-11
  • Android NavigationView頭部設(shè)置監(jiān)聽事件

    Android NavigationView頭部設(shè)置監(jiān)聽事件

    這篇文章主要為大家詳細(xì)介紹了Android NavigationView頭部設(shè)置監(jiān)聽事件,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-10-10

最新評論