NGUI WrapContent

2 篇文章 0 订阅
1 篇文章 0 订阅

为了解决启动成就、排名等UI时的卡顿问题,需要用wrapcontent脚本,在网上找了篇博客,试了试,还行,支持多行单列,多行多列。(多行多列我的做法是用一个空gameobject作为多列子项的父物体)。
具体做法:
首先给UIGrid组件所在物体挂wrapcontent脚本,然后设置minIndex = 0, itemSize = grid.cellHeight, 最后设置刷新函数onInitializeItem的回调。
这是从其它地方找的一个wrapcontent脚本:

//----------------------------------------------
//            NGUI: Next-Gen UI kit
// Copyright © 2011-2016 Tasharen Entertainment
//----------------------------------------------

using UnityEngine;
using System.Collections.Generic;

/// <summary>
/// This script makes it possible for a scroll view to wrap its content, creating endless scroll views.
/// Usage: simply attach this script underneath your scroll view where you would normally place a UIGrid:
/// 
/// + Scroll View
/// |- UIWrappedContent
/// |-- Item 1
/// |-- Item 2
/// |-- Item 3
/// </summary>

[AddComponentMenu("NGUI/Interaction/My Wrap Content")]
[ExecuteInEditMode]
public class MyWrapContent : MonoBehaviour
{
    public delegate void OnInitializeItem(GameObject go, int wrapIndex, int realIndex);

    /// <summary>
    /// Width or height of the child items for positioning purposes.
    /// </summary>

    public int itemSize = 100;

    /// <summary>
    /// Whether the content will be automatically culled. Enabling this will improve performance in scroll views that contain a lot of items.
    /// </summary>

    public bool cullContent = true;

    /// <summary>
    /// Minimum allowed index for items. If "min" is equal to "max" then there is no limit.
    /// For vertical scroll views indices increment with the Y position (towards top of the screen).
    /// </summary>

    public int minIndex = 0;

    /// <summary>
    /// Maximum allowed index for items. If "min" is equal to "max" then there is no limit.
    /// For vertical scroll views indices increment with the Y position (towards top of the screen).
    /// </summary>

    public int maxIndex = 0;

    /// <summary>
    /// Whether hidden game objects will be ignored for the purpose of calculating bounds.
    /// </summary>

    public bool hideInactive = false;

    public bool wrapInCircle = false;

    /// <summary>
    /// Callback that will be called every time an item needs to have its content updated.
    /// The 'wrapIndex' is the index within the child list, and 'realIndex' is the index using position logic.
    /// </summary>

    public OnInitializeItem onInitializeItem;

    protected Transform mTrans;
    protected UIPanel mPanel;
    protected UIScrollView mScroll;
    protected bool mHorizontal = false;
    protected bool mFirstTime = true;
    protected List<Transform> mChildren = new List<Transform>();

    protected List<Transform> MChildren
    {
        get
        {
            if (mChildren == null || mChildren.Count == 0)
                CacheChild();
            return mChildren;
        }
    }


    /// <summary>
    /// Initialize everything and register a callback with the UIPanel to be notified when the clipping region moves.
    /// </summary>
    bool isStart = false;
    protected virtual void Start()
    {
        if (isStart) return;
        isStart = true;
        SortBasedOnScrollMovement();
        WrapContent();
        if (mScroll != null) mScroll.GetComponent<UIPanel>().onClipMove = OnMove;
        mFirstTime = false;

        adjustWrapPos();
    }

    /// <summary>
    /// Callback triggered by the UIPanel when its clipping region moves (for example when it's being scrolled).
    /// </summary>

    protected virtual void OnMove(UIPanel panel) { WrapContent(); }

    void CacheChild()
    {
        mChildren.Clear();
        for (int i = 0; i < transform.childCount; ++i)
        {
            Transform t = transform.GetChild(i);
            if (hideInactive && !t.gameObject.active) continue;
            mChildren.Add(t);
        }
    }

    /// <summary>
    /// Immediately reposition all children.
    /// </summary>

