以下分成幾個部分:
- 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
刪除