以下分成幾個部分:
- ListBank
- 初始化內容
- 更換內容
ListBank
ListBank 的功能在於儲存清單的所有內容,提供給 ListBox 顯示。筆者在設計上讓 ListBank 提供:
- public static instance。儲存整個 scene 中唯一一個 ListBank 的 object 的 reference,讓 ListBox 可以直接存取,免去在 ListBox 額外宣告 public member 來儲存 ListBank object 的 reference,而且要在 Inspector 為每個 ListBox 設定的麻煩。
- 一個儲存資料內容的 array。可以是儲存角色名字的 string array 或是角色圖片的 sprite array,當然也可以是外部檔案的資訊清單,並在 Start() 中呼叫專屬的初始化函式等。
- 兩個基本函式。getListContent 及 getListLength 來存取 array 內容。
using UnityEngine;
using System.Collections;
public class ListBank : MonoBehaviour
{
public static ListBank Instance;
public int numOfListBoxes;
private int[] contents = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
};
void Awake()
{
Instance = this;
}
public int getListContent( int index )
{
return contents[ index ];
}
public int getListLength()
{
return contents.Length;
}
}
( 附註:在上一篇教學中,member numOfListBoxes 是要在 ListBox 中被設定,但是後來改成統一在 ListBank 中設定,而將 ListBox 中的 numOfListBoxes 改為 private,並在 Start() 中初始化 )然後在 scene 中,建立一個空的 gameObject,並將這個 script 貼上去。如此一來,每次 scene 開始時,Instance 變數所存的 reference 就會是這個 gameObject 所產生的 ListBank object。
初始化 ListBox 的顯示內容
根據 ListBox 的 ID 來決定要取得什麼內容。直觀來說,要讓中間的 ListBox 顯示清單中第一個內容,往下依序顯示,而由中間往上的 ListBox,由下往上顯示最後一個、最後第二個...等內容。
第一步就是得到位在中間 ListBox 的 ID,利用 int 除以 int 小數會被捨去的特性,中間 ListBox 的 ID 等於 ( numOfListBoxes / 2 ),例如:5 個 ListBox 就會得到 2,7 個就會得到 3。第二步處理 ID 比中間 ID 大的 ListBox,利用跟中間 ID 的差來決定顯示清單第幾個內容。稍微麻煩的是處理 ID 比中間 ID 小的 ListBox,與中間 ID 差 1 的顯示清單中最後一個內容,差 2 的顯示清單中最後第二個內容,依此類推。
/* Initialize the content of ListBox.
*/
private int contentID;
void initialContent()
{
if ( listBoxID == numOfListBox / 2 )
contentID = 0;
else if ( listBoxID < numOfListBox / 2 )
contentID = ListBank.Instance.getListLength() -
( numOfListBox / 2 - listBoxID );
else
contentID = listBoxID - numOfListBox / 2;
while ( contentID < 0 )
contentID += ListBank.Instance.getListLength();
contentID = contentID % ListBank.Instance.getListLength();
updateContent( ListBank.Instance.getListContent( contentID ).ToString() );
}
void updateContent( string content )
{
text.text = content;
}
在 Start() 呼叫 initialContent() 來初始化 ListBox 的內容,並透過 updateContent() 來更新目標 UI.text 的內容。需要注意的是程式碼中第 15 行到第 17 行是用來讓 contentID 為有效值,以免出現 exception 。當 contentID 為 -n 時,代表顯示最後第 n 個內容,這種情況會發生在可顯示內容比 ListBox 的數量的一半還要少的時候 ( 9 個 ListBox 顯示 3 個內容,或 7 個 ListBox 顯示 2 個內容 ),所以透過加上清單內容數量,得到正確的 contentID。ObjectLabel
只要為每個 ListBox 給與一個 UI.Text 作為 child object,並將 ListBox 的 member "content" 的 reference 指定到這個 text object,就可以用來顯示目前的內容。
隨著移動更換 ListBox 內容
這部分就是 Circular Scrolling List 的精隨。沒錯!就像是鳳尾炸蝦的醬汁一樣。發生時機為 ListBox 需要出現在另一端的時候。情境如下:
- 當 ListBox 出現在上方的時候,其內容為下方 ListBox 的上一個內容;
- 當 ListBox 出現在下方的時候,其內容為上方 ListBox 的下一個內容。
如上圖所示,每個 ListBox 旁標記的是他的 ID,ListBox 間的線把 ListBox 串起來,同時也幫助標記每一個 ListBox 的上一個及下一個 ListBox 是誰。在此以 ListBox_0 做為觀察對象,特別以紅色標記。
- 圖左:初始化的樣貌,可以看到 ListBox_0 顯示清單的最後第二個內容;
- 圖中:ListBox_0 從下方出現,內容更新為上方 ListBox ( ID 4 ) 的下一個內容;
- 圖右:ListBox_4 從上方出現,內容更新為下方 ListBox ( ID 0 ) 的上一個內容。
public ListBox lastListBox;
public ListBox nextListBox;
public int getCurrentContentID()
{
return contentID;
}
void updateToLastContent()
{
contentID = nextListBox.getCurrentContentID() - 1;
contentID = ( contentID < 0 ) ? ListBank.Instance.getListLength() - 1 : contentID;
updateContent( ListBank.Instance.getListContent( contentID ).ToString() );
}
void updateToNextContent()
{
contentID = lastListBox.getCurrentContentID() + 1;
contentID = ( contentID == ListBank.Instance.getListLength() ) ? 0 : contentID;
updateContent( ListBank.Instance.getListContent( contentID ).ToString() );
}
在 checkBoundary() 中,當 ListBox 超出上界時,此時要出現在下方,因此呼叫 updateToNextContent(),反之,則呼叫 updateToLastContent()。當然要記得檢查 contentID 是否在有效的範圍內。最後的程式碼:Github
Part 2 的教學到這邊結束,希望看完都會做鳳尾炸蝦((誤。有問題或是建議歡迎留言討論。
Can you give demo project
回覆刪除Sure! I would upload the project.
刪除Hi! The project file is available here https://drive.google.com/file/d/0B4C0FIMFSOv6UVpXeEJSdERfT2s/view?usp=sharing.
刪除多謝分享!
回覆刪除謝謝! 如果有問題,歡迎提出來
刪除I try to do horizontal mode, but somethings bad. Do you have horizontal version?
刪除It would take me some time to make horizontal version. If it's done, I would leave comment here.
刪除oh, thanks
刪除