    [ContextMenu("Sort Based on Scroll Movement")]
    public virtual void SortBasedOnScrollMovement()
    {
        if (!CacheScrollView()) return;

        // Cache all children and place them in order
        mChildren.Clear();
        for (int i = 0; i < mTrans.childCount; ++i)
        {
            Transform t = mTrans.GetChild(i);
            if (hideInactive && !t.gameObject.active) continue;
            mChildren.Add(t);
        }

        // Sort the list of children so that they are in order
        /*if (mHorizontal) mChildren.Sort(UIGrid.SortHorizontal);
        else mChildren.Sort(UIGrid.SortVertical);*/
        ResetChildPositions();
    }



    /// <summary>
    /// Immediately reposition all children, sorting them alphabetically.
    /// </summary>

    [ContextMenu("Sort Alphabetically")]
    public virtual void SortAlphabetically()
    {
        if (!CacheScrollView()) return;

        // Cache all children and place them in order
        mChildren.Clear();
        for (int i = 0; i < mTrans.childCount; ++i)
        {
            Transform t = mTrans.GetChild(i);
            if (hideInactive && !t.gameObject.active) continue;
            mChildren.Add(t);
        }

        // Sort the list of children so that they are in order
        mChildren.Sort(UIGrid.SortByName);
        ResetChildPositions();
    }

    /// <summary>
    /// Cache the scroll view and return 'false' if the scroll view is not found.
    /// </summary>

    protected bool CacheScrollView()
    {
        mTrans = transform;
        mPanel = NGUITools.FindInParents<UIPanel>(gameObject);
        mScroll = mPanel.GetComponent<UIScrollView>();
        if (mScroll == null) return false;
        if (mScroll.movement == UIScrollView.Movement.Horizontal) mHorizontal = true;
        else if (mScroll.movement == UIScrollView.Movement.Vertical) mHorizontal = false;
        else return false;
        return true;
    }

    /// <summary>
    /// Helper function that resets the position of all the children.
    /// </summary>
    [ContextMenu("ResetChildPosition")]
    public virtual void ResetChildPositions()
    {
        if (!Application.isPlaying)
        {
            CacheChild();
            adjustWrapPos();
        }

        for (int i = 0, imax = MChildren.Count; i < imax; ++i)
        {
            Transform t = MChildren[i];
            Vector3 pos = t.localPosition;
            t.localPosition = mHorizontal ? new Vector3(i * itemSize, pos.y, 0f) : new Vector3(pos.x, -i * itemSize, 0f);

            UpdateItem(t, i);
        }
    }

    /// <summary>
    /// 刷新Item数据
    /// </summary>
    public void RefreshChildData()
    {
        for (int i = 0, imax = MChildren.Count; i < imax; ++i)
        {
            Transform t = MChildren[i];
            UpdateItem(t, i);
        }
    }

    /// <summary>
    /// Wrap all content, repositioning all children as needed.
    /// </summary>

