使用NGUI 3.5.5创建高效的超大Scroll View

在使用NGUI的Scroll View的时候,碰到Scroll Item太多的话(超过100个),在滑动的过程中就会明显掉帧。究其原因就是NGUI每帧会对所有的Scroll Item进行更新,无论它是否显示。

NGUI 3.5.5加入了UIWrapContent,它会将不显示的Scroll Item设为disabled,这样就使得每帧更新的Scroll Item减少到当前显示的那几个,就再也不会出现掉帧的情况了。

不过UIWrapContent只能创建循环的Scroll View,不过只需要简单的几处修改,就能实现在普通的Scroll View上。

复制一份UIWrapContent.cs,重命名为UIBetterGrid.cs,修改类名

// line: 19 - 20, file: UIWrapContent.cs 
[AddComponentMenu("NGUI/Interaction/Wrap Content")] 
public class UIWrapContent : MonoBehaviour 

修改后的代码如下:

// line: 19 - 20, file: UIBetterGrid.cs 
[AddComponentMenu("NGUI/Interaction/Better Grid")] 
public class UIBetterGrid : MonoBehaviour 

修改初始化代码
// line: 52 - 54, file: UIWrapContent.cs
mScroll.restrictWithinPanel = false; 
if (mScroll.dragEffect == UIScrollView.DragEffect.MomentumAndSpring) 
mScroll.dragEffect = UIScrollView.DragEffect.Momentum; 

修改后的代码如下:

// line: 52 - 54, file: UIBetterGrid.cs 
mScroll.restrictWithinPanel = true; 
//if (mScroll.dragEffect == UIScrollView.DragEffect.MomentumAndSpring) 
//mScroll.dragEffect = UIScrollView.DragEffect.Momentum; 

注释创建首尾循环的代码

// line 159 - 170, file: UIBetterGrid.cs
//if (distance < -extents) 
//{ 
//     t.localPosition += new Vector3(extents * 2f, 0f, 0f); 
//        distance = t.localPosition.x - center.x; 
//     UpdateItem(t, i); 
//} 
//else if (distance > extents) 
//{ 
//     t.localPosition -= new Vector3(extents * 2f, 0f, 0f); 
//        distance = t.localPosition.x - center.x; 
//     UpdateItem(t, i); 
//} 
// line 190 - 201, file: UIBetterGrid.cs 
//if (distance < -extents) 
//{ 
//        t.localPosition += new Vector3(0f, extents * 2f, 0f); 
//        distance = t.localPosition.y - center.y; 
//     UpdateItem(t, i); 
//} 
//else if (distance > extents) 
//{ 
//     t.localPosition -= new Vector3(0f, extents * 2f, 0f); 
//        distance = t.localPosition.y - center.y; 
//     UpdateItem(t, i); 
//} 

修改 UIScrollView.cs

// line 173, file: UIWrapContent.cs
mBounds = NGUIMath.CalculateRelativeWidgetBounds(mTrans, mTrans); 
修改后的代码如下:

// line 173, file: UIBetterGrid.cs
mBounds = NGUIMath.CalculateRelativeWidgetBounds(mTrans, mTrans,true); 


最后,使用NGUI自带的例子Example 7 - Scroll View (Panel).unity测试下性能吧。把例子中的UIGrid替换为UIBetterGrid,试试复制成百上千个scroll item,跑起来一点也不会卡。


最后完整的代码如下,UIScrollView的代码别忘了

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

using UnityEngine;

/// <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/Wrap Content")]
public class UIBetterGrid : MonoBehaviour
{
	/// <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;

	Transform mTrans;
	UIPanel mPanel;
	UIScrollView mScroll;
	bool mHorizontal = false;
	BetterList<Transform> mChildren = new BetterList<Transform>();

	/// <summary>
	/// Initialize everything and register a callback with the UIPanel to be notified when the clipping region moves.
	/// </summary>

	protected virtual void Start ()
	{
		SortBasedOnScrollMovement();
		WrapContent();

		if (mScroll != null)
		{
			mScroll.GetComponent<UIPanel>().onClipMove = OnMove;
			mScroll.restrictWithinPanel = true;
			//if (mScroll.dragEffect == UIScrollView.DragEffect.MomentumAndSpring)
			//	mScroll.dragEffect = UIScrollView.DragEffect.Momentum;
		}
	}

	/// <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(); }

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

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

		// Cache all children and place them in order
		mChildren.Clear();
		for (int i = 0; i < mTrans.childCount; ++i)
			mChildren.Add(mTrans.GetChild(i));

		// 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 void SortAlphabetically ()
	{
		if (!CacheScrollView()) return;

		// Cache all children and place them in order
		mChildren.Clear();
		for (int i = 0; i < mTrans.childCount; ++i)
			mChildren.Add(mTrans.GetChild(i));

		// 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>

	void ResetChildPositions ()
	{
		for (int i = 0; i < mChildren.size; ++i)
		{
			Transform t = mChildren[i];
			t.localPosition = mHorizontal ? new Vector3(i * itemSize, 0f, 0f) : new Vector3(0f, -i * itemSize, 0f);
		}
	}

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

	public void WrapContent ()
	{
		float extents = itemSize * mChildren.size * 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);

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

			for (int i = 0; i < mChildren.size; ++i)
			{
				Transform t = mChildren[i];
				float distance = t.localPosition.x - center.x;

                //if (distance < -extents)
                //{
                //    t.localPosition += new Vector3(extents * 2f, 0f, 0f);
                //    distance = t.localPosition.x - center.x;
                //    UpdateItem(t, i);
                //}
                //else if (distance > extents)
                //{
                //    t.localPosition -= new Vector3(extents * 2f, 0f, 0f);
                //    distance = t.localPosition.x - center.x;
                //    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
		{
			float min = corners[0].y - itemSize;
			float max = corners[2].y + itemSize;

			for (int i = 0; i < mChildren.size; ++i)
			{
				Transform t = mChildren[i];
				float distance = t.localPosition.y - center.y;

                //if (distance < -extents)
                //{
                //    t.localPosition += new Vector3(0f, extents * 2f, 0f);
                //    distance = t.localPosition.y - center.y;
                //    UpdateItem(t, i);
                //}
                //else if (distance > extents)
                //{
                //    t.localPosition -= new Vector3(0f, extents * 2f, 0f);
                //    distance = t.localPosition.y - center.y;
                //    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);
				}
			}
		}
	}

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

	protected virtual void UpdateItem (Transform item, int index) {}
}


文章转载自使用NGUI 3.5.5创建高效的超大Scroll View,感谢JJCat提供好文章

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值