UGUI ScrollViewの自動無限スクロールについては、クリックスクロールとドラッグスクロールの組み合わせ

92542 ワード

ここではメモとしてダイレクトアップコードを使用します(イベントがまとめられています)
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using DG.Tweening;
using System.Collections.Generic;
using UnityEngine.Analytics;

[RequireComponent(typeof(GridLayoutGroup))]
[RequireComponent(typeof(ContentSizeFitter))]
public class SuperScrollView : MonoBehaviour
{

    [SerializeField]
    int minAmount = 0;//      ,      child  。       +      ,           2  ,    2  。      2 *2  + 1  * 2  = 6 。

    RectTransform rectTransform;

    GridLayoutGroup gridLayoutGroup;
    ContentSizeFitter contentSizeFitter;

    ScrollRect scrollRect;

    RectTransform lockPos;

    List<RectTransform> children = new List<RectTransform>();

    Vector2 startPosition;

    int amount = 0;
    float itemHeight = 0;
    float itemSpacing = 2;

    public delegate void UpdateChildrenCallbackDelegate(int index, Transform trans);
    public UpdateChildrenCallbackDelegate updateChildrenCallback = null;

    int realIndex = -1;
    int realIndexUp = -1; //    ;

    bool hasInit = false;
    Vector2 gridLayoutSize;
    Vector2 gridLayoutPos;
    Dictionary<Transform, Vector2> childsAnchoredPosition = new Dictionary<Transform, Vector2>();
    Dictionary<Transform, int> childsSiblingIndex = new Dictionary<Transform, int>();

    #region           
    /// 
    ///                
    /// 
    bool isSlide = false;
    bool isInitEnd = false;
    bool isDragging = false;

    /// 
    ///        
    /// 
    float targethorizontal = 0;

    /// 
    ///     
    /// 
    //float smooting = 0.3f;

    /// 
    ///           (   )
    /// 
    float timeInterval = 3f;

    /// 
    ///       (   )
    /// 
    //float executionTime = 2f;

    /// 
    ///     
    /// 
    float currentTime = 0;

    /// 
    ///       
    /// 
    //float currentExecutionTime = 0;

    #endregion

    // Use this for initialization
    void Start()
    {
        //StartCoroutine(InitChildren());
    }

    IEnumerator InitChildren()
    {
        yield return 0;

        if (!hasInit)
        {
            //  Grid   ;
            rectTransform = GetComponent<RectTransform>();
            gridLayoutGroup = GetComponent<GridLayoutGroup>();
            gridLayoutGroup.enabled = false;
            contentSizeFitter = GetComponent<ContentSizeFitter>();
            contentSizeFitter.enabled = false;

            gridLayoutPos = rectTransform.anchoredPosition;
            gridLayoutSize = rectTransform.sizeDelta;


            //  ScrollRect    ;
            scrollRect = transform.parent.parent.GetComponent<ScrollRect>();
            scrollRect.onValueChanged.AddListener((data) => { ScrollCallback(data); });

            //       
            lockPos = transform.parent.Find("CenterPoint").GetComponent<RectTransform>();

            //    child anchoredPosition    SiblingIndex;
            for (int index = 0; index < transform.childCount; index++)
            {
                Transform child = transform.GetChild(index);
                RectTransform childRectTrans = child.GetComponent<RectTransform>();
                childsAnchoredPosition.Add(child, childRectTrans.anchoredPosition);

                childsSiblingIndex.Add(child, child.GetSiblingIndex());
            }
        }
        else
        {
            rectTransform.anchoredPosition = gridLayoutPos;
            rectTransform.sizeDelta = gridLayoutSize;

            children.Clear();

            realIndex = -1;
            realIndexUp = -1;

            //children        ;
            foreach (var info in childsSiblingIndex)
            {
                info.Key.SetSiblingIndex(info.Value);
            }

            //children    anchoredPosition;
            for (int index = 0; index < transform.childCount; index++)
            {
                Transform child = transform.GetChild(index);

                RectTransform childRectTrans = child.GetComponent<RectTransform>();
                if (childsAnchoredPosition.ContainsKey(child))
                {
                    childRectTrans.anchoredPosition = childsAnchoredPosition[child];
                }
                else
                {
                    Debug.LogError("childsAnchoredPosition no contain " + child.name);
                }
            }
        }



        //    child;
        for (int index = 0; index < transform.childCount; index++)
        {
            Transform trans = transform.GetChild(index);
            trans.gameObject.SetActive(true);

            children.Add(transform.GetChild(index).GetComponent<RectTransform>());

            //       ;
            UpdateChildrenCallback(children.Count - 1, transform.GetChild(index));
        }

        startPosition = rectTransform.anchoredPosition;

        realIndex = children.Count - 1;

        hasInit = true;

        //                ;
        for (int index = 0; index < minAmount; index++)
        {
            children[index].gameObject.SetActive(index < amount);
        }

        if (gridLayoutGroup.constraint == GridLayoutGroup.Constraint.FixedColumnCount)
        {
            //      ,    GridLayout          ;
            int row = (minAmount - amount) / gridLayoutGroup.constraintCount;
            if (row > 0)
            {
                rectTransform.sizeDelta -= new Vector2(0, (gridLayoutGroup.cellSize.y + gridLayoutGroup.spacing.y) * row);
            }
        }
        else
        {
            //      ,    GridLayout          ;
            int column = (minAmount - amount) / gridLayoutGroup.constraintCount;
            if (column > 0)
            {
                rectTransform.sizeDelta -= new Vector2((gridLayoutGroup.cellSize.x + gridLayoutGroup.spacing.x) * column, 0);
            }
        }

        pos = new Vector2(rectTransform.anchoredPosition.x, rectTransform.anchoredPosition.y + 160f);

        isInitEnd = true;
        isSlide = true;
        Init();
        OnClickItemInit();
        
    }

