【Unity】NGUI自制 Scroll View實現觸摸滾動相冊效果

NGUI系列的文章在上一章提到的活靈活現ListView相信你們已經熟練掌握,可是這些是知足不了程序猿的慾望的,哇咔咔~~NGUI中提供了兩種Scroll View 一種是經過手指或鼠標滑動視圖時移動平面物體,另外一種則是直接移動攝像機,他們各有各的好處。可是NGUI提供的Scroll View很難實現相似Android 與 IOS 中的Scroll View 滾動相冊的那種效果,至少MOMO沒有很快的找到方法,不過程序猿的力量是偉大無窮的。雖然不能用它提供的API作出來,可是咱們能夠經過另外的手打巧妙的實現。不用擔憂MOMO會在這篇文章仔細向你們介紹如何實現自制Scroll View實現滾動相冊。數據庫

        以下圖所示,這是咱們的工程頁面,程序的實現原理是將相冊在Unity3D世界中呈橫向隊列,攝像機固定的照射在第一個Item相冊,當手指發生滑動事件時,計算向左滑動仍是向右滑動,此時總體移動相冊隊列,而攝像機不動。爲了讓滑動效果更加好看咱們須要使用插值計算滑動的時間,使滑動隊列不是直接移動過去,而是以必定慣性移動過去。相冊下方咱們製做一個小白點用來記錄當前滑動的位置,在作幾個灰色的點表示隊列一共的長度,滑動時下方的小白點也會跟隨移動,這樣就更想高級控件啦。固然小白點與小灰點是要根據item的數量居中顯示的喔。ide

註解1:滾動相冊通常可分爲兩種,第一種爲數量已知的狀況,第二種爲數量未知的狀況。由於第一種比較簡單因此咱們主要探討第二種。學習

Script historyInit.cs: 該腳本用於相冊隊列的初始化工做。在這裏初始化相冊隊列的數量,計算完畢讓隊列以橫向線性的排列方式在Unity3D中。ui

Prefab item:每一個相冊的預設,我這裏每一個相冊上還會有一些文字的描述,我須要動態的修改它們的內容。你們也可根據本身的狀況製做本身的相冊item。spa

Prefabhui:相冊滾動時下方用來記錄相冊隊列總數的灰色小點。3d

Prefabbai :相冊滾動時下方用來記錄當前滾動頁面ID的白色小點。code

Point :由於灰色、白色的點不能和相冊隊列在一個面板之上,不然會跟着相冊隊列移動而移動,因此這裏將灰色白色的點放在兩外一個面板之上。orm

註解2:這個面板上的4個item就是咱們經過historyinit腳本初始化時動態生成賦值的、當界面發生觸摸事件時,會總體移動該面板讓自對象的相冊隊列跟隨移動。對象

註解3:button0 – button3 是下方的Tabar。bai(Clone)表示白色的小點,hui(Clone)表示灰色的小點,它們的位置是須要根據滑動事件而改變的。blog

wKioL1X2OQXzVwjbAAN3h-HVnIg285.jpg

 

由於咱們須要監聽每個Item的滑動事件,因此確定要在每個item預設之上綁定監聽事件的腳本,以下圖所示。

註解1:由於須要監聽觸摸滑動事件,因此確定要綁定Box Collider組件,這個是NGUI的標準用法。

註解2:Move腳本用來監聽向左滑動 向右滑動 點擊事件。

註解3:這個就是每個相冊的item,在上圖中掛在historyInit腳本之上。

wKiom1X2NtKz1HxKAAHb7qDrEZI786.jpg

 

historyInit.cs

 

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

using UnityEngine;

using System.Collections;

using System.Collections.Generic;

 

public class historyInit  :MonoBehaviour

