FishPlayer

一个喜欢摸鱼的废物

0%

Unity 自制 Scrollrect 小坑

问题出现

终于改来改去,俺做的这个循环滚动列表成功运用到了项目里的仓库UI上。但是还是被一个BUG给击垮了。

UX给到的设计稿是当玩家鼠标在其中一个物品上时,要有一个小弹窗显示这个物品的一些讯息。
BUG的表现是当我已经’选中’一个物品后,用鼠标滚轮滚到下一行,小弹窗显示的还是上一个物品的讯息。

BUG原因

我在UI脚本中写了关于鼠标移动进入和离开的处理,但其实当列表滚动时候,鼠标下面的物体还是上一个物体,但是物体内的数据已经改变,却没有刷新。

解决方案

其实也还算有个凑合的解决方案。导师之前重写了InputModule,所以我们决定在这边做改动。
当发生滚动时,我们需要重新做raycast。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void OnScrollWheel(InputAction.CallbackContext context)
{
if (IsActive())
{
PointerEventData eventData = GetPointerData();
eventData.button = PointerEventData.InputButton.Middle;
eventData.Reset();
eventData.scrollDelta = context.ReadValue<Vector2>()
GameObject testScrollObject = ExecuteEventExecuteHierarchy(eventData.pointerCurrentRaycasgameObject, eventData, ExecuteEvents.scrollHandler)
if (testScrollObject != null)
{
// to re-do the reycast cuz we may scroll a recyclscrollrect
HandlePointerExitAndEnter(eventData, null);
m_rayCastDelayFrame = SCROLL_RAYCAST_DELAY;
// SCROLL_RAYCAST_DELAY =3 or 5, depends....
}
}
}

我们先清楚了事件数据所认为的鼠标悬停的物体,然后过几帧再重新发射射线进行检测。
因为我的循环滚动列表依赖于Unity自带的滚动视图,并且其位置也是在LateUpdate中更新的,所以我们最好在下一帧或者接下来的几帧后再做射线检测。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

// will call in update
public override void Process()
{
/*
.....
*/
CheckAndDoDelayRaycast();
}

void CheckAndDoDelayRaycast()
{
if (m_rayCastDelayFrame < 0)
{
return;

if (--m_rayCastDelayFrame == 0)
{
var eventData = GetPointerData();
eventSystem.RaycastAll(eventData, m_RaycastResultCache);
var firstRaycast = FindFirstRaycast(m_RaycastResultCache)
eventData.pointerCurrentRaycast = firstRaycast;
m_RaycastResultCache.Clear()
var temp = eventData.pointerCurrentRaycast.gameObject;
HandlePointerExitAndEnter(eventData, temp);
m_rayCastDelayFrame = -1;
}
}