纳金网
标题: NGUI实现逐页滑动效果 [打印本页]
作者: 烟雨 时间: 2015-8-31 23:32
标题: NGUI实现逐页滑动效果
今天看了雨松大神关于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);
}
}
欢迎光临 纳金网 (http://go.narkii.com/club/) |
Powered by Discuz! X2.5 |