{

 

//相冊列表的每個item

public GameObject prefab;

//灰色的小點

public GameObject prefabhui;

//白色的小點

public GameObject prefabbai;

//另一個顯示面板

//用來放置灰色、白色小點

public Transform  ponit;

//白色小點的臨時對象

private GameObject bai;

 

//鏈表,用來記錄每個相冊中的一些用戶信息

List<UserData> users = new List<UserData>();

//灰色、白色小點下方的起始位置。

int start;

 

void Start ()

{

//將當前面板對象儲存在全局靜態變量中

Globe.ListPanel = gameObject;

loadSQL ();

initItem();

}

 

//之前是讀取數據庫

//寫例子程序就不必使用數據庫了

//這裏直接寫4個死值,固然數量是靈活使用的

 

void loadSQL ()

{

//表示一共向U3D世界中添加橫向4個相冊隊列

for(int i =0; i< 4; i ++)

{

//簡單的對象儲存

string  name =  "momo =" + i;

string  age =  "26 = " + i;

string  height = "183 ="+ i;

users.Add(new UserData(name,age,height));

}

 

}

 

void initItem()

{

//由於下方灰色 白色的小點須要根據相冊列表的數量來計算居中顯示

int size = users.Count;

//乘以16表示計算全部小點加起來的寬度

int length = (size - 1) * 16;

//獲得下方灰色 白色 小點的居中起始位置

start = (-length) >>1;

 

for(int i=0; i< size; i++)

{

//把每個相冊加入相冊列表

GameObject o  =(GameObject) Instantiate(prefab);

//設置這個對象的父類爲 當前面板

o.transform.parent = transform;

//設置相對父類的座標,這些值可根據本身的狀況而設定,

//總之就是設置相冊列表中每個item的座標,讓它們橫向的排列下來就行

o.transform.localPosition = new Vector3(25 + i* 243,-145f,-86f);

//設置相對父類的縮放

o.transform.localScale= new Vector3(0.7349999f,0.66f,0.7349999f);

 

//獲得每個user的信息

UserData data = users[i];

//遍歷每個相冊對象的子組件,

UILabel []label = o.GetComponentsInChildren<UILabel>();

//拿到UILabel而且設置它們的數據

label[0].text = data.age;

label[1].text = data.height;

label[2].text = data.name;

 

//把每個灰色小點加入3D世界

GameObject hui  =(GameObject) Instantiate(prefabhui);

//設置灰色小點的父類爲另一個面板

hui.transform.parent = ponit;

//設置每個灰色小點的位置與縮放,總之讓它們居中排列顯示在相冊列表下方。

hui.transform.localPosition = new Vector3(start + i* 16,-120f,0f);

hui.transform.localScale= new Vector3(8,8,1);

 

//深度 由於是先在屏幕下方繪製4個灰色的小點, 而後在灰色上面繪製白色小點

//表示當前的窗口ID 因此深度是爲了設置白色小點在灰色小點之上繪製

hui.GetComponent<UISprite>().depth = 0;

}

 

//下面的數據是把當前初始化的數據放在一個static類中

//在Move腳本中就能夠根據這裏的數據來判斷了。

//滑動列表的長度

Globe.list_count = size -1;

//相冊每一項的寬度

Globe.list_offset = 243;

//當前滑動的索引

Globe.list_currentIndex = 0;

//點擊後打開的新遊戲場景

Globe.list_go_name= "LoadScene";

 

//把白色小點也加載在3D世界中

bai  =(GameObject) Instantiate(prefabbai);

//設置它的深度高於 灰色小點,讓白色小點顯示在灰色小點之上

bai.GetComponent<UISprite>().depth = 1;

//設置白色小點的位置

setBaiPos();

}

 

void Update()

{

//當用戶滑動界面

//在Update方法中更新

//當前白色小點的位置

setBaiPos();

}

 

void setBaiPos()

{

//Globe.list_currentIndex 就是當前界面的ID

//根據ID 從新計算白色小點的位置

bai.transform.parent = ponit;

bai.transform.localPosition = new Vector3(start + Globe.list_currentIndex* 16,-120f,-10f);

bai.transform.localScale= new Vector3(8,8,1);

 

}

}

 

