[Unity UGUI]ScrollRect效果大全

UGUI各种优化效果

本文所实现的UGUI效果需求如下: 
支持缩放滑动效果 
支持动态缩放循环加载 
支持大数据固定Item复用加载 
支持不用Mask遮罩无限循环加载 
支持ObjectPool动态加载 
支持无限不规则子物体动态加载 
支持拖动并点击和拖拽 
支持拖动并拖拽 
支持ScrollRect拖动自动吸附功能(拖动是否超过一半自动进退)


前言

要实现以上效果,我从网上搜索得到部分解决方案链接,但不是完全满足想要的效果,就自己继续改造优化和添加想要的效果,本文最后会附带上完整Demo下载链接。

效果图

  • 缩放滑动效果 
    这里写图片描述

  • 缩放循环展示卡牌效果

这里写图片描述

  • 大量数据无卡顿动态加载,并且支持拖拽、点击和吸附功能

这里写图片描述

  • 大量数据循固定Item复用 
    这里写图片描述

  • 无限无遮罩动态加载

这里写图片描述

  • 不规则子物体动态循环加载

这里写图片描述

部分核心代码

  • 有遮罩无卡顿加载 
    思路:并没有使用UGUI的ScrollRect组件,摆放几张卡片,通过移动和缩放来实现
  1 using UnityEngine;
  2 using System.Collections;
  3 using System.Collections.Generic;
  4 using UnityEngine.UI;
  5 
  6 public class EnhancelScrollView : MonoBehaviour
  7 {
  8     // 缩放曲线
  9     public AnimationCurve scaleCurve;
 10     // 位移曲线
 11     public AnimationCurve positionCurve;
 12     // 位移系数
 13     public float posCurveFactor = 500.0f;
 14     // y轴坐标固定值(所有的item的y坐标一致)
 15     public float yPositionValue = 46.0f;
 16 
 17     // 添加到EnhanceScrollView的目标对象
 18     public List<EnhanceItem> scrollViewItems;
 19     // 目标对象Widget脚本,用于depth排序
 20     private List<Image> imageTargets;
 21 
 22     // 当前处于中间的item
 23     private EnhanceItem centerItem;
 24     private EnhanceItem preCenterItem;
 25 
 26     // 当前出移动中,不能进行点击切换
 27     private bool canChangeItem = true;
 28 
 29     // 计算差值系数
 30     public float dFactor = 0.2f;
 31 
 32     // 点击目标移动的横向目标值
 33     private float[] moveHorizontalValues;
 34     // 对象之间的差值数组(根据差值系数算出)
 35     private float[] dHorizontalValues;
 36 
 37     // 横向变量值
 38     public float horizontalValue = 0.0f;
 39     // 目标值
 40     public float horizontalTargetValue = 0.1f;
 41 
 42     // 移动动画参数
 43     private float originHorizontalValue = 0.1f;
 44     public float duration = 0.2f;
 45     private float currentDuration = 0.0f;
 46 
 47     private static EnhancelScrollView instance;
 48     public static EnhancelScrollView GetInstance()
 49     {
 50         return instance;
 51     }
 52 
 53     void Awake()
 54     {
 55         instance = this;
 56     }
 57 
 58     void Start()
 59     {
 60         if((scrollViewItems.Count % 2) == 0)    
 61         {
 62             Debug.LogError("item count is invaild,please set odd count! just support odd count.");
 63         }
 64 
 65         if(moveHorizontalValues == null)
 66             moveHorizontalValues = new float[scrollViewItems.Count];
 67 
 68         if(dHorizontalValues == null)
 69             dHorizontalValues = new float[scrollViewItems.Count];
 70 
 71         if (imageTargets == null)
 72             imageTargets = new List<Image>();
 73 
 74         int centerIndex = scrollViewItems.Count / 2;
 75         for (int i = 0; i < scrollViewItems.Count;i++ )
 76         {
 77             scrollViewItems[i].scrollViewItemIndex = i;
 78             Image tempImage = scrollViewItems[i].gameObject.GetComponent<Image>();
 79             imageTargets.Add(tempImage);
 80 
 81             dHorizontalValues[i] = dFactor * (centerIndex - i);
 82 
 83             dHorizontalValues[centerIndex] = 0.0f;
 84             moveHorizontalValues[i] = 0.5f - dHorizontalValues[i];
 85             scrollViewItems[i].SetSelectColor(false);
 86         }
 87 
 88         centerItem = scrollViewItems[centerIndex];
 89         canChangeItem = true;
 90     }
 91 
 92     public void UpdateEnhanceScrollView(float fValue)
 93     {
 94         for (int i = 0; i < scrollViewItems.Count; i++)
 95         {
 96             EnhanceItem itemScript = scrollViewItems[i];
 97             float xValue = GetXPosValue(fValue, dHorizontalValues[itemScript.scrollViewItemIndex]);
 98             float scaleValue = GetScaleValue(fValue, dHorizontalValues[itemScript.scrollViewItemIndex]);
 99             itemScript.UpdateScrollViewItems(xValue, yPositionValue, scaleValue);
100         }
101     }
102 
103     void Update()
104     {
105         currentDuration += Time.deltaTime;
106         if (currentDuration > duration)
107         {
108             // 更新完毕设置选中item的对象即可
109             currentDuration = duration;
110             if (centerItem != null)
111                 centerItem.SetSelectColor(true);
112             if (preCenterItem != null)
113                 preCenterItem.SetSelectColor(false);
114             canChangeItem = true;
115         }
116 
117         SortDepth();
118         float percent = currentDuration / duration;
119         horizontalValue = Mathf.Lerp(originHorizontalValue, horizontalTargetValue, percent);
120         UpdateEnhanceScrollView(horizontalValue);
121     }
122 
123     /// <summary>
124     /// 缩放曲线模拟当前缩放值
125     /// </summary>
126     private float GetScaleValue(float sliderValue, float added)
127     {
128         float scaleValue = scaleCurve.Evaluate(sliderValue + added);
129         return scaleValue;
130     }
131 
132     /// <summary>
133     /// 位置曲线模拟当前x轴位置
134     /// </summary>
135     private float GetXPosValue(float sliderValue, float added)
136     {
137         float evaluateValue = positionCurve.Evaluate(sliderValue + added) * posCurveFactor;
138         return evaluateValue;
139     }
140 
141     public void SortDepth()
142     {
143         imageTargets.Sort(new CompareDepthMethod());
144         for (int i = 0; i < imageTargets.Count; i++)
145             imageTargets[i].transform.SetSiblingIndex(i);
146     }
147 
148     /// <summary>
149     /// 用于层级对比接口
150     /// </summary>
151     public class CompareDepthMethod : IComparer<Image>
152     {
153         public int Compare(Image left, Image right)
154         {
155             if (left.transform.localScale.x > right.transform.localScale.x)
156                 return 1;
157             else if (left.transform.localScale.x < right.transform.localScale.x)
158                 return -1;
159             else
160                 return 0;
161         }
162     }
163 
164     /// <summary>
165     /// 获得当前要移动到中心的Item需要移动的factor间隔数
166     /// </summary>
167     private int GetMoveCurveFactorCount(float targetXPos)
168     {
169         int centerIndex = scrollViewItems.Count / 2;
170         for (int i = 0; i < scrollViewItems.Count;i++ )
171         {
172             float factor = (0.5f - dFactor * (centerIndex - i));
173 
174             float tempPosX = positionCurve.Evaluate(factor) * posCurveFactor;
175             if (Mathf.Abs(targetXPos - tempPosX) < 0.01f)
176                 return Mathf.Abs(i - centerIndex);
177         }
178         return -1;
179     }
180 
181     /// <summary>
182     /// 设置横向轴参数,根据缩放曲线和位移曲线更新缩放和位置
183     /// </summary>
184     public void SetHorizontalTargetItemIndex(int itemIndex)
185     {
186         if (!canChangeItem)
187             return;
188 
189         EnhanceItem item = scrollViewItems[itemIndex];
190         if (centerItem == item)
191             return;
192 
193         canChangeItem = false;
194         preCenterItem = centerItem;
195         centerItem = item;
196 
197         // 判断点击的是左侧还是右侧计算ScrollView中心需要移动的value
198         float centerXValue = positionCurve.Evaluate(0.5f) * posCurveFactor;
199         bool isRight = false;
200         if (item.transform.localPosition.x > centerXValue)
201             isRight = true;
202 
203         // 差值,计算横向值
204         int moveIndexCount = GetMoveCurveFactorCount(item.transform.localPosition.x);
205         if (moveIndexCount == -1)
206         {
207             moveIndexCount = 1; 
208         }
209 
210         float dvalue = 0.0f;
211         if (isRight)
212             dvalue = -dFactor * moveIndexCount;
213         else
214             dvalue = dFactor * moveIndexCount;
215 
216         // 更改target数值,平滑移动
217         horizontalTargetValue += dvalue;
218         currentDuration = 0.0f;
219         originHorizontalValue = horizontalValue;
220     }
221 
222     /// <summary>
223     /// 向右选择角色按钮
224     /// </summary>
225     public void OnBtnRightClick()
226     {
227         if (!canChangeItem)
228             return;
229         int targetIndex = centerItem.scrollViewItemIndex + 1;
230         if (targetIndex > scrollViewItems.Count - 1)
231             targetIndex = 0;
232         SetHorizontalTargetItemIndex(targetIndex);
233     }
234 
235     /// <summary>
236     /// 向左选择按钮
237     /// </summary>
238     public void OnBtnLeftClick()
239     {
240         if (!canChangeItem)
241             return;
242         int targetIndex = centerItem.scrollViewItemIndex - 1;
243         if (targetIndex < 0)
244             targetIndex = scrollViewItems.Count - 1;
245         SetHorizontalTargetItemIndex(targetIndex);
246     }
247 }
View Code
 1 using UnityEngine;
 2 using System.Collections;
 3 using UnityEngine.UI;
 4 
 5 public class EnhanceItem : MonoBehaviour {
 6 
 7     // 在ScrollViewitem中的索引
 8     // 定位当前的位置和缩放
 9     public int scrollViewItemIndex = 0;
10     public bool inRightArea = false;
11 
12     private Vector3 targetPos = Vector3.one;
13     private Vector3 targetScale = Vector3.one;
14 
15     private Transform mTrs;
16     private Image mImage;
17 
18 
19     void Awake()
20     {
21         mTrs = this.transform;
22         mImage = this.GetComponent<Image>();
23     }
24 
25     void Start()
26     {
27         this.gameObject.GetComponent<Button>().onClick.AddListener(delegate () { OnClickScrollViewItem(); });
28     }
29 
30     // 当点击Item,将该item移动到中间位置
31     private void OnClickScrollViewItem()
32     {
33         EnhancelScrollView.GetInstance().SetHorizontalTargetItemIndex(scrollViewItemIndex);
34     }
35 
36     /// <summary>
37     /// 更新该Item的缩放和位移
38     /// </summary>
39     public void UpdateScrollViewItems(float xValue, float yValue, float scaleValue)
40     {
41         targetPos.x = xValue;
42         targetPos.y = yValue;
43         targetScale.x = targetScale.y = scaleValue;
44 
45         mTrs.localPosition = targetPos;
46         mTrs.localScale = targetScale;
47     }
48 
49     public void SetSelectColor(bool isCenter)
50     {
51         if (mImage == null)
52             mImage = this.GetComponent<Image>();
53 
54         if (isCenter)
55             mImage.color = Color.white;
56         else
57             mImage.color = Color.gray;
58     }
59 }
View Code
  • 有遮罩无卡顿加载 
    思路:协程加载,先加载屏幕显示的数量,然后返回一帧在继续加载,防止出现数量太大卡顿的现象。
 1 while (CardsList.Count > roleInfo.Count)
 2 {
 3     DestroyImmediate(CardsList[0].gameObject);
 4     CardsList.RemoveAt(0);
 5 }
 6 StartCoroutine(createRoleCards());
 7 
 8 private IEnumerator createRoleCards()
 9 {
10     List<CLocalCharInfo> charInfos = new List<CLocalCharInfo>();
11     charInfos.AddRange(roleInfo);
12     int index = 0;
13     for (int i = 0; i < charInfos.Count; i++)
14     {
15         _createRoleCard(charInfos[i], index++);
16         if (index % 10 == 0)
17             yield return null;
18     }
19 }
20 
21 private void _createRoleCard(CLocalCharInfo roleInfo, int index)
22 {
23     CUIPlayedCharCardWidget charCardWidget = null;
24     if (CardsList.Count > index)
25     {
26         charCardWidget = CardsList[index];
27     }
28     else
29     {
30         var obj = Instantiate(Resources.Load<GameObject>("Prefab/RoleCard")) as GameObject;
31         if (obj == null)
32         {
33             UnityEngine.Debug.LogError("有误");
34             return;
35         }
36         obj.name = roleInfo.Name;
37 
38         charCardWidget = obj.GetComponent<CUIPlayedCharCardWidget>();
39 
40         if (charCardWidget == null)
41         {
42             UnityEngine.Debug.LogError("有误");
43             return;
44         }
45         obj.transform.parent = Obj_ScrollViewContent.transform;
46         obj.transform.localScale = Vector3.one;
47         CardsList.Add(charCardWidget);
48     }
49 
50     CUIPlayedCharCardWidget.CUIContent uiContent = new CUIPlayedCharCardWidget.CUIContent();
51     uiContent.RoleInfo = roleInfo;
52     uiContent.ScrollRectObj = m_ScrollRect;
53     uiContent.FixGridRect = m_FixGrid;
54     charCardWidget.InitContent(uiContent);
55 }
View Code
  • 支持ScrollRect拖拽或点击 
    思路:在卡片的Image上添加一个继承了IBeginDragHandler,IGradHandler,IEndDragHandler的脚本,重写接口里面的Drag事件方法。
  1 using UnityEngine;
  2 using UnityEngine.EventSystems;
  3 using UnityEngine.UI;
  4 
  5 namespace Mga
  6 {
  7     [RequireComponent(typeof(Image))]
  8     public class CPlayedCardOnDrag : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
  9     {
 10         public bool dragOnSurfaces = true;
 11         public ScrollRect m_ScrollRect = null;
 12         public CFixGridRect m_FixGridRect = null;
 13         private GameObject m_DraggingCard;
 14         private RectTransform m_DraggingPlane;
 15 
 16         public bool isVertical = false;
 17         private bool isSelf = false;
 18 
 19         private System.Action m_OnBeginDragCallBack = null;
 20         private System.Action m_OnEndDragCallBack = null;
 21 
 22         private System.Action m_OnBeginScroll = null;
 23         private System.Action m_OnEndScroll = null;
 24         public void Init(CLocalCharInfo roleInfo, System.Action beginCallBack = null, System.Action endCallBack = null, System.Action beginScroll = null, System.Action endScroll = null)
 25         {
 26             m_OnBeginDragCallBack = beginCallBack;
 27             m_OnEndDragCallBack = endCallBack;
 28             m_OnBeginScroll = beginScroll;
 29             m_OnEndScroll = endScroll;
 30         }
 31         public void OnBeginDrag(PointerEventData eventData)
 32         {
 33             Vector2 touchDeltaPosition = Vector2.zero;
 34 #if UNITY_EDITOR
 35             float delta_x = Input.GetAxis("Mouse X");
 36             float delta_y = Input.GetAxis("Mouse Y");
 37             touchDeltaPosition = new Vector2(delta_x, delta_y);
 38 
 39 #elif UNITY_ANDROID || UNITY_IPHONE
 40         touchDeltaPosition = Input.GetTouch(0).deltaPosition;  
 41 #endif
 42             if (isVertical)
 43             {
 44                 if (Mathf.Abs(touchDeltaPosition.x) > Mathf.Abs(touchDeltaPosition.y))
 45                 {
 46                     isSelf = true;
 47                     var canvas = FindInParents<Canvas>(gameObject);
 48                     if (canvas == null)
 49                         return;
 50                     m_DraggingCard = createCard();
 51                     m_DraggingCard.transform.SetAsLastSibling();
 52 
 53                     m_DraggingCard.AddComponent<CIgnoreRayCast>();
 54 
 55                     if (dragOnSurfaces)
 56                         m_DraggingPlane = transform as RectTransform;
 57                     else
 58                         m_DraggingPlane = canvas.transform as RectTransform;
 59 
 60                     SetDraggedPosition(eventData);
 61                     if (m_OnBeginDragCallBack != null)
 62                     {
 63                         m_OnBeginDragCallBack();
 64                     }
 65                 }
 66                 else
 67                 {
 68                     isSelf = false;
 69                     if (m_ScrollRect != null)
 70                         m_ScrollRect.OnBeginDrag(eventData);
 71                 }
 72             }
 73             else
 74             {
 75                 if (Mathf.Abs(touchDeltaPosition.x) < Mathf.Abs(touchDeltaPosition.y))
 76                 {
 77                     isSelf = true;
 78                     var canvas = FindInParents<Canvas>(gameObject);
 79                     if (canvas == null)
 80                         return;
 81                     m_DraggingCard = createCard();
 82                     m_DraggingCard.transform.SetAsLastSibling();
 83 
 84                     m_DraggingCard.AddComponent<CIgnoreRayCast>();
 85 
 86                     if (dragOnSurfaces)
 87                         m_DraggingPlane = transform as RectTransform;
 88                     else
 89                         m_DraggingPlane = canvas.transform as RectTransform;
 90 
 91                     SetDraggedPosition(eventData);
 92                     if (m_OnBeginDragCallBack != null)
 93                     {
 94                         m_OnBeginDragCallBack();
 95                     }
 96                 }
 97                 else
 98                 {
 99                     isSelf = false;
100                     if (m_ScrollRect != null)
101                         m_ScrollRect.OnBeginDrag(eventData);
102                 }
103             }
104             if (m_OnBeginScroll != null)
105                 m_OnBeginScroll();
106         }
107 
108         public void OnDrag(PointerEventData data)
109         {
110             if (isSelf)
111             {
112                 if (m_DraggingCard != null)
113                 {
114                     SetDraggedPosition(data);
115                 }
116             }
117             else
118             {
119                 if (m_ScrollRect != null)
120                     m_ScrollRect.OnDrag(data);
121             }
122         }
123 
124         private void SetDraggedPosition(PointerEventData data)
125         {
126             if (dragOnSurfaces && data.pointerEnter != null && data.pointerEnter.transform as RectTransform != null)
127                 m_DraggingPlane = data.pointerEnter.transform as RectTransform;
128 
129             var rt = m_DraggingCard.GetComponent<RectTransform>();
130             Vector3 globalMousePos;
131             if (RectTransformUtility.ScreenPointToWorldPointInRectangle(m_DraggingPlane, data.position, data.pressEventCamera, out globalMousePos))
132             {
133                 rt.position = globalMousePos;
134                 rt.rotation = m_DraggingPlane.rotation;
135             }
136         }
137 
138         private GameObject createCard()
139         {
140             CUIPlayedCharCardWidget charCardWidget = null;
141             m_DraggingCard = Instantiate(Resources.Load<GameObject>("Prefab/RoleCard") as GameObject);
142             if (m_DraggingCard == null)
143             {
144                 return null;
145             }
146             charCardWidget = m_DraggingCard.GetComponent<CUIPlayedCharCardWidget>();
147 
148             if (charCardWidget == null)
149             {
150                 return null;
151             }
152 
153             CUIPlayedCharCardWidget.CUIContent uiContent = new CUIPlayedCharCardWidget.CUIContent();
154 
155             charCardWidget.InitContent(uiContent);
156             return m_DraggingCard;
157         }
158 
159         public void OnEndDrag(PointerEventData eventData)
160         {
161             if (isSelf)
162             {
163                 if (m_DraggingCard != null)
164                 {
165                     Destroy(m_DraggingCard);
166                     if (m_OnEndDragCallBack != null)
167                     {
168                         m_OnEndDragCallBack();
169                     }
170                 }
171             }
172             else
173             {
174                 if (m_ScrollRect != null)
175                     m_ScrollRect.OnEndDrag(eventData);
176                 if (m_FixGridRect != null)
177                     m_FixGridRect.OnEndDrag(eventData);
178             }
179 
180         }
181 
182         static public T FindInParents<T>(GameObject go) where T : Component
183         {
184             if (go == null) return null;
185             var comp = go.GetComponent<T>();
186 
187             if (comp != null)
188                 return comp;
189 
190             Transform t = go.transform.parent;
191             while (t != null && comp == null)
192             {
193                 comp = t.gameObject.GetComponent<T>();
194                 t = t.parent;
195             }
196             return comp;
197         }
198     }
199 }
View Code

