ugui scrollrect 优化能垂直拖动吗

uGUI练习(七) Drag And Drop-不解
一、相关组件
EventTrigger
Canvas Group
ScrollRect
二、拖放练习 1、创建一个Panel,命名Panel1,添加EventTrigger组件,稍稍改一下Panel的颜色
2、Panel1下创建一个Text,输入”Test Draggable\n&&&&&& object”,设置字体颜色及Text超出处理
3、在 一文中,已经大概了解uGUI的EventSystem,需要继承三个事件接口,接下来我们创建一个DragDropScene.cs,代码如下:using UnityE using System.C using UnityEngine.UI; using UnityEngine.EventS public class DragDropScene : MonoBehaviour,IDragHandler,IPointerDownHandler,IPointerUpHandler { public void OnDrag(PointerEventData eventData) { GetComponent&RectTransform&().pivot.Set(0,0); transform.position=Input.mouseP } public void OnPointerDown(PointerEventData eventData) { transform.localScale=new Vector3(0.7f,0.7f,0.7f); } public void OnPointerUp(PointerEventData eventData) { transform.localScale=new Vector3(1f,1f,1f); } } 4、上面的代码就是 按下,拖动,抬起 这三个事件的处理.把这个脚本绑定在Panel1,按Ctrl+P 运行游戏,在Game视图我们就可以拖动Panel1了.
5、选中创建好的Panel1,按Ctrl+D Copy 几个Panel,更改成不同的颜色,如下图所示:
6、在上面的步骤中,我们创建了几个Panel1,并且给它们都绑定了DragDropScene.cs,但还没有实现Drop的事件; 接下来,我们创建一个Panel,命名DropPanel,用来作停放Panel的容器 7、在DropPanel下创建一个Panel,命名Grid,并给它添加Grid Layout Group和Canvas Group组件
8、为了让我们知道Drop是可以停放的,我们在Grid下创建两个Panel,同样的给它们绑定DragDropScene.cs,如下图:
9、接下来就是把Panel,拖动并停放在DropPanel下,如下图所示
10、打开DragDropScene.cs脚本,添加一行,并修改OnPointerDown(),OnPointUp( )[SerializeField] GameObject grid=null,rootCanvas=public void OnPointerDown(PointerEventData eventData) { transform.localScale=new Vector3(0.7f,0.7f,0.7f); transform.parent=rootCanvas. }
public void OnPointerUp(PointerEventData eventData) { transform.localScale=new Vector3(1f,1f,1f); RaycastHit2D hit = Physics2D.Raycast(Input.mousePosition,-Vector2.up); if (hit.collider != null) { //如果射线检测到的gameobject为grid,就把当前Panel放在grid节点下 if(hit.collider.gameObject.name==&Grid&) transform.parent=grid. } }上面的代码,当鼠标抬起时,如果是在Grid的上方,就把当前Panel设置在Grid下,鼠标按下时,设置当前Panel的Parent为rootCanvas11、为DragDropScene设置参数值: &12、到这一步,我们就可以拖动Panel放到Grid下了,为了避免Grid下的Panel超出,在一文中我们使用了SrollRect和Mask.所以现在我们就给DropPanel添加上这两个组件,当然最后也可以给DropPanel添加Scrollbar
三、CanvasGroup CanvasGroup是一个容器,可以用来改变child的Alpha,Raycasting,Enable state. 可以用来改变child元素的state. 比如:在一段时间内window变淡,在同一个group里的child元素的alpha值也会受到影响,alpha 值=任何嵌套的group相乘。乘以canvas元素的alpha值. CanvasGroup 可以配置为不遮挡 射线(在这个group里的任何物件都不用为图形射线考虑) ,并且元素是否相互作用. 四、EventTrigger 从事件系统接收事件并调用每一个已注册的事件. 在每一个特殊的函数中,都可以使用EventTrigger,你可以在一个事件上注册多个函数,当EventTrigger接收事件时,将按提供的顺序调用. 注意:将EventTrigger组件绑定在任何Gameobject上之后,它将拦截一切事件,并在这个对象上没有冒泡事件出现. 五、Drag && Drop 效果
同步自网易博客
很喜欢此文字
很喜欢此文字
很喜欢此文字
很喜欢此文字
很喜欢此文字
转载了此文字
很喜欢此文字
很喜欢此文字
很喜欢此文字
很喜欢此文字
转载了此文字请完成以下验证码
您当前的位置: &
如何优化UGUI的ScrollRect
查看: 1935|
|原作者: 钱康来
UGUI的ScrollRect在加载太多物体的时候,第一次弹出界面会非常卡顿,而且不在界面里的内容依然会参与绘制,导致毫无意义的浪费。笔者对此进行了一番研究,并将心得与大家分享。介绍每个元素知道自己的序号,可以根据需要修改自己的内容、大小等信息。此外支持了ScrollBar,支持横向、纵向及正反向。在关闭Mask后可以看到,只有当需要的时候才动态实例化元素,使用完后回收。最原始版本的代码是@ivomarel的InfinityScroll。我改到后来,基本和原始版没啥相同的了。原代码使用了sizeDelta作为大小,但是这个在锚点不重合情况下是不成立的支持了GridLayout在启动时检查锚点和轴心,方便使用修复了原代码在往前拖拽会卡顿的问题优化代码,提升性能支持反向滑动支持ScrollBar (在无尽模式下不起作用;如果元素大小不一致会出现滚动条瑕疵)此外,我修改了Easy Object Pool作为池子,循环利用元素。警告: 为了解决原始代码回拉卡顿的问题,我直接复制了一份UGUI中的ScrollRect代码,而没有继承。这是因为老的做法是在onDrag里停止并立即启动滚动,而我通过修改两个私有变量保证了滑动顺畅。所有我的代码都用==========LoopScrollRect==========这样的注释包起来,维护起来就像打patch了。框架思路和UGUI自带的ScrollRect有所不同,我拆分出了LoopHorizontalScrollRect和LoopVerticalScrollRect两个类,分别代表水平滚动条和水平滚动条。下面我们以LoopVerticalScrollRect为例,水平版本类似。1. 判定cell大小LoopScrollRect要解决的核心问题是:如何计算每个元素的大小。这里我使用了Content Size Fitter配合Layout Element来控制每个cell的长宽,因此对于GridLayout直接取高度,否则取Preferred Height。需要注意的是,除了元素本身的大小之外,我们还要将padding考虑进去。protected override float GetSize(RectTransform item){
float size = contentS
if (m_GridLayout != null)
size += m_GridLayout.cellSize.y;
size += LayoutUtility.GetPreferredHeight(item);
}}这个其实也是最核心的一个地方:在能够准确计算格子大小的基础上,后续工作就好实现了。2. 如何优雅的增删元素对于每个ScrollRect,其实只需要考虑在头部和尾部是否需要增加或者删除元素。在这里以头部的各种情况为例进行解释,因为在正向滑动情况下,必须保证在修改元素之后整个ScrollRect内容显示一致不跳变;这些情况比尾部处理会麻烦一些。NewItemAtStart函数实现了在头部增加一个(或一行,针对GridLayout)元素,并返回这些元素的高度;DeleteItemAtStart代表删除头部的一个元素。需要注意的是,在修改头部元素之后要及时修改content的anchoredPosition,这样才能保证整个内容区域不会因为多了或者少了一行而产生跳变。protected float NewItemAtStart(){
float size = 0;
for (int i = 0; i & contentConstraintC i++)
// Get Element from ObjectPool
if (!reverseDirection)
// Modify content.anchoredPosition
}}protected float DeleteItemAtStart(){
float size = 0;
for (int i = 0; i & contentConstraintC i++)
// Return Element to ObjectPool
if (!reverseDirection)
// Modify content.anchoredPosition
}}3. 何时需要增删元素这里需要有两个概念viewBounds和contentBounds:前者是指ScrollRect本身的大小,一般也对应Mask;后者是指ScrollRect里所有cell组成的内容部分的大小。在这个基础上就简单了:如果contentBounds的最上面比viewBounds的最上面要低,那么尝试在顶部增加元素;如果contentBounds的最上面比viewBounds的最上面高很多,那么尝试删除元素。protected override bool UpdateItems(Bounds viewBounds, Bounds contentBounds){
bool changed =
// cases for NewItemAtEnd/DeleteItemAtEnd
if (viewBounds.max.y & contentBounds.max.y - 1)
float size = NewItemAtStart();
if (size & 0)
else if (viewBounds.max.y & contentBounds.max.y - threshold)
float size = DeleteItemAtStart();
if (size & 0)
}}4. 对象池交互在新建cell和销毁cell的时候,使用对象池来避免内存碎片;同时这里使用了SendMessage来向每个cell发送必须的信息,保证数据的正确性。private void SendMessageToNewObject(Transform go, int idx){
go.SendMessage("ScrollCellIndex", idx);}private void ReturnObjectAndSendMessage(Transform go){
go.SendMessage("ScrollCellReturn", SendMessageOptions.DontRequireReceiver);
prefabPool.ReturnObjectToPool(go.gameObject);}private RectTransform InstantiateNextItem(int itemIdx){
RectTransform nextItem = prefabPool.GetObjectFromPool(prefabPoolName).GetComponent&RectTransform&();
nextItem.transform.SetParent(content, false);
nextItem.gameObject.SetActive(true);
SendMessageToNewObject(nextItem, itemIdx);
return nextI}5. 滚动条相关这块我其实是估算的,根据当前的长度和当前元素个数/总个数按照比例缩放,这个在所有cell大小一致的情况下是没有问题的;但是如果大小不一致我就无法得到精确结果,所以会产生一定抖动。我暂时没有更好办法,因为得到的信息就是不够用。6. 其他细节我主要遇到了两个坑:增加或者删除元素之后,有时候需要强行调用Canvas.ForceUpdateCanvases()刷新下。注意不要在Build Canvas过程中再次修改元素,从而再次触发Build Canvas。使用示例以竖直滚动条为例,介绍一下步骤。如果觉得麻烦的话,直接打开DemoScene复制粘贴就好。当然你也可以干掉EasyObjPool,自己控制生成和销毁。1. 准备好Prefabs每个物体上需要贴上Layout Element并指定preferred width/height。贴上一个脚本接受void ScrollCellIndex (int idx) 消息,从而对每个位置的元素根据需要灵活修改。2. 在Hierarchy里右键,选择UI/Loop Horizontal Scroll Rect或UI/Loop Vertical Scroll Rect即可。使用Component菜单里的也是一样的。Init in Start:&启动时自动调用Refill cells初始化Prefab Pool:&EasyObjPool物体Prefab Pool Name:&第二步中对应的Cell Prefab名字Total Count:&总共能有多少物体,范围0 ~ TotalCount-1Threshold:&两端预留出来的缓存量(像素数)ReverseDirection:&如果是从下往上或者从右往左拖动,就打开这里Clear Cells:&清除已有元素,恢复到未初始化状态Refill Cells:&初始化并填充元素如果是正向滑动,就设置pivot为1;否则设为0并打开ReverseDirection。我强烈建议你试试在播放状态下修改这些参数。无尽模式如果需要无限滚动模式,将totalCount设为负数即可。其他参考后来搜了下,发现网上也有人提到过UGUI ScrollRect 优化(),不过他的策略是监听ScrollRect的value,然后禁用范围外的cell。最后作者也提到改成动态加载策略。这种基于value的做法我不太确认在在滚动前动态添加新元素的时候是否会出现问题。文末,再次感谢钱康来的分享,如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群)。
微信扫一扫
专注于VR的学习、开发和人才交流
&津ICP备号移动效果开发_UGUI ScrollRect 带按钮翻页支持拖拽效果
移动效果开发_UGUI ScrollRect 带按钮翻页支持拖拽效果。
using System.C
using UnityEngine.UI;
using UnityEngine.EventS
using System.Collections.G
/// 略知CSharp https://blog.csdn.net/subsystemp
public class ScrollRectHelper : MonoBehaviour, IBeginDragHandler, IEndDragHandler
public float smooting = 5;
//滑动速度
public List listI
//scrollview item
public int pageCount = 3;
//每页显示的项目
float pageI
bool isDrag =
//是否拖拽结束
List listPageValue = new List { 0 };
//总页数索引比列 0-1
float targetPos = 0;
//滑动的目标位置
float nowindex = 0;
//当前位置索引
void Awake()
srect = GetComponent();
ListPageValueInit();
//每页比例
void ListPageValueInit()
pageIndex = (listItem.Count / pageCount)-1;
if (listItem != null && listItem.Count != 0)
for (float i = 1; i &= pageI i++)
listPageValue.Add((i / pageIndex));
void Update()
if (!isDrag)
srect.horizontalNormalizedPosition = Mathf.Lerp(srect.horizontalNormalizedPosition, targetPos, Time.deltaTime * smooting);
/// 拖动开始
public void OnBeginDrag(PointerEventData eventData)
/// 拖拽结束
public void OnEndDrag(PointerEventData eventData)
var tempPos = srect.horizontalNormalizedP //获取拖动的值
var index = 0;
float offset = Mathf.Abs(listPageValue[index] - tempPos);
//拖动的绝对值
for (int i = 1; i & listPageValue.C i++)
float temp = Mathf.Abs(tempPos - listPageValue[i]);
if (temp & offset)
targetPos = listPageValue[index];
nowindex =
public void BtnLeftGo()
nowindex = Mathf.Clamp(nowindex - 1, 0, pageIndex);
targetPos = listPageValue[Convert.ToInt32(nowindex)];
public void BtnRightGo()
nowindex = Mathf.Clamp(nowindex + 1, 0, pageIndex);
targetPos = listPageValue[Convert.ToInt32(nowindex)];}

我要回帖

更多关于 ugui scrollrect 优化 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信