    Vector2 pos;
    // Update is called once per frame
    void Update()
    {
        if (isInitEnd)
        {
            if (isSlide && !isStartMove && !isDragging && !isMove)
            {
                currentTime += Time.deltaTime;
                if (timeInterval + Mathf.Epsilon <= currentTime)
                {
                    //Debug.Log("currentTime  :" + currentTime);
                    //currentExecutionTime += Time.deltaTime;
                    if (pos.y - m_Content.anchoredPosition.y < 0.6f/*executionTime + Mathf.Epsilon <= currentExecutionTime*/)
                    {
                        pos = new Vector2(m_Content.anchoredPosition.x, m_Content.anchoredPosition.y + itemHeight /*160*/);
                        currentTime = 0;
                        //currentExecutionTime = 0;
                    }
                    //Debug.Log("currentExecutionTime  :" + currentExecutionTime);
                    //Debug.Log("Y  scrollRect.verticalNormalizedPosition:" + scrollRect.verticalNormalizedPosition);
                    //scrollRect.verticalNormalizedPosition = Mathf.Lerp(scrollRect.verticalNormalizedPosition, targethorizontal, Time.deltaTime * smooting);
                    m_Content.anchoredPosition = Vector2.Lerp(m_Content.anchoredPosition, pos, Time.deltaTime * speedSlide/*smooting*/);
                }
            }
            ItemOnClickMoveUpdate();
            centerUpdate();
        }
    }


    void ScrollCallback(Vector2 data)
    {
        UpdateChildren();
    }

