NGUI系列教程十(Scroll View實現觸摸滾動相冊效果)

  NGUI中提供了兩種Scroll View 一種是經過手指或鼠標滑動視圖時移動平面物體,另外一種則是直接移動攝像機,他們各有各的好處。可是NGUI提供的Scroll View很難實現相似Android 與 IOS 中的Scroll View 滾動相冊的那種效果,不過程序猿的力量是偉大無窮的。雖然不能用它提供的API作出來,可是咱們能夠經過另外的手打巧妙的實現。這篇文章仔細向你們介紹如何實現自制Scroll View實現滾動相冊。php

        以下圖所示數據庫

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

首先咱們來看下,Panel的的腳本historyInit.csui

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];
            Move moveScript = o.GetComponent<Move>();
            moveScript.AgeLabel.text = data.age;
            moveScript.HeightLabel.text = data.height;
            moveScript.NameLabel.text = data.name;
            ////遍歷每個相冊對象的子組件,
            //UILabel[] label = o.GetComponentsInChildren<UILabel>();
            ////拿到UILabel而且設置它們的數據
            //label[1].text = data.age;   
            //label[2].text = data.height;
            //label[3].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);
        print(bai);
        //設置它的深度高於 灰色小點,讓白色小點顯示在灰色小點之上
        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);

    }
}

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

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

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

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

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

 

咱們須要監聽每個CardItem的滑動事件,因此確定要在每個CardItem預設之上綁定監聽事件的腳本,這裏是Move.cs,以下圖所示。blog

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

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

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

 

using UnityEngine;
using System.Collections;

public class Move : MonoBehaviour
{

    //是否觸摸
    bool isTouch = false;
    //是否向左滑動
    bool isRight = false;
    //是否向右滑動
    bool isLeft = false;
    //是否正在滑動中
    bool isOnDrag = false;
    public UILabel AgeLabel;
    public UILabel HeightLabel;
    public UILabel NameLabel;
    public UILabel UserLabel;

    //滑動中事件
    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

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 這個靜態類用來共享記錄多個腳本甚至多個場景所需的數據。

using System.Collections.Generic;
using UnityEngine;
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;

}

參考:http://www.xuanyusong.com/archives/1465

個人項目:http://pan.ceeger.com/viewfile.php?file_id=1827&file_key=KOdeQf5o

相關文章
相關標籤/搜索