Unity UGUI ScrollRect嵌套及事件被拦截问题

ScrollRect横竖嵌套滑动

问题描述

常规ScrollRect滑动行为是由用户滑动事件触发的,在嵌套ScrollRect时,滑动事件被二级ScrollRect触发并劫持而不会再向上级ScrollRect传递,这样就会造成只有二级ScrollRect响应事件而顶级ScrollRect无响应

解决思路

为了解决这一问题我们需要重写ScrollRect对象的OnBeginDrag、OnDrag、OnEndDrag方法,在执行方法时检测滑动方向,如果滑动方向与当前ScrollRect预设的方向不相符则事件向上传递,如若滑动方向与当前ScrollRect的预设方向一样则在本层ScrollRect响应事件

代码

重写ScrollRect命名为MyScrollRect,具体逻辑如下

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class MyScrollRect : ScrollRect
{
    //上层ScrollRect
    private ScrollRect upperScroll;

    //方向
    private enum Direction
    {
        Horizontal,
        Vertical
    }
    //预设滑动方向
    private Direction dir;
    //当前操作方向
    private Direction dragDir;

	protected override void Awake()
	{
        //找到父对象
        Transform parent = transform.parent;
        if(parent){
            upperScroll = parent.GetComponentInParent<ScrollRect>();
        }
        if (horizontal&&vertical)
        {
            vertical = false;
            Debug.LogWarning("不能同时选择Horizontal和Vertical,同时选择时默认仅Horizontal");
        }
        dir = horizontal ? Direction.Horizontal : Direction.Vertical;
        base.Awake();
	}


	public override void OnBeginDrag(PointerEventData eventData)
	{
        if(upperScroll){
            //判断手势方向
            dragDir = Mathf.Abs(eventData.delta.x) > Mathf.Abs(eventData.delta.y) ? Direction.Horizontal : Direction.Vertical;
            if(dragDir != dir){//当前滑动方向不等于ScrollRect预设方向,故执行上层ScrollRect事件
                upperScroll.OnBeginDrag(eventData);
                return;
            }
        }
        base.OnBeginDrag(eventData);
	}
	public override void OnDrag(PointerEventData eventData)
	{
        if (upperScroll) {
            if (dragDir != dir){//当前滑动方向不等于ScrollRect预设方向,故执行上层ScrollRect事件
                upperScroll.OnDrag(eventData);
                return;
            }
        }
        base.OnDrag(eventData);
	}

	public override void OnEndDrag(PointerEventData eventData)
	{
        if (upperScroll){
            if (dragDir != dir){//当前滑动方向不等于ScrollRect预设方向,故执行上层ScrollRect事件
                upperScroll.OnEndDrag(eventData);
                return;
            }
        }
        base.OnEndDrag(eventData);
	}
	
    public override void OnScroll(PointerEventData data)
	{
        if (upperScroll){
            if (dragDir != dir){//当前滑动方向不等于ScrollRect预设方向,故执行上层ScrollRect事件
                upperScroll.OnScroll(data);
                return;
            }
        }
        base.OnScroll(data);
	}
}

使用时只需要用MyScrollRect替换ScrollRect即可

ScrollRect滑动事件被其他UI事件拦截

问题描述

最近有项目需求:一个用ScrollRect做的滑动列表,列表中包含多个InputField组件,测试过程中发现当我们滑动列表时如果初始位置是在InputField物体上则ScrollRect滑动事件被InputField给拦截,造成ScrollRect无法滑动的现象

解决思路

其实这个问题和上面的嵌套问题类似,都是二级UI劫持顶级ScrollRect事件的问题,那么解决思路也是雷同的,直接重写拦截事件的UI物体身上的的OnBeginDrag、OnDrag、OnEndDrag方法即可,检测到这些事件之后传递给相应的父ScrollRect即可

代码

创建ScrollChild类,这个类继承自MonoBehaviour,并且继承接口IDragHandler, IBeginDragHandler, IEndDragHandler,用来检测自身拖动事件,具体逻辑如下


using System;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class ScrollChild : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler
{
    private ScrollRect upperscroll;

    private void Awake()
    {
        Transform parent = transform.parent;
        if (parent)
        {
            upperscroll = parent.GetComponentInParent<ScrollRect>();
        }
    }

    /// <summary>
    /// 开始拖拽
    /// </summary>
    /// <param name="eventData"></param>

    public void OnBeginDrag(PointerEventData eventData)
    {
        if (upperscroll != null)
        {
            upperscroll.OnBeginDrag(eventData); 
        }
    }

    public void OnDrag(PointerEventData eventData)
    {
        if (upperscroll != null)
        {
            upperscroll.OnDrag(eventData);
        }

        
    }

    /// <summary>
    /// 结束拖拽
    /// </summary>
    /// <param name="eventData"></param>
    public void OnEndDrag(PointerEventData eventData)
    {
        if (upperscroll != null)
        {
            upperscroll.OnEndDrag(eventData);
        }
    }
}


使用时只需要把ScrollChild挂载在InputField(遮挡ScrollRect事件的UI物体)身上即可

工程源码下载

Demo下载

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

司军礼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值