    /// 
    ///         
    /// 
    void UpdateChildren()
    {
        if (transform.childCount < minAmount)
        {
            return;
        }

        Vector2 currentPos = rectTransform.anchoredPosition;//    UI     

        if (gridLayoutGroup.constraint == GridLayoutGroup.Constraint.FixedColumnCount)
        {
            float offsetY = currentPos.y - startPosition.y;

            if (offsetY > 0)
            {
                //   ,    ;
                {
                    if (realIndex >= amount - 1)
                    {
                        startPosition = currentPos;
                        return;
                    }

                    float scrollRectUp = lockPos.transform.TransformPoint(Vector3.zero).y;//scrollRect.transform.TransformPoint(Vector3.zero).y;

                    Vector3 childBottomLeft = new Vector3(children[0].anchoredPosition.x, children[0].anchoredPosition.y - gridLayoutGroup.cellSize.y, 0f);//                
                    float childBottom = transform.TransformPoint(childBottomLeft).y;

                    if (childBottom >= scrollRectUp)
                    {
                        //Debug.Log("childBottom >= scrollRectUp");

                        //     ;
                        for (int index = 0; index < gridLayoutGroup.constraintCount; index++)
                        {
                            children[index].SetAsLastSibling();//    UI    

                            children[index].anchoredPosition = new Vector2(children[index].anchoredPosition.x, children[children.Count - 1].anchoredPosition.y - gridLayoutGroup.cellSize.y - gridLayoutGroup.spacing.y);

                            realIndex++;

                            if (realIndex > amount - 1)
                            {
                                children[index].gameObject.SetActive(false);
                            }
                            else
                            {
                                UpdateChildrenCallback(realIndex, children[index]);
                            }
                        }

                        //GridLayoutGroup     ;
                        rectTransform.sizeDelta += new Vector2(0, gridLayoutGroup.cellSize.y + gridLayoutGroup.spacing.y);

                        //  child;
                        for (int index = 0; index < children.Count; index++)
                        {
                            children[index] = transform.GetChild(index).GetComponent<RectTransform>();
                        }
                    }
                }
            }
            else
            {
                //Debug.Log("Drag Down");
                //   ,    ;
                if (realIndex + 1 <= children.Count)
                {
                    startPosition = currentPos;
                    return;
                }

                RectTransform scrollRectTransform = scrollRect.GetComponent<RectTransform>();
                Vector3 scrollRectAnchorBottom = new Vector3(0, -scrollRectTransform.rect.height - gridLayoutGroup.spacing.y, 0f);
                float scrollRectBottom = scrollRect.transform.TransformPoint(scrollRectAnchorBottom).y;

                Vector3 childUpLeft = new Vector3(children[children.Count - 1].anchoredPosition.x, children[children.Count - 1].anchoredPosition.y, 0f);

                float childUp = transform.TransformPoint(childUpLeft).y;

                if (childUp < scrollRectBottom)
                {
                    //Debug.Log("childUp < scrollRectBottom");

                    //            
                    for (int index = 0; index < gridLayoutGroup.constraintCount; index++)
                    {
                        children[children.Count - 1 - index].SetAsFirstSibling();

                        children[children.Count - 1 - index].anchoredPosition = new Vector2(children[children.Count - 1 - index].anchoredPosition.x, children[0].anchoredPosition.y + gridLayoutGroup.cellSize.y + gridLayoutGroup.spacing.y);

                        children[children.Count - 1 - index].gameObject.SetActive(true);

                        UpdateChildrenCallback(realIndex - children.Count - index, children[children.Count - 1 - index]);
                    }

                    realIndex -= gridLayoutGroup.constraintCount;

                    //GridLayoutGroup     ;
                    rectTransform.sizeDelta -= new Vector2(0, gridLayoutGroup.cellSize.y + gridLayoutGroup.spacing.y);

                    //  child;
                    for (int index = 0; index < children.Count; index++)
                    {
                        children[index] = transform.GetChild(index).GetComponent<RectTransform>();
                    }
                }
            }
        }
        startPosition = currentPos;
        //targethorizontal = currentPos.y;
    }

    void UpdateChildrenCallback(int index, Transform trans)
    {
        if (updateChildrenCallback != null)
        {
            updateChildrenCallback(index, trans);
        }
    }


   /// 
   ///           
   /// 
   ///      
   ///        
    public void SetAmount(float height,float spacing = 2f)
    {
        amount = int.MaxValue;
        itemHeight = height;
        itemSpacing = spacing;
        StartCoroutine(InitChildren());
    }

    public void DragStart()
    {
        isSlide = false;
        isDragging = true;
        isMove = true;
        Debug.Log("      :" + isSlide);
    }

    public void DragEnd()
    {
        isSlide = true;
        isDragging = false;
        newPos = new Vector2(m_Content.anchoredPosition.x, children[minEleNum].anchoredPosition.y-m_CenterPoint.anchoredPosition.y - 2);
        Debug.Log("      :" + isSlide);
    }



    #region         
    private RectTransform centerPoint;
    private Vector2 newPos;

    /// 
    ///         
    /// 
    private int distanceBetweenEles;

    /// 
    ///           
    /// 
    private float[] distanceToCenter;

    /// 
    ///          
    /// 
    private int minEleNum;
    private bool isMove = false;

    private void Init()
    {
        int elelength = children.Count;
        centerPoint = lockPos;
        distanceToCenter = new float[elelength];
       
        //        
        distanceBetweenEles = (int)Mathf.Abs(children[1].anchoredPosition.y - children[0].anchoredPosition.y);
    }

