做网站能赚钱么,用wordpress搭建知名网站,wordpress的polylang,怎么找网红合作卖东西Unity3D 解决 UI 嵌套滚动视图滑动问题。
嵌套滚动视图
滑动问题
在游戏开发中#xff0c;我们常常会遇到一种情况#xff0c;在一个滚动视图列表中#xff0c;每个 item 还包含了一个内嵌的滚动视图。
这样#xff0c;当我们在滑动外层的滚动视图时#xff0c;如果点…Unity3D 解决 UI 嵌套滚动视图滑动问题。
嵌套滚动视图
滑动问题
在游戏开发中我们常常会遇到一种情况在一个滚动视图列表中每个 item 还包含了一个内嵌的滚动视图。
这样当我们在滑动外层的滚动视图时如果点击位置在内嵌的滚动视图上很可能滑不动内外层滚动视图的滑动事件出现了冲突。
如下图所示点击位置在奖励文本上时是可以正常滑动的。但是点击位置在奖励列表时滑动方向变成了左右而不是期望的上下滑动。 解决方案
通常的解决方案是根据拖拽的增量判断滑动的方向如果方向与内层的方向相同则优先滑动内层如果方向不同则传递滑动事件给外层的滚动视图。
为此我们创建一个脚本 CustomScrollRect.cs继承 ScrollRect并重写它的一些方法。
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;public class CustomScrollRect : ScrollRect
{protected override void Awake(){base.Awake();}public override void OnBeginDrag(PointerEventData eventData){base.OnBeginDrag(eventData);}public override void OnDrag(PointerEventData eventData){base.OnDrag(eventData);}public override void OnEndDrag(PointerEventData eventData){base.OnEndDrag(eventData);}public override void OnScroll(PointerEventData eventData){base.OnScroll(eventData);}
}首先在 Awake 中获取父节点的 CustomScrollRect 组件。
这里使用的 GetComponentInParent会从当前节点开始查找递归遍历其父节点。
所以要从 transform.parent 开始遍历避免获取到自己身上的 CustomScrollRect 组件。
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;public class CustomScrollRect : ScrollRect
{CustomScrollRect parent;protected override void Awake(){base.Awake();if (parent null){parent transform.parent.GetComponentInParentCustomScrollRect();}}// ...
}同时在类内部定义一个方向枚举在 Awake 时记录当前的方向。
这里仅判断是水平还是垂直通常不会有两个方向都能滑动的情况。
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;public class CustomScrollRect : ScrollRect
{CustomScrollRect parent;enum Direction{horizontal,vertical}Direction curDirection;Direction dragDirection;protected override void Awake(){base.Awake();if (parent null){parent transform.parent.GetComponentInParentCustomScrollRect();}curDirection horizontal ? Direction.horizontal : Direction.vertical;}// ..
}然后在开始拖拽时根据 eventData.delta 的 x 和 y 变量增幅哪个较大判断滑动的方向。
当拖拽的方向和当前方向不同且有外层滚动视图时把 beginDragHandler 传递给外层如果不符合条件则执行自身的 OnBeginDrag 事件。
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;public class CustomScrollRect : ScrollRect
{// ...public override void OnBeginDrag(PointerEventData eventData){// 判断拖拽的方向dragDirection Mathf.Abs(eventData.delta.x) Mathf.Abs(eventData.delta.y)? Direction.horizontal : Direction.vertical;// 拖拽的方向和当前方向不同且有外层滚动视图if (dragDirection ! curDirection parent ! null){// 把 beginDragHandler 传递给外层ExecuteEvents.Execute(parent.gameObject, eventData,ExecuteEvents.beginDragHandler);// 不执行自身的 OnBeginDrag 事件return;}// 执行自身的 OnBeginDrag 事件base.OnBeginDrag(eventData);}
}依此类推在其他方法中也加上这样的判断dragDirection 可以仅在开始拖拽时赋值。
需要注意的是
OnBeginDrag 方法传递的事件是 beginDragHandlerOnDrag 方法传递的事件是 dragHandlerOnEndDrag 方法传递的事件是 endDragHandlerOnScroll 方法传递的事件是 scrollHandler
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;public class CustomScrollRect : ScrollRect
{// ...public override void OnDrag(PointerEventData eventData){if (dragDirection ! curDirection parent ! null){ExecuteEvents.Execute(parent.gameObject, eventData,ExecuteEvents.dragHandler);return;}base.OnDrag(eventData);}public override void OnEndDrag(PointerEventData eventData){if (dragDirection ! curDirection parent ! null){ExecuteEvents.Execute(parent.gameObject, eventData,ExecuteEvents.endDragHandler);return;}base.OnEndDrag(eventData);}public override void OnScroll(PointerEventData eventData){if (dragDirection ! curDirection parent ! null){ExecuteEvents.Execute(parent.gameObject, eventData,ExecuteEvents.scrollHandler);return;}base.OnScroll(eventData);}
}使用说明
移除掉原来的 ScrollRect 组件换上 CustomScrollRect 组件。
记得要拖拽 Viewport 和 Content 节点。
内外层滚动视图都需要换上 CustomScrollRect 组件。 最终效果如图 完整代码
CustomScrollRect.cs
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;public class CustomScrollRect : ScrollRect
{CustomScrollRect parent;enum Direction{horizontal,vertical}Direction curDirection;Direction dragDirection;protected override void Awake(){base.Awake();if (parent null){parent transform.parent.GetComponentInParentCustomScrollRect();}curDirection horizontal ? Direction.horizontal : Direction.vertical;}public override void OnBeginDrag(PointerEventData eventData){// 判断拖拽的方向dragDirection Mathf.Abs(eventData.delta.x) Mathf.Abs(eventData.delta.y)? Direction.horizontal : Direction.vertical;// 拖拽的方向和当前方向不同且有外层滚动视图if (dragDirection ! curDirection parent ! null){// 把 beginDragHandler 传递给外层ExecuteEvents.Execute(parent.gameObject, eventData,ExecuteEvents.beginDragHandler);// 不执行自身的 OnBeginDrag 事件return;}// 执行自身的 OnBeginDrag 事件base.OnBeginDrag(eventData);}public override void OnDrag(PointerEventData eventData){if (dragDirection ! curDirection parent ! null){ExecuteEvents.Execute(parent.gameObject, eventData,ExecuteEvents.dragHandler);return;}base.OnDrag(eventData);}public override void OnEndDrag(PointerEventData eventData){if (dragDirection ! curDirection parent ! null){ExecuteEvents.Execute(parent.gameObject, eventData,ExecuteEvents.endDragHandler);return;}base.OnEndDrag(eventData);}public override void OnScroll(PointerEventData eventData){if (dragDirection ! curDirection parent ! null){ExecuteEvents.Execute(parent.gameObject, eventData,ExecuteEvents.scrollHandler);return;}base.OnScroll(eventData);}
}