UGUI ScrollRect完美使用

第一次在正式项目里用UGUI,遇到不少问题。其中ScrollRect是比较让人恼火的。看了很多网上已有教程和原代码,终于做出满足项目需求的样子来了。简单分享一下。如有错误的地方,希望大家可以指出,一起进步!

制作一个滚动列表,首先就会想到ScrollRect这个组件。但与NGUI的不同,NGUI的UIScrollView把很多功能都写好了,或者都写到滚动列表专用的几个脚本里。但UGUI的各组件更加分离,比如ScrollRect里面的布局,不是在做滚动列表才使用,而是对所有布局情况下都通用的。我们要做的是把几个通用组件合理组合起来,做出某种特定功能的东西。

首先来看下我的功能树目录:

跟官方的例子很像吧。这里的ScrollPanel是我的一个界面根节点,比如你可以把它当成一个道具界面,ScrollRect是这个界面的主要内容,放了很多道具。整个ScrollRect分了3层,中间层ViewPoint是用来指定滚动窗口大小的,出了ViewPoint范围的Item就看不见了。Content节点是放布局组件的,你可以用水平布局或垂直布局等。

ScrollRect节点上的组件如下:

主要就是挂ScrollRect脚本,在两处红框分别挂Content节点和ViewPoint节点。因为我的例子里是做水平滚动的,所有在Horizontal里打勾就行了。然后MovementType指定为Elastic,就是有弹性,在Content内容大小大小ViewPoint可视区域大小时,会把Content的内容自动弹回边界位置。

ViewPoint节点的组件如下:

这里要做的是指定滚动可视区域的大小,比如我指定大小为720*240,效果如下:

白色区域,就是在ViewPoint里指定的可视区域,Item出超出这个区域就会看不见了。其实白色区域不需要显示出来,把Mask组件的Show Mask Graphic的勾取消就行了。

Content节点的组件如下:

这个组件非常关键,用了两个UGUI的重要组件,一个是Horizontal Layout Group,水平布局组。用来把Content下面的子节点自动水平布局,Padding用来指定上下左右的偏移量,注意,Left和Right尽量一致,否则Content在自动调整大小时会有问题。Content Size Fitter组件用于让Content自动根据其子节点的大小来调整自身的大小。如果没有这个组件,在动态添加Item时,Content的大小就不会自动调整大小了,在拖动时就会发现有些位置拖不过去。因为Content的大小一定要比所有子节点的大小要大,才能正常显示。你可以试一下把这个组件去掉,然后在运行时动态添加item,看看有什么情况发生。当然,有些人喜欢自己写布局或自己写代码动态调整Content的大小。我喜欢用UGUI的组件,既然有现成的,就把它用得如鱼得水。

注意看我这里的Pivot(轴心点),我把它的x设置为0。如果不设置为0会怎样,看看打开界面后的效果。

这是我运行时打开界面的效果,第一个item没有显示在第一的位置,这是为什么。因为我们用了Content Size Fitter组件,这个组件在自动调整UI元素的大小时,是根据UI元素自身的轴心点来扩展大小的,也就是说,如果我Content的轴心点在0.5*0.5位置的话,Content的大小就会向四周扩大。如果我把Pivot设置为0*0.5,效果如下:

Content就会从轴心点(0,0.5)向外扩大,那前面的item就可以在打开界面时就看得到了。

有些界面我们会打开了关闭再打开,如果第一次打开这个滚动界面并且发生了拖动,不做任何处理只是简单隐藏界面的话,下次打开Content还是停留在上一次拖动的位置。

怎么解决?只要在代码里加一句代码随便设置一下Content的位置,它就会自动回到起始位置了。比如:

如果我们的Item是可以点击的,而且是自己重写了EventTrigger或封装了点击回调脚本,那可能会出现一个问题,在item上面拖动时没有效果,ScrollRect的拖动事件被屏蔽了。如果你的Item直接用Button组件来做的话是没问题的,但很多同学喜欢根据需求或更加便利地使用点击事件就自己写了点击回调脚本。比如,雨松大神的那个代码,如果用那种方法做按钮并把按钮放到ScrollRect上的话,在item上拖动就没效果了。为什么?因为EventTrigger继承了IDragHandler这些接口,如果你自己写的事件触发器是继承了EventTrigger,事件触发器挂在Item上就会把拖动事件截取,但是自己又没有实现IDraghandler,所以在item上面拖动就没任何反应了。所以在自己写点击按钮回调脚本时,可以根据自己需求单独继承IPointerClickHandler,不要什么接口都继承。

