[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 }
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 }
- 有遮罩无卡顿加载
思路:协程加载,先加载屏幕显示的数量,然后返回一帧在继续加载,防止出现数量太大卡顿的现象。
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 }
- 支持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 }
如果想要实现拖拽到目标位置的检测,还要在目标位置放一个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 }
在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 }
具体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 }
补充
如果代码创建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;
这样的话就是直线了。
感谢来访,共同学习!