UGUI 的 Scroll Rect 优化卡顿现象-新闻详情

UGUI 的 Scroll Rect 优化卡顿现象


发布时间:2017-05-24责任编辑:朱明 浏览:6234


现手游项目中使用了大量的滚动层,但滚动层使用不慎,就给给项目带来困扰,尤其是面对需要加载大量数据的子部件时,在滑动过程中难免会有卡顿现象,接下来讲一下自己使用scrollRect时,需要加载大量子部件时的方法,供大家参考,大家有更好的建议欢迎一起探讨。

图片是项目中的英雄列表,它使用了scrollRect 加载了很多英雄,每个英雄上包含了多重信息。

1.png

 

scrollRect  加载大量子部件后,滑动 scrollRect  过程中,引擎会同时计算所有子部件的位置信息,如果子部件上包含N个子子部件,那么他的计算量便是普通的N倍,如下面两图对比,每一条黑色的线,便是一个需要计算的点,第三张图可以看出下面所有的子部件,都显示在引擎中。

2.png  3.png4.png

 

本方法就是实现减少计算量,简单原理是,首先给子部件增加一个占位部件,也就是当该部件需要展示时,在占位部件上加载该部件,当滑动到隐藏位置时,将该部件从占位上移除,这样在看不到的地方只会有空的占位参与位置计算,计算消耗必然下降,需要的内存也会减少。

话不多说,上代码。

//列表中添加英雄

     public void ShowHeros(List<ServerPlayerHero>  listHeros)

    {

        for (int i = listHeros.Count - 1; i  >= 0; i--)

        {

            //创建占位

            GameObject go =  uiHandler.AddItem(listHeroRoot, heroItemBox);

            var item =  go.GetComponent<HeroItemViewBox>();

            //初始化占位英雄信息

             item.Set(listHeros[i]);

            //给占位增加位置移动监听

             scrollRect.onValueChanged.AddListener(item.MoveChanged);

        }

    }

//位置监听

    public void MoveChanged(Vector2  position)

    {

        //判断当前位置是否在可视范围内,数值可以自行调节。

        bool isfanwei = transform.position.y  < 0.3 && transform.position.y > -0.8;

//isShow指的是当前是否在显示状态

       if (isShow &&  !isfanwei)

            removeHero();//移除子部件

        else (!isShow &&  isfanwei)

            ShowHero();//添加子部件

    }

 

个人在移除子部件和添加子部件时加入了缓存池,使其效率更高。

//展示该角色

    public void  ShowHero()

    {

        heroitem =  pool.Pop(heroItem);//缓存池中取出item

        if (heroitem == null)  return;

        isShow =  true;

         heroitem.transform.SetParent(transform);

        heroitem.transform.localScale = new  UnityEngine.Vector3(1, 1, 1);

        heroitem.transform.localPosition =  Vector3.zero;

         heroitem.Set(heroMsg);

    }

    //移除该角色

    void  removeHero()

    {

        isShow =  false;

         pool.Push(heroitem);//放入到缓存池中

        heroitem =  null;

    }

//缓存池

public class  HeroItemPool : IHeroItemPool

{

    //私有的list,保存未被使用的item

    private Stack<HeroItemView> listItems  = new Stack<HeroItemView>();//缓存列表

 

    public HeroItemView Pop(GameObject  prefab)

    {

        //当list中没有item时,创建一个新的

        if (listItems.Count ==  0)

        {

            GameObject go =  GameObject.Instantiate<GameObject>(prefab);

             listItems.Push(go.GetComponent<HeroItemView>());

        }

        return  listItems.Pop();

    }

 

    public void Push(HeroItemView  t)

    {

        //当list中数量大于12时,移除,因为他应该不会用到了

        if (listItems.Count <  12)

       {

             listItems.Push(t);

             t.transform.SetParent(null);

        }

        else {

             GameObject.DestroyImmediate(t.gameObject);

        }

    }

}

 

战国工作室  供稿