    public virtual void WrapContent()
    {
        float extents = itemSize * MChildren.Count * 0.5f;
        Vector3[] corners = mPanel.worldCorners;

        for (int i = 0; i < 4; ++i)
        {
            Vector3 v = corners[i];
            v = mTrans.InverseTransformPoint(v);
            corners[i] = v;
        }

        Vector3 center = Vector3.Lerp(corners[0], corners[2], 0.5f);
        bool allWithinRange = true;
        float ext2 = extents * 2f;

        if (mHorizontal)
        {
            float min = corners[0].x - itemSize;
            float max = corners[2].x + itemSize;

            for (int i = 0, imax = MChildren.Count; i < imax; ++i)
            {
                Transform t = MChildren[i];
                float distance = t.localPosition.x - center.x;

                int index = Mathf.RoundToInt(t.localPosition.x / itemSize);
                if (wrapInCircle)
                    index = (index % (maxIndex - minIndex) + (maxIndex - minIndex)) % (maxIndex - minIndex) + minIndex;
                if (distance < -extents)
                {
                    Vector3 pos = t.localPosition;
                    pos.x += ext2;
                    distance = pos.x - center.x;
                    int realIndex = Mathf.RoundToInt(pos.x / itemSize);

                    if (wrapInCircle)
                        realIndex = (realIndex % (maxIndex - minIndex) + (maxIndex - minIndex)) % (maxIndex - minIndex) + minIndex;

                    if (minIndex == maxIndex || (minIndex <= realIndex && realIndex < maxIndex))
                    {
                        t.localPosition = pos;
                        UpdateItem(t, i);
                    }
                    else allWithinRange = false;
                }
                else if (distance > extents)
                {
                    Vector3 pos = t.localPosition;
                    pos.x -= ext2;
                    distance = pos.x - center.x;
                    int realIndex = Mathf.RoundToInt(pos.x / itemSize);

                    if (wrapInCircle)
                        realIndex = (realIndex % (maxIndex - minIndex) + (maxIndex - minIndex)) % (maxIndex - minIndex) + minIndex;

                    if (minIndex == maxIndex || (minIndex <= realIndex && realIndex < maxIndex))
                    {
                        t.localPosition = pos;
                        UpdateItem(t, i);
                    }
                    else allWithinRange = false;
                }
                else if (mFirstTime) UpdateItem(t, i);

                if (cullContent)
                {
                    distance += mPanel.clipOffset.x - mTrans.localPosition.x;
                    if (!UICamera.IsPressed(t.gameObject))
                        NGUITools.SetActive(t.gameObject, (distance > min && distance < max), false);
                }
                else
                {
                    NGUITools.SetActive(t.gameObject, true);
                }
                if (!(maxIndex < 0 && maxIndex < 0) && (index < minIndex || index >= maxIndex))
                    NGUITools.SetActive(t.gameObject, false);
            }
        }
        else
        {
            float min = corners[0].y - itemSize;
            float max = corners[2].y + itemSize;

            for (int i = 0, imax = MChildren.Count; i < imax; ++i)
            {
                Transform t = MChildren[i];
                float distance = t.localPosition.y - center.y;
                int index = Mathf.RoundToInt(-t.localPosition.y / itemSize);//y轴向下为负轴,所以index要取反
                if (wrapInCircle)
                    index = (index % (maxIndex - minIndex) + (maxIndex - minIndex)) % (maxIndex - minIndex) + minIndex;

                if (distance < -extents)
                {
                    Vector3 pos = t.localPosition;
                    pos.y += ext2;
                    distance = pos.y - center.y;
                    int realIndex = Mathf.RoundToInt(-pos.y / itemSize);//y轴向下为负轴,所以index要取反
                    if (wrapInCircle)
                        realIndex = (realIndex % (maxIndex - minIndex) + (maxIndex - minIndex)) % (maxIndex - minIndex) + minIndex;

                    if (minIndex == maxIndex || (minIndex <= realIndex && realIndex < maxIndex))
                    {
                        t.localPosition = pos;
                        UpdateItem(t, i);
                    }
                    else allWithinRange = false;
                }
                else if (distance > extents)
                {
                    Vector3 pos = t.localPosition;
                    pos.y -= ext2;
                    distance = pos.y - center.y;
                    int realIndex = Mathf.RoundToInt(-pos.y / itemSize);//y轴向下为负轴,所以index要取反

                    if (wrapInCircle)
                        realIndex = (realIndex % (maxIndex - minIndex) + (maxIndex - minIndex)) % (maxIndex - minIndex) + minIndex;

                    if (minIndex == maxIndex || (minIndex <= realIndex && realIndex < maxIndex))
                    {
                        t.localPosition = pos;
                        UpdateItem(t, i);
                    }
                    else allWithinRange = false;
                }
                else if (mFirstTime) UpdateItem(t, i);

                if (cullContent)
                {
                    distance += mPanel.clipOffset.y - mTrans.localPosition.y;
                    if (!UICamera.IsPressed(t.gameObject))
                    {
                        NGUITools.SetActive(t.gameObject, (distance > min && distance < max), false);
                    }
                }
                else
                {
                    NGUITools.SetActive(t.gameObject, true);
                }
                if (!(maxIndex < 0 && maxIndex < 0) && (index < minIndex || index >= maxIndex))
                    NGUITools.SetActive(t.gameObject, false);
            }
        }

        //Start首次WrapContent的时候会影响ScrollView的restrictWithPanel所以注释掉。
        //只要能保证WrapContent还没有滑到min或maxIndex的时候,底部的下一个Item的active为true,
        //注释掉这句就不会有什么影响
        //  mScroll.restrictWithinPanel = !allWithinRange;
        //mScroll.InvalidateBounds();

    }