还有最后一个问题,策划可以需要我们自动把ScrollRect定位到某一个item上,比如在打开界面时ScrollRect就自动滚动到item9的位置,让item9显示在ViewPoint中间。这个要怎么做呢?

在NGUI里,UIScrollView有一个参数可以设置当前滚动的百分比,只要计算要滚动到的Item在所有Item中的位置比例就可以了。但在UGUI中没有这个功能。我们需要手动计算应该把Content定位到哪个位置。

/// <summary>

/// 指定一个 item让其定位到ScrollRect中间

/// </summary>

/// <param name="target">需要定位到的目标</param>

public void CenterOnItem(RectTransform target)

{

// Item is here

var itemCenterPositionInScroll = GetWorldPointInWidget( scrollRect.GetComponent <RectTransform>(), GetWidgetWorldPoint( target));

Debug .Log( "Item Anchor Pos In Scroll: " + itemCenterPositionInScroll);

// But must be here

var targetPositionInScroll = GetWorldPointInWidget( scrollRect.GetComponent <RectTransform>(), GetWidgetWorldPoint( viewPointTransform));

Debug .Log( "Target Anchor Pos In Scroll: " + targetPositionInScroll);

// So it has to move this distance

var difference = targetPositionInScroll - itemCenterPositionInScroll;

difference .z = 0f ;

var newNormalizedPosition = new Vector2(difference .x / (contentTransform.rect.width - viewPointTransform.rect.width ),

difference .y / (contentTransform.rect .height - viewPointTransform. rect.height ));

newNormalizedPosition = scrollRect.normalizedPosition - newNormalizedPosition;

newNormalizedPosition .x = Mathf.Clamp01(newNormalizedPosition.x );

newNormalizedPosition .y = Mathf.Clamp01(newNormalizedPosition.y );

DOTween .To(() => scrollRect.normalizedPosition , x=>scrollRect.normalizedPosition = x , newNormalizedPosition, 3);

}

Vector3 GetWidgetWorldPoint (RectTransform target)

{

//pivot position + item size has to be included

var pivotOffset = new Vector3(

(0.5f - target .pivot. x) * target .rect. size.x ,

(0.5f - target .pivot. y) * target .rect. size.y ,

0f);

var localPosition = target.localPosition + pivotOffset ;

return target.parent.TransformPoint (localPosition);

}

Vector3 GetWorldPointInWidget (RectTransform target, Vector3 worldPoint)

{

return target.InverseTransformPoint(worldPoint );

}

我直接上代码了,就是调用CenterOnItem这个方法,传入一个item的RectTransform。上面用到了DoTween插件,使得在定位时可以平滑一点,不懂这个的直接百度DoTween。还有一种方法,也是计算好Item的目标位置,直接设置Content的位置

void CenterToSelected (GameObject selected)

{

var target = selected.GetComponent<RectTransform >();

Vector3 maskCenterPos = viewPointTransform.position + (Vector3)viewPointTransform.rect .center;

Debug .Log ( "Mask Center Pos: " + maskCenterPos);

Vector3 itemCenterPos = target.position;

Debug .Log ( "Item Center Pos: " + itemCenterPos);

Vector3 difference = maskCenterPos - itemCenterPos;

difference .z = 0 ;

Vector3 newPos = contentTransform.position + difference ;

DOTween .To(() => contentTransform.position , x => contentTransform. position = x , newPos, 5);

}

其实都差不多,设置ScrollRect.normalizedPosition,在源代码里也是设置Content的位置。而上一种方法,我把移动比例设置在0到1的范围,这在定位前面几个和最后几个item时,就不会跳(呵呵 呵呵呵呵我都不知道怎么讲)。总之自己多试一下吧,我也折腾了一下午,最后看了外国论坛和源代码才最终搞定了,好累。准备跨年啦,祝同学们新年快乐!

时间: 2024-07-30 03:12:25

UGUI ScrollRect完美使用的相关文章

UGUI ScrollRect 代码定位

在NGUI 的scrollview组建定位可以直接用value:但是在ugui上的scrollrect确实分的更细了分为 verticalNormallizedPosition 和HorizontalNormaliazedPozition 以及可以设置vector2的NormallizedPosition, 但是这里面有一个坑,实例化列表时要定位需要等待一帧ugui布局才能完成,需要做个协程在endofFrame执行