以下圖所示,咱們能夠看出Tabbar 、 下方記錄界面的灰色、白色小點、攝像機  它們是不會發生改變的。惟一改變的就是面板之上的相冊隊列。爲了讓滑動界面的效果更加連貫,咱們須要以插值的形式來計算真個相冊面板的座標。

 

wKioL1X2OQbTsEFDAAH_Dbelttw210.jpg

 

觸摸的事件全都寫在Move.cs腳本中。

 

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

using UnityEngine;

using System.Collections;

 

public class Move : MonoBehaviour {

 

//是否觸摸

bool isTouch = false;

//是否向左滑動

bool isRight = false;

//是否向右滑動

bool isLeft = false;

//是否正在滑動中

bool isOnDrag = false;

 

//滑動中事件

void OnDrag (Vector2 delta)

{

//爲了不事件衝突

//這裏只判斷一個滑動的事件

if(!isTouch)

{

if(delta.x > 0.5)

{

//向左滑動

isRight = true;

isOnDrag = true;

}else if(delta.x < -0.5)

{

//向右滑動

isLeft = true;

isOnDrag = true;

}

isTouch = true;

}

}

 

//滑動後鬆手調用OnPress事件

void OnPress()

{

//從新計算當前界面的ID

if(Globe.list_currentIndex < Globe.list_count && isLeft)

{

Globe.list_currentIndex++;

}

 

if(Globe.list_currentIndex >0 && isRight)

{

Globe.list_currentIndex--;

}

 

//表示一次滑動事件結束

isTouch = false;

isLeft = false;

isRight = false;

}

 

void Update()

{

//這個方法就是本節內容的核心

//Globe.ListPanel 這個對象是咱們在historyInit腳本中獲得的,它用來當面相冊面板對象使用插值,讓面板有慣性的滑動。

 

//Vector3.Lerp() 這個是一個插值的方法, 參數1 表示開始的位置 參數2 表示結束的位置  參數3 表示一共所用的時間, 在Time.deltaTime * 5 時間之內 Update每一幀中獲得插值當前的數值,只到插值結束

 

//-(Globe.list_currentIndex * Globe.list_offset) 獲得當前須要滑動的目標點。

//請你們仔細看這個方法。

 

Globe.ListPanel.transform.localPosition =Vector3.Lerp(Globe.ListPanel.transform.localPosition, new Vector3(-(Globe.list_currentIndex * Globe.list_offset),0,0), Time.deltaTime * 5);

}

 

void OnClick ()

{

//當點擊某個item時進入這裏

 

if(!isOnDrag)

{

//若是不是在拖動中 進入另外一個場景

Application.LoadLevel(Globe.list_go_name);

}

else

{

//不然等待用戶從新發生觸摸事件

isOnDrag = false;

}

}

}

 

還有兩個輔助的類,我也貼出來。

UserData.cs

 

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

using UnityEngine;

using System.Collections;

 

public class UserData{

 

public string name;

public string age;

public string height;

public string hand;

 

public UserData(string _name, string _age,string _height)

{

age = _age;

height = _height;

name = _name;

}

 

}

 

Globe.cs 這個靜態類用來共享記錄多個腳本甚至多個場景所需的數據。

 

C#

1

2

3

4

5

6

7

8

9

10

11

using System.Collections.Generic;

public class Globe

{

 

public static GameObject ListPanel;

public static int list_count;

public static int list_currentIndex;

public static int list_offset;

public static string list_go_name;

 

}

 

寫到這裏,本篇博文就寫的差很少了。這篇文章我是用NGUI來實現的觸摸滾動效果,仔細想一想,其實不用NGUI徹底也能實現這樣的效果。在腳本中徹底能夠經過射線 以及 觸摸的時間去計算當前用戶操做的事件,這篇文章裏的工程最後我是打包在Android上面的,效果挺不錯,滑動的效果圖很差截取我也不截取了,主要仍是文章的書寫內容,但願你們學習愉快,雨鬆MOMO祝你們晚安,哇咔咔,啦啦啦。

相關文章
相關標籤/搜索