    /// <summary>
    /// Sanity checks.
    /// </summary>

    void OnValidate()
    {
        if (maxIndex < minIndex)
            maxIndex = minIndex;
        if (minIndex > maxIndex)
            maxIndex = minIndex;

    }

    /// <summary>
    /// Want to update the content of items as they are scrolled? Override this function.
    /// </summary>

    protected virtual void UpdateItem(Transform item, int index)
    {
        int realIndex = getRealIndex(item.localPosition);
        if (!(minIndex < 0 && maxIndex < 0) && (realIndex < minIndex || realIndex >= maxIndex))
            item.gameObject.SetActiveRecursively(false);
        else
        {
            item.gameObject.SetActiveRecursively(true);
            if (onInitializeItem != null)
            {
                onInitializeItem(item.gameObject, index, realIndex);
            }
        }

    }

    /// <summary>
    /// 调整Grid的初始坐标贴边,为了自适应
    /// </summary>
    [ContextMenu("adjustWrapPos")]
    public void adjustWrapPos()
    {
        if (mScroll == null)
            CacheScrollView();
        Bounds b = NGUIMath.CalculateRelativeWidgetBounds(mScroll.transform, MChildren[0], true);
        Vector2 pos = transform.localPosition;
        if (mHorizontal)
        {
            pos.x = -(mPanel.GetViewSize().x / 2f - mPanel.baseClipRegion.x - b.extents.x - mPanel.clipSoftness.x);
        }
        else
        {
            pos.y = mPanel.GetViewSize().y / 2f + mPanel.baseClipRegion.y - b.extents.y - mPanel.clipSoftness.y;
        }
        transform.localPosition = pos;
    }

    /// <summary>
    ///根据用户设置的maxIndex 获取ScrollView能滑动到的最小坐标 滑倒maxIndex实际对应的是最小坐标
    /// </summary>
    /// <returns></returns>
    public Vector2 getMinSpringPos()
    {
        if (mScroll == null) CacheScrollView();
        Vector2 pos = mScroll.transform.localPosition;

        if (mHorizontal)
        {
            if (minIndex == maxIndex)
                pos.x = mScroll.transform.localPosition.x - mPanel.GetViewSize().x;
            else
                pos.x = -(itemSize * maxIndex - mPanel.GetViewSize().x);
        }
        else
        {
            if (minIndex == maxIndex)
                pos.y = mScroll.transform.localPosition.y + mPanel.GetViewSize().y;
            else
                pos.y = (itemSize * minIndex);
        }

        return pos;
    }

    /// <summary>
    /// 根据用户设置的minIndex 获取ScrollView能滑动到的最大坐标 滑倒minIndex实际对应的是最大坐标
    /// </summary>
    /// <returns></returns>
    public Vector2 getMaxSpringPos()
    {
        if (mScroll == null) CacheScrollView();
        Vector2 pos = mScroll.transform.localPosition;
        if (mHorizontal)
        {
            if (minIndex == maxIndex)
                pos.x = mScroll.transform.localPosition.x + mPanel.GetViewSize().x;
            else
                pos.x = -(itemSize * minIndex);
        }
        else
        {
            if (minIndex == maxIndex)
                pos.y = mScroll.transform.localPosition.y - mPanel.GetViewSize().y;
            else
            {
                pos.y = (itemSize * maxIndex - mPanel.GetViewSize().y);
                pos.y = pos.y < 0 ? 0 : pos.y;
            }

        }
        return pos;
    }

    public bool couldSpringBack()
    {
        //因为x轴向负轴为变大,y轴向负轴为变小
        if (mHorizontal)
        {
            Vector2 pos = mScroll.transform.localPosition;
            Vector2 minPos = getMinSpringPos();
            return pos.x > minPos.x;
        }
        else
        {
            Vector2 pos = mScroll.transform.localPosition;
            Vector2 maxPos = getMaxSpringPos();
            return pos.y > maxPos.y;
        }

    }

