今天看了雨松大神关于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); } } |