zoukankan      html  css  js  c++  java
  • [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;

    这样的话就是直线了。

  • 相关阅读:
    python网络编程--线程GIL(全局解释器锁)
    python网络编程--进程线程
    html之块级标签h系列,div
    html之head,base,meta,title
    可视化SNV安装
    MySQLdb模块的安装
    python之os模块
    python之时间函数
    python之路之正则表达式
    python之路 之open
  • 原文地址:https://www.cnblogs.com/dingxiaowei/p/7516724.html
Copyright © 2011-2022 走看看