如果想要实现拖拽到目标位置的检测,还要在目标位置放一个Image并且添加上继承了IDropHandler,IPointerEnterHandler,IPointerExitHanler的组件。

 1 using System.Reflection;
 2 using UnityEngine;
 3 using UnityEngine.EventSystems;
 4 using UnityEngine.UI;
 5 using System.Collections;
 6 namespace Mga
 7 {
 8     public class CPlayedCardOnDrop : MonoBehaviour, IDropHandler, IPointerEnterHandler, IPointerExitHandler
 9     {
10         public Image containerImage;
11         public Image receivingImage;
12         private Color normalColor;
13         public Color highlightColor = Color.yellow;
14         private int drapAreaIndex = 0;
15 
16         void Start()
17         {
18             drapAreaIndex = System.Convert.ToInt32(this.transform.parent.name);
19         }
20 
21         public void OnEnable()
22         {
23             if (containerImage != null)
24                 normalColor = containerImage.color;
25         }
26 
27         public void OnDrop(PointerEventData data)
28         {
29             containerImage.color = normalColor;
30 
31             if (receivingImage == null)
32                 return;
33             Sprite dropSprite = GetDropSprite(data);
34             if (dropSprite != null)
35                 receivingImage.overrideSprite = dropSprite;
36         }
37 
38         public void OnPointerEnter(PointerEventData data)
39         {
40             if (containerImage == null)
41                 return;
42             Sprite dropSprite = GetDropSprite(data);
43             if (dropSprite != null)
44                 containerImage.color = highlightColor;
45         }
46 
47         public void OnPointerExit(PointerEventData data)
48         {
49             if (containerImage == null)
50                 return;
51             containerImage.color = normalColor;
52         }
53 
54         private Sprite GetDropSprite(PointerEventData data)
55         {
56             var originalObj = data.pointerDrag;
57             if (originalObj == null)
58                 return null;
59 
60             var srcImage = originalObj.GetComponent<Image>();
61             if (srcImage == null)
62                 return null;
63 
64             return srcImage.sprite;
65         }
66     }
67 }
View Code