    /// 
    ///       
    /// 
    private void centerUpdate()
    {
        //if (isSlide) return;
        if (isDragging)
        {
            if (Vector2.Distance(rectTransform.anchoredPosition, newPos) > 5f)
            {
                for (int i = 0; i < children.Count; i++)
                {
                    //             
                    distanceToCenter[i] = Mathf.Abs(centerPoint.transform.position.y - children[i].transform.position.y);
                    Debug.Log(" "+ i + "          :" + distanceToCenter[i]);
                }

                //      
                float minDist = Mathf.Min(distanceToCenter);

                for (int i = 0; i < children.Count; i++)
                {
                    //           
                    if (minDist == distanceToCenter[i])
                    {
                        minEleNum = i;
                        break;
                    }
                }
            }
        }

        if (!isDragging)
        {
            if (isMove)
            {
                //      ,      
                if (newPos.y - m_Content.anchoredPosition.y < 0.6f)
                {
                    isMove = false;
                }
                rectTransform.anchoredPosition = Vector2.Lerp(m_Content.anchoredPosition, newPos, Time.deltaTime * 5f);
            }
            //newPos = new Vector2(m_Content.anchoredPosition.x, minEleNum * -distanceBetweenEles);
        }
    }
    #endregion


    #region       
    List<RectTransform> currentRectTList = new List<RectTransform>();
    List<Button> currentButtonList = new List<Button>();
    ScrollRect currentScrollRect;
    RectTransform m_Content;
    RectTransform m_CenterPoint;
    bool isStartMove = false;
    float offsetY = 0;
    Vector2 tagetPos;
    float speedSlide = 2f;


    void OnClickItemInit()
    {
        currentScrollRect = scrollRect;
        m_Content = currentScrollRect.content;
        m_CenterPoint = lockPos;
        foreach (RectTransform itemButton in m_Content)
        {
            currentRectTList.Add(itemButton);
        }
        Debug.Log("Content       :" + currentRectTList.Count);

        for (int i = 0; i < currentRectTList.Count; i++)
        {
            int index = i;
            currentButtonList.Add(currentRectTList[i].GetComponent<Button>());
            currentButtonList[i].onClick.AddListener(delegate { OnClickMoveContent(currentRectTList[index]); });

        }
    }

    /// 
    /// Update           
    /// 
    void ItemOnClickMoveUpdate()
    {
        if (isStartMove && !isMove)
        {
            if (offsetY - m_Content.anchoredPosition.y < 0.6f /*Mathf.Epsilon + m_Content.anchoredPosition.y == offsetY*/)
            {
                isStartMove = false;
                Debug.Log("   ContentY     :" + m_Content.anchoredPosition.y);
                for (int i = 0; i < currentButtonList.Count; i++)
                {
                    int index = i;
                    currentButtonList[i].onClick.AddListener(delegate { OnClickMoveContent(currentRectTList[index]); });
                }
            }
            m_Content.anchoredPosition = Vector2.Lerp(m_Content.anchoredPosition, tagetPos, Time.deltaTime * speedSlide);
            Debug.Log("   ContentY     :" + m_Content.anchoredPosition.y);
            Debug.Log("   offsetY:" + offsetY);
        }
    }

    /// 
    ///       
    /// 
    void OnClickMoveContent(RectTransform currentR)
    {
        Debug.Log("currentR   :" + currentR.anchoredPosition);
        //float temp = m_Content.anchoredPosition.y;
        offsetY = Mathf.Abs(currentR.anchoredPosition.y - m_CenterPoint.anchoredPosition.y - itemSpacing);
        //offsetY = temp + offsetY;
        tagetPos = new Vector2(m_Content.anchoredPosition.x, offsetY);
        Debug.Log("       :" + offsetY);
        isStartMove = true;
    }
    #endregion
}

ScrollView Content

superScrollView.SetAmount(160f,2f);

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TestSuperScrollView : MonoBehaviour
{
    SuperScrollView superScrollView;
    int amount = 500;
    private void Start()
    {
        //       
        superScrollView = transform.Find("Viewport/Content").GetComponent<SuperScrollView>();
        superScrollView.SetAmount(160f,2f);
        //superScrollView.updateChildrenCallback = UpdateChildrenCallback;
    }

    void UpdateChildrenCallback(int index, Transform trans)
    {
        Debug.Log("UpdateChildrenCallback: index=" + index + " name:" + trans.name);

        Text text = trans.Find("Text").GetComponent<Text>();
        text.text = index.ToString();
    }
}