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


前言

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

效果图

  • 缩放滑动效果 
    [Unity UGUI]ScrollRect效果大全

  • 缩放循环展示卡牌效果

[Unity UGUI]ScrollRect效果大全

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

[Unity UGUI]ScrollRect效果大全

  • 大量数据循固定Item复用 
    [Unity UGUI]ScrollRect效果大全

  • 无限无遮罩动态加载

[Unity UGUI]ScrollRect效果大全

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

[Unity UGUI]ScrollRect效果大全

部分核心代码

  • 有遮罩无卡顿加载 
    思路:并没有使用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

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2021-10-10
  • 2021-10-04
  • 2021-12-25
  • 2021-10-05
  • 2021-07-09
  • 2022-12-23
猜你喜欢
  • 2021-11-14
  • 2022-12-23
  • 2022-12-23
  • 2021-08-11
  • 2021-07-07
  • 2021-11-03
  • 2021-12-21
相关资源
相似解决方案