在ScrollRect物体上添加吸附功能组件,工程里面要使用DoTween插件

 1 using System.Collections.Generic;
 2 using DG.Tweening;
 3 using UnityEngine;
 4 using UnityEngine.EventSystems;
 5 using UnityEngine.UI;
 6 
 7 //TODO:当前只试应横向的ScrollRect,还需要扩展支持纵向
 8 public class CFixGridRect : MonoBehaviour, IEndDragHandler
 9 {
10     public GameObject content;
11     public ScrollRect scorllRect;
12     public float itemWidth;
13     private RectTransform contentRectTf;
14 
15     private float formalPosX = 0;
16     private float currentPosX = 0;
17     private float halfItemLength = 0;
18 
19     void Start()
20     {
21         if (itemWidth <= 0)
22             UnityEngine.Debug.LogError("请设置Item的宽度");
23         halfItemLength = itemWidth / 2;
24         this.contentRectTf = this.content.GetComponent<RectTransform>();
25     }
26 
27     public void OnEndDrag(PointerEventData eventData)
28     {
29         this.scorllRect.StopMovement();
30         Vector2 afterDragPagePos = this.content.transform.localPosition;
31         currentPosX = afterDragPagePos.x; //当前拖动的位置  负
32         if (scorllRect.horizontalNormalizedPosition < 0 || scorllRect.horizontalNormalizedPosition > 1)
33             return;
34         int count = (int)(Mathf.Abs(currentPosX) / itemWidth);
35         var targetPos = -(float)(count * itemWidth);
36 
37         if (((float)(count * itemWidth + halfItemLength)) < Mathf.Abs(currentPosX))
38         {
39             targetPos = -(float)((count + 1) * itemWidth);
40         }
41         formalPosX = targetPos;
42         this.contentRectTf.DOLocalMoveX(targetPos, .2f);
43     }
44 }
View Code

