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;
這樣的話就是直線了。