GJM :Unity UI 之 UGUI 开发

转载URL:http://www.manew.com/thread-41633-1-1.html 最近因为要做各种UI控件,于是与UGUI杠上了.首当其冲的就是RectTransform,最坑爹的是,这货竟然不是UGUI框架的,代码竟然封装在unityengine里面,所以,不得不吐槽下unity的开源动机,根本就是留一手,估计只是因为自己的研发力量不足,所以开放一部分出来而已.       RectTransform继承于Transform,配合Canvas专门交给UGUI使用,具体这边就不展

Unity3D UGUI中ScrollRect的一些知识点

需求 这几天在公司里,项目需要将游戏游戏中的2D城堡界面在拉动的时候显示出3D的拉近效果.当时是在Cocos2d-x下实现的.回家的时候自己重新用Unity实现的了一遍. 虽然现在Unity已经到了5.0时代,从4.6时代起Unity就开始支持原生2D了,网络上大部分的教程还是NGUI.毕竟原生的也是开源的,详细以后也会慢慢取代NGUI. 解决思路 需要在拉动的过程中显示出由远及近不通层次的效果,自然想到了利用Scroll类型的控件.Unity中原生2D中使用到的时ScrollRect组件. 在

UGUI 与 Spine 的完美结合

SkeletonGraphic.cs       代替官方的  SkeletonAnimation.cs   使用(对象/预制体上) SkeletonGraphic.shader   代替 官方的   Spine/Skeleton  shader 使用(赋值给材质上)

UGUI初学习--------Canvas

今天仔细研究了一下UGUI觉得有必要写一篇文章来分享一下.废话不多说直接开码字..... 作者之前也学过NGUI.这里来说明一下,UGUI和NGUI的渲染结构略有不同,UGUI中将NGUI中的深度处理项取消了.UGUI的渲染是按照Hierarchy的UI游戏对象的排列顺序从上到下依次渲染的,重叠部分后渲染的会把先渲染的挡住.总结一句话:下在上前,子在父前.为了修改各个UI控件的绘制顺序,开发者可以采用以下两种方法:拖动Hierarchy视图里的各UI控件对象,改变它们在Canvas下的排列顺序:

Unity UGUI —— 无限循环List

还记得大学毕业刚工作的时候是做flash的开发,那时候看到别人写的各种各样的UI组件就非常佩服,后来自己也慢慢尝试着写,发现其实也就那么回事.UI的开发其实技术的成分相对来说不算多,但是一个好的UI是绝对少不了底层组件的支持的.我个人认为UI组件中相对比较复杂的就是List了,所以,这两天实现了一个UGUI的list,写了好几个版本,最终这个版本是相对比较好用的,在这我介绍一下大概思路,一是巩固一下知识做个记录,二是发扬一下分享精神.嘿嘿,大家多多赐教. 写List有两个重点是需要考虑的: 1.

如何快速优化手游性能问题?从UGUI优化说起

WeTest 导读 本文作者从自身多年的Unity项目UI开发及优化的经验出发,从UGUI,CPU,GPU以及unity特有资源等几个维度,介绍了unity手游性能优化的一些方法. 在之前的文章<手游内存占用过高?如何快速定位手游内存问题>中提到,Mono内存和native内存是PSS内存主要的组成部分,mono内存更多的起到内存调用的功能,因此常常成为了开发人员优化内存的起点:而在游戏的其他的进程中,同样有很多因素影响着游戏的性能表现.本文将从UGUI的优化角度,介绍unity游戏性能优化的

UGUI 之Scroll Rect 坑

由于UGUI没有提供类似Scroll View类似的控件,但提供了ScrollRect主机.可以自定义Scroll View 同时提供了Mask组件来遮罩超出Scroll Rect对象的范围, 之所以说有一个坑,是因为如果Scroll Rect对象少了Image组件,Mask就起不来作用,添加后解决

uGUI练习(六) Drag And Drop

一.相关组件 EventTrigger Canvas Group ScrollRect Mask Scrollbar 二.拖放练习 1.创建一个Panel,命名Panel1,添加EventTrigger组件,稍稍改一下Panel的颜色 2.Panel1下创建一个Text,输入"Test Draggable\n       object",设置字体颜色及Text超出处理 3.在 uGUI练习(四) Draggable Object一文中,已经大概了解uGUI的EventSystem,需要