具体DemoGit下载链接

欢迎加入U3D开发交流群:159875734


优化支持横竖屏的ScrollRect吸附功能

  1 using System.Collections.Generic;
  2 using DG.Tweening;
  3 using UnityEngine;
  4 using UnityEngine.EventSystems;
  5 using UnityEngine.UI;
  6 
  7 namespace Mga
  8 {
  9     public enum DragDirection
 10     {
 11         Horizontal,
 12         Vertical,
 13     }
 14 
 15     public class CFixGridRectBase : MonoBehaviour, IEndDragHandler
 16     {
 17         public class CUIContent
 18         {
 19             public GameObject ScrollRectContent;
 20             public ScrollRect m_ScorllRect;
 21             public float ItemSize;
 22             public float ItemSpaceLength; //间隙
 23             public float Margin = 0; //顶部边缘间隙
 24             public DragDirection m_DragDirection = DragDirection.Vertical;
 25         }
 26         private RectTransform contentRectTf;
 27         private float halfItemLength = 0;
 28         private CUIContent m_uiContent = null;
 29         private bool m_bWidgetReady = false;
 30         void Start()
 31         {
 32             m_bWidgetReady = true;
 33             _initContent();
 34         }
 35 
 36         public void InitContent(CUIContent uiContent)
 37         {
 38             m_uiContent = uiContent;
 39 
 40             if (m_bWidgetReady)
 41                 _initContent();
 42         }
 43 
 44         private void _initContent()
 45         {
 46             if (m_uiContent == null) return;
 47 
 48             if (m_uiContent.ItemSize <= 0)
 49             {
 50                 UnityEngine.Debug.LogError("请设置Item的宽度");
 51                 return;
 52             }
 53             halfItemLength = m_uiContent.ItemSize / 2;
 54             this.contentRectTf = m_uiContent.ScrollRectContent.GetComponent<RectTransform>();
 55         }
 56 
 57         public void OnEndDrag(PointerEventData eventData)
 58         {
 59             m_uiContent.m_ScorllRect.StopMovement();
 60             Vector2 afterDragPagePos = m_uiContent.ScrollRectContent.transform.localPosition;
 61             var itemLength = m_uiContent.ItemSize + m_uiContent.ItemSpaceLength;
 62             if (m_uiContent.m_DragDirection == DragDirection.Horizontal)
 63             {
 64                 var currentPosX = afterDragPagePos.x; //当前拖动的位置  负
 65                 currentPosX -= m_uiContent.Margin;
 66                 int count = (int)(Mathf.Abs(currentPosX) / m_uiContent.ItemSize);
 67                 if (m_uiContent.m_ScorllRect.horizontalNormalizedPosition <= 0)
 68                 {
 69                     return;
 70                 }
 71                 else if (m_uiContent.m_ScorllRect.horizontalNormalizedPosition >= 1)  //总数-当前显示的数量
 72                 {
 73                     return;
 74                 }
 75 
 76                 var targetPosX = -(float)(count * itemLength);
 77                 if (((float)(targetPosX + halfItemLength)) < Mathf.Abs(currentPosX))
 78                 {
 79                     count++;
 80                     targetPosX = -(float)(count * itemLength);
 81                 }
 82                 this.contentRectTf.DOLocalMoveX(targetPosX, .2f);
 83             }
 84             else
 85             {
 86                 var currentPosY = afterDragPagePos.y; //当前拖动的位置  正
 87                 currentPosY -= m_uiContent.Margin;
 88                 int count = (int)(Mathf.Abs(currentPosY) / itemLength);
 89                 if (m_uiContent.m_ScorllRect.verticalNormalizedPosition <= 0)
 90                 {
 91                     return;
 92                 }
 93                 else if (m_uiContent.m_ScorllRect.verticalNormalizedPosition >= 1)  //总数-当前显示的数量
 94                 {
 95                     return;
 96                 }
 97 
 98                 var targetPosY = (float)(count * itemLength);
 99                 if (((float)(targetPosY + halfItemLength)) < Mathf.Abs(currentPosY))
100                 {
101                     count++;
102                     targetPosY = (float)(count * itemLength);
103                 }
104                 this.contentRectTf.DOLocalMoveY(targetPosY, .2f);
105             }
106         }
107     }
108 }
View Code
 

补充

如果代码创建AnimationCurve默认是曲线,如果想要直线效果,可以在面板里面设置,也可以代码设置,如果代码设置如下:

1 var curve2 = new AnimationCurve();
2 var key1 = new Keyframe(0, 0);
3 key1.outTangent = 1;
4 var key2 = new Keyframe(1, 1);
5 key2.inTangent = 1;
6 curve2.AddKey(key1);
7 curve2.AddKey(key2);
8 curve2.postWrapMode = WrapMode.Loop;
9 curve2.preWrapMode = WrapMode.Loop;

这样的话就是直线了。

posted @ 2017-09-13 18:50  蓬莱仙羽  阅读(6294)  评论(1编辑  收藏  举报