    public bool couldSpringForward()
    {

        if (mHorizontal)
        {
            Vector2 pos = mScroll.transform.localPosition;
            Vector2 maxPos = getMaxSpringPos();
            return pos.x < maxPos.x;
        }
        else
        {
            Vector2 pos = mScroll.transform.localPosition;
            Vector2 minPos = getMinSpringPos();
            return pos.y < minPos.y;
        }
    }


    /// <summary>
    /// 限制ScrollView的滑动边界
    /// </summary>
    /// <param name="pos"></param>
    public void RoundSpringLimit(ref Vector3 pos)
    {
        Vector2 minLimitPos = getMinSpringPos();
        Vector2 maxLimitPos = getMaxSpringPos();
        pos.x = pos.x < minLimitPos.x ? minLimitPos.x : pos.x;
        pos.x = pos.x > maxLimitPos.x ? maxLimitPos.x : pos.x;

        pos.y = pos.y < minLimitPos.y ? minLimitPos.y : pos.y;
        pos.y = pos.y > maxLimitPos.y ? maxLimitPos.y : pos.y;
    }

    /// <summary>
    /// 获取一个locl坐标下对应的真实序号
    /// </summary>
    /// <param name="localPos"></param>
    /// <returns></returns>
    public int getRealIndex(Vector3 localPos)
    {

        int realIndex = (mHorizontal) ?
                Mathf.RoundToInt(localPos.x / itemSize) :
                Mathf.RoundToInt(-localPos.y / itemSize);//y轴向下为负轴,所以index要取反
        if (wrapInCircle)
            realIndex = (realIndex % (maxIndex - minIndex) + (maxIndex - minIndex)) % (maxIndex - minIndex) + minIndex;
        return realIndex;
    }

    /// <summary>
    /// 根据localPos获取对应的序号
    /// </summary>
    /// <param name="localPos"></param>
    /// <returns></returns>
    public int getIndexWithLocalPos(Vector3 localPos)
    {
        return getIndexWithRealIndex(getRealIndex(localPos));
    }

    /// <summary>
    /// 根据真实序号获取对应的序号
    /// </summary>
    /// <param name="realIndex"></param>
    /// <returns></returns>
    public int getIndexWithRealIndex(int realIndex)
    {
        int index = realIndex % MChildren.Count;
        return index;
    }

    /// <summary>
    /// 获取一个真实序号对应的locl坐标
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    public Vector3 getRealShouldPos(int realIndex)
    {
        if (MChildren.Count == 0) return Vector3.zero;

        Vector3 pos = MChildren[0].localPosition;
        int realIndex0 = getRealIndex(pos);

        if (mHorizontal)
        {
            pos.x = pos.x + (realIndex - realIndex0) * itemSize;
        }
        else
        {
            pos.y = pos.y - (realIndex - realIndex0) * itemSize;
        }
        return pos;
    }

    public Vector3 getRealIndexShouldSpringPOS(int realIndex)
    {
        if (!mScroll) CacheScrollView();
        Vector3 scrollPos = mScroll.transform.localPosition;
        if (mHorizontal)
        {
            scrollPos.x = -(realIndex * itemSize);
        }
        else
        {
            scrollPos.y = realIndex * itemSize;
        }

        RoundSpringLimit(ref scrollPos);
        return scrollPos;
    }

    /// <summary>
    /// 根据一个真实序号调整当前所有Item的坐标
    /// </summary>
    /// <param name="realIndex"></param>
    public void WrapChildPosWithRealIndex(int realIndex)
    {
        if (!isStart)
            Start();

        int index = getIndexWithRealIndex(realIndex);
        Vector3 targetPos = getRealShouldPos(realIndex);
        Vector3 offset = targetPos - MChildren[index].localPosition;
        for (int i = 0, Imax = MChildren.Count; i < Imax; i++)
        {
            Vector3 pos = MChildren[i].localPosition;
            pos += offset;
            MChildren[i].localPosition = pos;
        }
        WrapContent();
        RefreshChildData();
    }

    public bool isInBottom()
    {
        float totalLength = itemSize * maxIndex;
        if (mHorizontal)
        {
            return mPanel.clipOffset.x >= (totalLength - mPanel.GetViewSize().x);
        }
        else
        {
            return mPanel.clipOffset.y <= -(totalLength - mPanel.GetViewSize().y);
        }
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值