木骰

UGUI:循环滚动框 可设置排列方向

以前写的一个UGUI下的循环滚动框,前段时间用的时候发现不能支持scrollview从下往上滑的模式,于是就做了修改,加上从下往上和从右往左。

通过设置StartConner枚举值设定滑动方式。

除了滑动方式的修改,还修改了根据item的pivot设定来计算排列坐标,以前的item pivot只能设定为0.5 0.5,现在怎么设都可以了。

2017/09/03 做了一些修改。
获取ScrollRect的四角坐标由RectTransform.rect.size的计算改为GetWorldConrners
在ResetChildPosition的时候 先将Grid的尺寸设为0
在RefreshChildData的时候 将Grid的尺寸更新到最大尺寸


public class GridAndLoop : MonoBehaviour
{
    /// 
    /// 设置Item内容的委托
    /// 
    ///  Item对象
    ///  Item在Grid中的序号 
    ///  当前Item在List中的序号 
    public delegate void OnInitializeItem(GameObject item, int wrapIndex, int realIndex);
    /// 
    /// 排列方式枚举
    /// 
    public enum ArrangeType
    {
        Horizontal = 0, //水平排列
        Vertical = 1, //垂直排列
    }
    public enum StartConner
    {
        UpLeft,
        UpRight,
        LowLeft,
        LowRight,
    }
    /// 
    /// Item的尺寸
    /// 
    public int cell_x = 100, cell_y = 100;
    /// 
    /// 是否隐藏裁剪部分
    /// 
    public bool cullContent = true;
    /// 
    /// Item最小序号
    /// 
    public int minIndex = 0;
    /// 
    /// Item最大序号
    /// 
    public int maxIndex = 0;
    /// 
    /// 排列方式
    /// 
    public ArrangeType arrangeType = ArrangeType.Horizontal;
    public StartConner startConner = StartConner.UpLeft;
    /// 
    /// 行列个数 0表示1列
    /// 
    public int ConstraintCount = 0;
    /// 
    /// 设置Item的委托
    /// 
    public OnInitializeItem onInitializeItem;
    /// 
    ///当前对象
    /// 
    Transform mTrans;
    /// 
    /// 当前RectTransform对象
    /// 
    RectTransform mRTrans;
    /// 
    /// ScrollRect
    /// 
    ScrollRect mScroll;
    /// 
    /// 滚动方向
    /// 
    bool mHorizontal;
    Vector2 mDirect = Vector2.one;
    /// 
    /// 元素链表
    /// 
    List mChild = new List();
    /// 
    /// 显示区域长度或高度的一半
    /// 
    float extents = 0;
    Vector2 SR_size = Vector2.zero;//SrollRect的尺寸
    Vector3[] conners = new Vector3[4];//ScrollRect四角的世界坐标  
    Vector2 startPos; //ScrollRect的初始位置
    bool isStart = false;
    void Start()
    {
        if (isStart) return;
        isStart = true;
        InitList();
    }
    int sortByName(Transform a, Transform b) { return string.Compare(a.name, b.name); }
    /// 
    /// 初始化mChild链表
    /// 
    void InitList()
    {
        int i, ChildCount;
        InitValue();
        mChild.Clear();
        for (i = 0, ChildCount = mTrans.childCount; i < ChildCount; i++)
            mChild.Add(mTrans.GetChild(i));
        ResetChildPosition();
        //     mChild.Sort(sortByName);//按照Item名字排序  
    }
    void InitValue()
    {
        if (ConstraintCount <= 0)
            ConstraintCount = 1;
        if (minIndex > maxIndex) minIndex = maxIndex;
        mTrans = transform;
        mRTrans = transform.GetComponent();
        mScroll = transform.GetComponentInParent();
        mHorizontal = mScroll.horizontal;
        SR_size = transform.parent.GetComponent().rect.size;
        (mScroll.transform as RectTransform).GetWorldCorners(conners);
        if (startConner == StartConner.UpLeft)
        {
            mRTrans.pivot = new Vector2(0, 1);//设置grid的中心在左上角 为了适配尺寸用
            mDirect.x = 1;  //初始化排列方向 x轴正方向 y轴负方向  即 向左和向下 用来算realIndex和排列坐标用
            mDirect.y = -1;
        }
        else if (startConner == StartConner.UpRight)
        {
            mRTrans.pivot = new Vector2(1, 0);
            mDirect.x = -1;
            mDirect.y = -1;
        }
        else if (startConner == StartConner.LowLeft)
        {
            mRTrans.pivot = new Vector2(0, 0);
            mDirect.x = 1;
            mDirect.y = 1;
        }
        else if (startConner == StartConner.LowRight)
        {
            mRTrans.pivot = new Vector2(1, 0);
            mDirect.x = -1;
            mDirect.y = 1;
        }
        mScroll.onValueChanged.AddListener(delegate { WrapContent(); });//添加滚动事件回调
        startPos = mTrans.localPosition;
    }
    //初始化各Item的坐标
    [ContextMenu("RePosition")]
    public virtual void RePosition()
    {
        if (!isStart) Start();
        InitList();
    }
    void Update()
    {
        if (Application.isPlaying) enabled = false;
        //      RePosition();
    }
    void ResetChildPosition()
    {
        int rows = 1, cols = 1;
        int i;
        int imax = mChild.Count;//Item元素数量
        //初始化行列数
        if (arrangeType == ArrangeType.Vertical) //垂直排列 则适应行数
        {
            rows = ConstraintCount;
            cols = (int)Mathf.Ceil((float)imax / (float)rows);
            extents = (float)(cols * cell_x) * 0.5f;
        }
        else if (arrangeType == ArrangeType.Horizontal) //水平排列则适应列数
        {
            cols = ConstraintCount;
            rows = (int)Mathf.Ceil((float)imax / (float)cols);
            extents = (float)(rows * cell_y) * 0.5f;
        }
        mRTrans.sizeDelta = Vector2.zero;
        for (i = 0; i < imax; i++)
        {
            RectTransform temp = mChild[i] as RectTransform;
            if (startConner == StartConner.UpLeft)
            {
                temp.anchorMin = new Vector2(0, 1);
                temp.anchorMax = new Vector2(0, 1);
            }
            else if (startConner == StartConner.UpRight)
            {
                temp.anchorMin = Vector2.one;
                temp.anchorMax = Vector2.one;
            }
            else if (startConner == StartConner.LowLeft)
            {
                temp.anchorMin = Vector2.zero;
                temp.anchorMax = Vector2.zero;
            }
            else if (startConner == StartConner.LowRight)
            {
                temp.anchorMin = new Vector2(1, 0);
                temp.anchorMax = new Vector2(1, 0);
            }
            Vector2 startAxis = new Vector2(cell_x * temp.pivot.x * mDirect.x, cell_y * temp.pivot.y * mDirect.y);//起始位置
            int x = 0, y = 0;//行列号
            if (arrangeType == ArrangeType.Horizontal) { x = i / cols; y = i % cols; }
            else if (arrangeType == ArrangeType.Vertical) { x = i % rows; y = i / rows; }
            temp.localPosition = new Vector2(startAxis.x + y * cell_x * mDirect.x, startAxis.y + x * cell_y * mDirect.y);
            if ((minIndex == maxIndex && maxIndex != 0 ) || (i >= minIndex && i < maxIndex))
            {
                //       cullContent = true;
                temp.gameObject.SetActive(true);
                UpdateRectsize(temp.localPosition, (temp as RectTransform).pivot);//更新panel的尺寸
                UpdateItem(temp, i, i);
            }
            else
            {
                temp.gameObject.SetActive(false);
                //cullContent = temp.gameObject.activeSelf;//如果预制Item数超过maxIndex则将超过部分隐藏 并 设置cullCintent为ufalse 并且不再更新 panel尺寸
            }
        }
    }
    /// 
    /// ScrollRect复位
    /// 
    public void ResetPosition()
    {
        if (!isStart) Start();
        mTrans.localPosition = startPos;
        ResetChildPosition();
    }
    public void SetMinMaxIndex(int min, int max)
    {
        if (!isStart) Start();
        minIndex = min;
        maxIndex = max;
    }
    /// 
    /// 刷新Item数据
    /// 
    public void RefreshChildData()
    {
        if (!isStart) Start();
        for (int i = 0, imax = mChild.Count; i < imax; ++i)
        {
            Transform t = mChild[i];
            int realIndex = getRealIndex(t.localPosition);
            if ((minIndex == maxIndex && maxIndex != 0) || (realIndex >= minIndex && realIndex < maxIndex))
            {
                t.gameObject.SetActive(true);
                UpdateItem(t, i, realIndex);
            }
            else
            {
                t.gameObject.SetActive(false);
            }
        }
        UpdateRectsizeToMax();
    }
    /// 
    /// 获取一个真实序号对应的locl坐标
    /// 
    /// 
    /// 
    public Vector3 getRealShouldPos(int realIndex)
    {
        if (!isStart) Start();
        if (mChild.Count == 0)
        {
            RectTransform recttrans = mChild[0] as RectTransform;
            return Vector3.zero + new Vector3(recttrans.pivot.x * cell_x, recttrans.pivot.y * cell_y, 0);
        }
        Vector3 pos = mChild[0].localPosition;
        int realIndex0 = getRealIndex(pos);
        if (mHorizontal)
        {
            pos.x = pos.x + (realIndex - realIndex0) * cell_x * mDirect.x;
        }
        else
        {
            pos.y = pos.y + (realIndex - realIndex0) * cell_y * mDirect.y;
        }
        return pos;
    }
    /// 
    /// 根据真实序号获取对应的序号
    /// 
    /// 
    /// 
    public int getIndexWithRealIndex(int realIndex)
    {
        if (!isStart) Start();
        int index = realIndex % mChild.Count;
        return index;
    }
    /// 
    /// 根据一个真实序号调整当前所有Item的坐标
    /// 
    /// 
    public void WrapChildPosWithRealIndex(int realIndex)
    {
        if (!isStart) Start();
        int index = getIndexWithRealIndex(realIndex);
        Vector3 targetPos = getRealShouldPos(realIndex);
        Vector3 offset = targetPos - mChild[index].localPosition;
        for (int i = 0, Imax = mChild.Count; i < Imax; i++)
        {
            Vector3 pos = mChild[i].localPosition;
            pos += offset;
            mChild[i].localPosition = pos;
        }
        WrapContent();
        RefreshChildData();
    }
    /// 
    /// 更新panel的尺寸
    /// 
    ///   
    void UpdateRectsize(Vector2 pos, Vector2 pivot)
    {
        if (arrangeType == ArrangeType.Vertical)
        {
            float offset = mDirect.x * pos.x;
            if (offset < 0) return;
            Vector2 size = Vector2.zero;
            size.x = offset + cell_x * pivot.x;
            size.y = ConstraintCount * cell_y;
            mRTrans.sizeDelta = size;
        }
        else
        {
            float offset = mDirect.y * pos.y;
            if (offset < 0) return;
            Vector2 size = Vector2.zero;
            size.x = ConstraintCount * cell_x;
            size.y = offset + cell_y * pivot.y;
            mRTrans.sizeDelta = size;
        }
    }
    /// 
    /// 更新panel尺寸为最大尺寸
    /// 
    void UpdateRectsizeToMax()
    {
        if (arrangeType == ArrangeType.Vertical)
        {
            Vector2 size = Vector2.zero;
            size.x = cell_x * maxIndex;
            size.y = ConstraintCount * cell_y;
            mRTrans.sizeDelta = size;
        }
        else
        {
            Vector2 size = Vector2.zero;
            size.x = ConstraintCount * cell_x;
            size.y = cell_y * maxIndex;
            mRTrans.sizeDelta = size;
        }
    }
    //Vector2 calculatePos(Vector2 world,Vector2 target,Vector2 lcal)
    //{
    //    Vector2 temp = world - target;
    //    temp.x /= (target.x/lcal.x);
    //    temp.y /= (target.y/lcal.y);
    //    return temp;
    //}
    int getRealIndex(Vector2 pos)//计算realindex
    {
        int x = (int)Mathf.Ceil(mDirect.y * pos.y / cell_y) - 1; //行号
        int y = (int)Mathf.Ceil(mDirect.x * pos.x / cell_x) - 1; //列号
        int realIndex;
        if (arrangeType == ArrangeType.Horizontal)
        {
            realIndex = x * ConstraintCount + y;
        }
        else
        {
            realIndex = x + ConstraintCount * y;
        }
        return realIndex;
    }
    void WrapContent()
    {
        Vector3[] conner_local = new Vector3[4];
        for (int i = 0; i < 4; i++)
        {
            conner_local[i] = mTrans.InverseTransformPoint(conners[i]);
        }
        //计算ScrollRect的中心坐标 相对于this的坐标
        Vector2 center = (conner_local[0] + conner_local[2]) / 2f;
        if (mHorizontal)
        {
            float min = conner_local[0].x - cell_x;//显示区域
            float max = conner_local[2].x + cell_x;
            for (int i = 0, imax = mChild.Count; i < imax; i++)
            {
                Transform temp = mChild[i];
                float distance = temp.localPosition.x - center.x;
                if (distance < -extents)
                {
                    Vector2 pos = temp.localPosition;
                    pos.x += extents * 2f;
                    int realIndex = getRealIndex(pos);
                    if ((minIndex == maxIndex && maxIndex != 0) || (realIndex >= minIndex && realIndex < maxIndex))
                    {
                        if (startConner == StartConner.UpLeft || startConner == StartConner.LowLeft) //只在增长时才更新grid的尺寸 只加长 不缩短
                            UpdateRectsize(pos, (temp as RectTransform).pivot);
                        temp.localPosition = pos;
                        //设置Item内容
                        UpdateItem(temp, i, realIndex);
                    }
                }
                else if (distance > extents)
                {
                    Vector2 pos = temp.localPosition;
                    pos.x -= extents * 2f;
                    int realIndex = getRealIndex(pos);
                    if ((minIndex == maxIndex && maxIndex != 0) || (realIndex >= minIndex && realIndex < maxIndex))
                    {
                        if (startConner == StartConner.UpRight || startConner == StartConner.LowRight)
                            UpdateRectsize(pos, (temp as RectTransform).pivot);
                        temp.localPosition = pos;
                        //设置Item内容
                        UpdateItem(temp, i, realIndex);
                    }
                }
                if (cullContent)//设置裁剪部分是否隐藏
                {
                    Vector2 pos = temp.localPosition;
                    temp.gameObject.SetActive((pos.x > min && pos.x < max) ? true : false);
                }
            }
        }
        else
        {
            float min = conner_local[0].y - cell_y;//显示区域
            float max = conner_local[2].y + cell_y;
            for (int i = 0, imax = mChild.Count; i < imax; i++)
            {
                Transform temp = mChild[i];
                float distance = temp.localPosition.y - center.y;
                if (distance < -extents)
                {
                    Vector2 pos = temp.localPosition;
                    pos.y += extents * 2f;
                    int realIndex = getRealIndex(pos);
                    if ((minIndex == maxIndex && maxIndex != 0 ) || (realIndex >= minIndex && realIndex < maxIndex))
                    {
                        if (startConner == StartConner.LowLeft || startConner == StartConner.LowRight)
                            UpdateRectsize(pos, (temp as RectTransform).pivot);
                        temp.localPosition = pos;
                        //设置Item内容
                        UpdateItem(temp, i, realIndex);
                    }
                }
                else if (distance > extents)
                {
                    Vector2 pos = temp.localPosition;
                    pos.y -= extents * 2f;
                    int realIndex = getRealIndex(pos);
                    if ((minIndex == maxIndex && maxIndex != 0) || (realIndex >= minIndex && realIndex < maxIndex))
                    {
                        if (startConner == StartConner.UpLeft || startConner == StartConner.UpRight)
                            UpdateRectsize(pos, (temp as RectTransform).pivot);
                        temp.localPosition = pos;
                        //设置Item内容
                        UpdateItem(temp, i, realIndex);
                    }
                }
                int _realIndex = getRealIndex(temp.localPosition);
                if (_realIndex < minIndex || _realIndex >= maxIndex)
                {
                    temp.gameObject.SetActive(false);
                }else if (cullContent)//设置裁剪部分是否隐藏
                {
                    temp.gameObject.SetActive((temp.localPosition.y > min && temp.localPosition.y < max) ? true : false);
                }
            }
        }
    }
    void UpdateItem(Transform item, int index, int realIndex) //跟新Item的内容
    {
        if (onInitializeItem != null)
        {
            onInitializeItem(item.gameObject, index, realIndex);
        }
    }
}
— 于 共写了9637个字
— 文内使用到的标签:

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*