zoukankan      html  css  js  c++  java
  • UGUI ScrollRect滑动居中CenterOnChild实现

    NGUI有一个UICenterOnChild脚本,可以轻松实现ScrollView中拖动子物体后保持一个子物体位于中心位置。然而UGUI就没这么方便了,官方并没有类似功能的脚本。网上找到一些运行效果都不对,可能因为UGUI需要配置的东西太多,RectTransfrom不同设置效果就不一样。故自己实现了该功能,使用时的配置如下:

    1. 仅适用于水平方向拖动的ScrollRect。
    2. ScrollRect中的Grid必须使用GridLayoutGroup。
    3. 由于需要知道ScrollRect的宽度以便计算中心位置,故ScrollRect的Anchors的四个小三角中的上面或者下面的一对角不得分离,不然宽度计算出错,即需要:Anchors.Min.x == Anchors.Max.x。最好四角合一。
    4. 由于是通过设置ScrollRect's content的localPosition实现,故需要将ScrollRect的中心点Pivot与content的中心点均置于自身最左边(0, 0.5)。
    5. 由于第一个与最后一个子物体需要停留在中间,故ScrollRect的Movement Type需要设置为Unrestricted。该项会在运行时自动设置。

    代码如下:

      1     /// <summary>
      2     /// 
      3     /// 拖动ScrollRect结束时始终让一个子物体位于中心位置。
      4     /// 
      5     /// </summary>
      6     public class CenterOnChild : MonoBehaviour, IEndDragHandler, IDragHandler
      7     {
      8         //将子物体拉到中心位置时的速度
      9         public float centerSpeed = 9f;
     10 
     11         //注册该事件获取当拖动结束时位于中心位置的子物体
     12         public delegate void OnCenterHandler (GameObject centerChild);
     13         public event OnCenterHandler onCenter;
     14 
     15         private ScrollRect _scrollView;
     16         private Transform _container;
     17 
     18         private List<float> _childrenPos = new List<float> ();
     19         private float _targetPos;
     20         private bool _centering = false;
     21 
     22         void Awake ()
     23         {
     24             _scrollView = GetComponent<ScrollRect> ();
     25             if (_scrollView == null)
     26             {
     27                 Debug.LogError ("CenterOnChild: No ScrollRect");
     28                 return;
     29             }
     30             _container = _scrollView.content;
     31 
     32             GridLayoutGroup grid;
     33             grid = _container.GetComponent<GridLayoutGroup> ();
     34             if (grid == null)
     35             {
     36                 Debug.LogError ("CenterOnChild: No GridLayoutGroup on the ScrollRect's content");
     37                 return;
     38             }
     39 
     40             _scrollView.movementType = ScrollRect.MovementType.Unrestricted;
     41 
     42             //计算第一个子物体位于中心时的位置
     43             float childPosX = _scrollView.GetComponent<RectTransform> ().rect.width * 0.5f - grid.cellSize.x * 0.5f;
     44             _childrenPos.Add (childPosX);
     45             //缓存所有子物体位于中心时的位置
     46             for (int i = 0; i < _container.childCount - 1; i++)
     47             {
     48                 childPosX -= grid.cellSize.x + grid.spacing.x;
     49                 _childrenPos.Add (childPosX);
     50             }
     51         }
     52 
     53         void Update ()
     54         {
     55             if (_centering)
     56             {
     57                 Vector3 v = _container.localPosition;
     58                 v.x = Mathf.Lerp (_container.localPosition.x, _targetPos, centerSpeed * Time.deltaTime);
     59                 _container.localPosition = v;
     60                 if (Mathf.Abs (_container.localPosition.x - _targetPos) < 0.01f)
     61                 {
     62                     _centering = false;
     63                 }
     64             }
     65         }
     66 
     67         public void OnEndDrag (PointerEventData eventData)
     68         {
     69             _centering = true;
     70             _targetPos = FindClosestPos (_container.localPosition.x);
     71         }
     72 
     73         public void OnDrag (PointerEventData eventData)
     74         {
     75             _centering = false;
     76         }
     77 
     78         private float FindClosestPos (float currentPos)
     79         {
     80             int childIndex = 0;
     81             float closest = 0;
     82             float distance = Mathf.Infinity;
     83 
     84             for (int i = 0; i < _childrenPos.Count; i++)
     85             {
     86                 float p = _childrenPos[i];
     87                 float d = Mathf.Abs (p - currentPos);
     88                 if (d < distance)
     89                 {
     90                     distance = d;
     91                     closest = p;
     92                     childIndex = i;
     93                 }
     94             }
     95 
     96             GameObject centerChild = _container.GetChild (childIndex).gameObject;
     97             if (onCenter != null)
     98                 onCenter (centerChild);
     99 
    100             return closest;
    101         }
    102     }

    由于已缓存所有子物体的位置信息,故该代码简单修改可以扩展功能,如增加到上一项、到下一项、跳转到指定项等功能。

  • 相关阅读:
    [CF707D]Persistent Bookcase_主席树_bitset
    [CF798D]Mike and distribution_贪心
    [LuoguP2164][SHOI2007]交通网络_拓扑排序_概率期望
    [LuoguP3064][USACO12DEC]伊斯坦布尔的帮派Gangs of Istanbull(加强版)_线段树_贪心
    [CF306C]White, Black and White Again_排列组合
    [LuoguP2167][SDOI2009]Bill的挑战_容斥原理/状压dp
    [LuoguP2163][SHOI2007]园丁的烦恼_CDQ分治
    正则字符串插入字符
    [react]
    react 预览pdf 转换
  • 原文地址:https://www.cnblogs.com/suoluo/p/5535420.html
Copyright © 2011-2022 走看看