查看: 782|回复: 0
打印 上一主题 下一主题

[其他] NGUI实现逐页滑动效果

[复制链接]

9903

主题

126

听众

7万

积分

首席设计师

Rank: 8Rank: 8

纳金币
53456
精华
316

最佳新人 热心会员 灌水之王 活跃会员 突出贡献 荣誉管理 论坛元老

跳转到指定楼层
楼主
发表于 2015-8-31 23:32:35 |只看该作者 |倒序浏览


今天看了雨松大神关于Scroll View实现触摸滚动相册效果的文章(http://www.xuanyusong.com/archives/1465)后,感觉受益匪浅, 然后就对该文的方法做了写改进(自认为), 在此和大家一起分享, 当然有任何不足之处还请指出,共同进步。首先,我认为雨松大神的思路是很有启发的,但是直接用这个方法的主要存在三个问题:1. 耦合性太强(当然这只是大神给出的Demo) 2. 当我们按住拖动不放的时候,整个相册并不会跟着移动,和我们一般游戏里的情况不符。 3。 如果我们的个数比较多的时候,也没有做一些优化。

故我将从这三个方面进行一些改变。

首先是耦合性:

我的思路是:
Script UIPageItem.cs: 代表一张相册, 它自己负责对自己的UI进行刷新(即SetData方法,对于自己不同的需求自己去继承和重写它就可以了),用来刷新的真正数据由PageScroller来派发。
Script PageScroller.cs: 该脚本用于管理相册的滑动,同时包含了每一个相册用来刷新的数据列表。
Script Move.cs:用于检测各种事件,包括刚开始拖拽, 拖拽中, 松手, 和点击,然后抛出这些事件,让对此感兴趣的人去注册和响应。在这里是由PageScroller.cs来处理。
到现在又不知道该怎么写了,原谅原谅, 呵呵,第一次写博客,思路有点乱,还是直接上代码吧:
using System;
using System.Collections.Generic;
using UnityEngine;
public class PageScroller<T> where T : UIPageItem, new()
{
    public Action<int> PageChanged;
    /// <summary>
    /// 存放Item的列表
    /// </summary>
    readonly List<T> itemList = new List<T>();
    /// <summary>
    /// 存放所有的数据列表
    /// </summary>
    List<object> data = new List<object>();
    private int CurPage
    {
        get { return curPage; }
        set
        {
            if (curPage != value)
            {
                var min = Mathf.Min(curPage, value);
                var max = Mathf.Max(curPage, value);
                for (var i = min; i <= max; i++)
                {
                    if(i < 0)
                    {
                        continue;
                    }
                    var item = itemList;
                    item.Show();
                }
                curPage = value;
                if (PageChanged != null)
                {
                    PageChanged(curPage);
                }
            }
            var springPanel = SpringPanel.Begin(gameObject, cachedPos + curPage * offset * Vector3.left, 10);
            springPanel.onFinished = OnSpringFinished;
        }
    }
    //不要主动去修改这个变量
    private int curPage = -1;
    private int dataCount;
    private readonly float offset;
    private readonly Vector3 cachedPos;
    private readonly GameObject gameObject;
    private readonly UIPanel panel;
    private Vector3 dragStartPos;
    public PageScroller(GameObject gameObject)
    {
        this.gameObject = gameObject;
        panel = gameObject.GetComponent<UIPanel>();
        offset = panel.finalClipRegion.z;
        cachedPos = gameObject.transform.localPosition;
    }
    public void SetDataProvider(List<object> datas)
    {
        data = datas;
        var itemCount = itemList.Count;
        if (data == null)
        {
            for (var i = 0; i < itemCount; i++)
            {
                itemList.Hide();
            }
            return;
        }
        dataCount = data.Count;
        for (var i = 0; i < dataCount; i++)
        {
            if (i < itemCount)
            {
                var item = itemList;
                item.SetData(data);
                item.SetLocalPosition(offset * i * Vector3.right);
                var move = item.GetMove();
                move.ItemDrag = OnItemDrag;
                move.ItemMoved = OnItemMoved;
                move.ItemDragStart = OnItemDragStart;
            }
            else
            {
                var item = new T();
                item.SetToParent(gameObject.transform);
                item.Hide();
                var move = item.GetMove();
                move.ItemMoved = OnItemMoved;
                move.ItemDrag = OnItemDrag;
                move.ItemDragStart = OnItemDragStart;
                itemList.Add(item);
                item.SetData(data);
                item.SetLocalPosition(offset * i * Vector3.right);
            }
        }
        if (CurPage == -1)
        {
            CurPage = 0;
        }
    }
    private void OnItemDragStart()
    {
        dragStartPos = gameObject.transform.localPosition;
    }
    private void OnItemDrag(Vector2 obj)
    {
        var localPos = gameObject.transform.localPosition;
        localPos += new Vector3(obj.x, 0, 0);
        if (Mathf.Abs(localPos.x - dragStartPos.x) < offset)
        {
            gameObject.transform.localPosition = localPos;
            panel.clipOffset = new Vector2(-gameObject.transform.localPosition.x, 0);
        }
    }
    private void OnItemMoved(bool obj)
    {
        NextPage(obj);
    }
    public void NextPage(bool next)
    {
        if (next)
        {
            if (CurPage < dataCount - 1)
            {
                CurPage++;
            }
            else
            {
                var springPanel = SpringPanel.Begin(gameObject, cachedPos + curPage * offset * Vector3.left, 10);
                springPanel.onFinished = OnSpringFinished;
            }
        }
        else
        {
            if (curPage > 0)
            {
                CurPage--;
            }
            else
            {
                var springPanel = SpringPanel.Begin(gameObject, cachedPos + curPage * offset * Vector3.left, 10);
                springPanel.onFinished = OnSpringFinished;
            }
        }
    }
    public void MoveToPage(int index)
    {
        CurPage = index;
    }
    private void OnSpringFinished()
    {
        for(var i = 0; i < dataCount; i++)
        {
            var item = itemList;
            if (Mathf.Abs(CurPage - i) <= 1)
            {
                item.Show();
            }
            else
            {
                item.Hide();
            }
        }
    }
}
public class UIPageItem
{
    public GameObject ViewRoot;
    public UIPageItem()
    {
    }
    public virtual void SetData(object data)
    {
    }
    public void SetToParent(Transform parent)
    {
        ViewRoot.transform.parent = parent;
        NGUITools.SetLayer(ViewRoot, parent.gameObject.layer);
        ViewRoot.transform.localPosition = Vector3.zero;
        ViewRoot.transform.localRotation = Quaternion.identity;
        ViewRoot.transform.localScale = Vector3.one;
    }
    public void SetLocalPosition(Vector3 vector3)
    {
        ViewRoot.transform.localPosition = vector3;
    }
    public void Hide()
    {
        ViewRoot.SetActive(false);
    }
    public void Show()
    {
        ViewRoot.SetActive(true);
    }
    public Move GetMove()
    {
        var move = ViewRoot.GetComponent<Move>();
        if (move != null)
        {
            return move;
        }
        return ViewRoot.AddComponent<Move>();
    }
}
你自己的Item,继承于UIPageItem, 我这个Demo中的是这样的
using UnityEngine;
public class UIItem : UIPageItem
{
    private UILabel nameLbl;
    private UILabel ageLbl;
    private UILabel heightLbl;
    private UserData userData;
    public UIItem()
    {
        var prefab = Resources.Load<GameObject>("Prefabs/Item");
        ViewRoot = Object.Instantiate(prefab) as GameObject;
        OnInit();
    }
    protected void OnInit()
    {
        nameLbl = ViewRoot.transform.Find("Name/NameValue").GetComponent<UILabel>();
        ageLbl = ViewRoot.transform.Find("Age/AgeValue").GetComponent<UILabel>();
        heightLbl = ViewRoot.transform.Find("Height/HeightValue").GetComponent<UILabel>();
    }
    public override void SetData(object data)
    {
        var tempData = data as UserData;
        if (tempData == null || tempData == userData)
        {
            return;
        }
        userData = new UserData(tempData);
        nameLbl.text = userData.Name;
        ageLbl.text = userData.Age;
        heightLbl.text = userData.Height;
    }
}
对应的数据类,用来刷新每一个Item
public class UserData
{
    public string Name;
    public string Age;
    public string Height;
    public static bool operator ==(UserData operand1, UserData operand2)
    {
        return Equals(operand1, operand2);
    }
    public static bool operator !=(UserData operand1, UserData operand2)
    {
        return !(operand1 == operand2);
    }
    public override bool Equals(object obj)
    {
        //判断与之比较的类型是否为null。这样不会造成递归的情况
        if (obj == null)
            return false;
        if (GetType() != obj.GetType())
            return false;
        var rec = (UserData)obj;
        return Name == rec.Name && Age == rec.Age && Height == rec.Height;
    }
}
测试和初始化的代码
using System.Collections.Generic;
using UnityEngine;
public class Init : MonoBehaviour
{
    readonly List<object> users = new List<object>();
    private PageScroller<UIItem> pageScroller;
    public int Index;
    private int start;
    void Start()
    {
        pageScroller = new PageScroller<UIItem>(gameObject);
        LoadSQL();
        InitItems();
    }
    private void OnGUI()
    {
        if(GUILayout.Button("Change"))
        {
            ((UserData) users[Index]).Height += 30;
            pageScroller.SetDataProvider(users);
        }
        if(GUILayout.Button("ResetPosition"))
        {
            pageScroller.MoveToPage(Index);
        }
    }
    private void LoadSQL()
    {
        for(var i = 0; i < 10; i++)
        {
            users.Add(new UserData{ Name = "yongquan" + i, Age = ""+(29 + i), Height = ""+ (170 +i)});
        }
    }
    private void InitItems()
    {
        pageScroller.SetDataProvider(users);
    }
}
分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏0 支持支持0 反对反对0
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

关闭

站长推荐上一条 /1 下一条

手机版|纳金网 ( 闽ICP备08008928号

GMT+8, 2024-5-6 09:36 , Processed in 0.093282 second(s), 29 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部