当前位置: 首页 > news >正文

Unity3D UI 嵌套滚动视图

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.GetComponentInParent<CustomScrollRect>();}}// ...
}

同时,在类内部定义一个方向枚举,在 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.GetComponentInParent<CustomScrollRect>();}curDirection = horizontal ? Direction.horizontal : Direction.vertical;}// ..
}

然后在开始拖拽时,根据 eventData.deltaxy 变量增幅哪个较大,判断滑动的方向。

当拖拽的方向和当前方向不同,且有外层滚动视图时,把 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 方法传递的事件是 beginDragHandler
  • OnDrag 方法传递的事件是 dragHandler
  • OnEndDrag 方法传递的事件是 endDragHandler
  • OnScroll 方法传递的事件是 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.GetComponentInParent<CustomScrollRect>();}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);}
}

相关文章:

Unity3D UI 嵌套滚动视图

Unity3D 解决 UI 嵌套滚动视图滑动问题。 嵌套滚动视图 滑动问题 在游戏开发中&#xff0c;我们常常会遇到一种情况&#xff0c;在一个滚动视图列表中&#xff0c;每个 item 还包含了一个内嵌的滚动视图。 这样&#xff0c;当我们在滑动外层的滚动视图时&#xff0c;如果点…...

你还没有将 Siri 接入GPT对话功能吗?

由于各种原因&#xff0c;国内ios用户目前无缘自带 AI 功能&#xff0c;但是这并不代表国内 ios 无法接入 AI 功能&#xff0c;接下来手把手带你为iPhone siri 接入 gpt 对话功能。 siri 接入 chatGPT 暂时还无法下载 ChatGPT app&#xff0c;或者没有账号的读者可以直接跳到…...

_C#_串口助手_字符串拼接缺失问题(未知原理)

最近使用WPF开发串口助手时&#xff0c;遇到一个很奇怪的问题&#xff0c;无论是主线程、异步还是多线程&#xff0c;当串口接收速度达到0.016s一次以上&#xff0c;就会发生字符串缺失问题并且很卡。而0.016s就一切如常&#xff0c;仿佛0.015s与0.016s是天堑之隔。 同一份代码…...

浅析大数据时代下的网络安全

一、大数据时代下网络安全的现状 在全球化进程不断深入发展的情况下&#xff0c;互联网行业发展速度也更加迅猛&#xff0c;人们对网络信息的需求量不断增加&#xff0c;所以目前已经进入了大数据时代。 随着计算机技术的不断发展&#xff0c;我国互联网网络规模、网民数量、…...

Mysql数据库基础篇笔记

目录 sql语句 DDL——数据库定义语言&#xff08;定义库&#xff0c;表&#xff0c;字段&#xff09; 数据库操作&#xff1a; 表操作&#xff1a; DML 增删改语句 DQL 语法编写顺序&#xff1a; 条件查询 DCL 用户管理&#xff1a; 权限管理&#xff1a; 函数 常见字符串内置函…...

rabbitmq原理及命令

目录 一、RabbitMQ原理1、交换机&#xff08;Exchange&#xff09;fanoutdirecttopicheaders&#xff08;很少用到&#xff09; 2、队列Queue3、Virtual Hosts4、基础对象 二、RabbitMQ的一些基本操作:1、用户管理2、用户角色3、vhost4、开启web管理接口5、批量删除队列 一、Ra…...

React进阶面试题(四)

React 的 reconciliation&#xff08;协调&#xff09;算法 Reconciliation是React的diff算法&#xff0c;用于比较更新前后的虚拟DOM树差异&#xff0c;从而使用最小的代价将原始DOM按照新的状态、属性进行更新。其目的是找出两棵树的差异&#xff0c;原生方式直接比较复杂度…...

24/12/1 算法笔记<强化学习> 创建Maze交互

我们今天制作一个栅格的游戏。 我们直接上代码教学。 1.载入库和查找相应的函数版本 import numpy as np import time import sysif sys.version_info.major 2:import Tkinter as tk else:import tkinter as tk 2.设置长宽和单元格大小 UNIT 40 MAZE_H 4 MAZE_W 4 3.初始…...

Linux驱动开发(10):I2C子系统–mpu6050驱动实验

本章我们以板载MPU6050为例讲解i2c驱动程序的编写&#xff0c;本章主要分为五部分内容。 第一部分&#xff0c;i2c基本知识&#xff0c;回忆i2c物理总线和基本通信协议。 第二部分&#xff0c;linux下的i2c驱动框架。 第三部分&#xff0c;i2c总线驱动代码拆解。 第四部分&a…...

《装甲车内气体检测“神器”:上海松柏 K-5S 电化学传感器模组详解》

《装甲车内气体检测“神器”:上海松柏 K-5S 电化学传感器模组详解》 一、引言二、K-5S 电化学传感器模组概述&#xff08;一&#xff09;产品简介&#xff08;二&#xff09;产品特点&#xff08;三&#xff09;产品适用场景 三、电化学传感器原理及优点&#xff08;一&#xf…...

如何将多个JS文件打包成一个JS文件?

文章目录 前言SDK 打包安装 webpack创建 webpack.config.js编译命令行遇到的坑点前言 上一篇已经记录了如何开发一个小游戏聚合SDK,既然是SDK,最终都是给外部人员使用的。调研了一下市面上的前端SDK,最终都是编译成一个 js 文件。我猜理由大概是 js 文件之间的调用都是需要…...

100个python经典面试题详解(新版)

应老粉要求,每晚加餐一个最新面试题 包括Python面试中常见的问题,涵盖列表、元组、字符串插值、比较操作符、装饰器、类与对象、函数调用方式、数据结构操作、序列化、数据处理函数等多个方面。 旨在帮助数据科学家和软件工程师准备面试或提升Python技能。 7、Python面试题…...

C#初阶概念理解

​​​​​​​ 梳理了一些本人在学习C#时的一些生疏点&#xff0c;同时也加深自己的印象。 堆&栈 堆用来存储程序运行时产生的变量&#xff0c;当程序结束时释放&#xff1b; 栈用来存储程序运行时&#xff0c;调用方法产生的临时变量&#xff0c;方法运行完成后就会释放…...

node.js基础学习-url模块-url地址处理(二)

前言 前面我们创建了一个HTTP服务器&#xff0c;如果只是简单的http://localhost:3000/about这种链接我们是可以处理的&#xff0c;但是实际运用中一般链接都会带参数&#xff0c;这样的话如果我们只是简单的判断链接来分配数据&#xff0c;就会报404找不到链接。为了解决这个问…...

算法与数据结构(1)

一&#xff1a;数据结构概论 数据结构分为初阶数据结构&#xff08;主要由C语言实现&#xff09;和高阶数据结构&#xff08;由C实现&#xff09; 初阶数据结构当中&#xff0c;我们会学到顺序表、链表、栈和队列、二叉树、常见排序算法等内容。 高阶数据结构当中&#xff0…...

FTP介绍与配置

前言&#xff1a; FTP是用来传送文件的协议。使用FTP实现远程文件传输的同时&#xff0c;还可以保证数据传输的可靠性和高效性。 介绍 FTP的应用 在企业网络中部署一台FTP服务器&#xff0c;将网络设备配置为FTP客户端&#xff0c;则可以使用FTP来备份或更新VRP文件和配置文件…...

SQL面试题——抖音SQL面试题 最近一笔有效订单

最近一笔有效订单 题目背景如下,现有订单表order,包含订单ID,订单时间,下单用户,当前订单是否有效 +---------+----------------------+----------+-----------+ | ord_id | ord_time | user_id | is_valid | +---------+----------------------+--------…...

【线程】Java多线程代码案例(1)

【线程】Java多线程代码案例&#xff08;1&#xff09; 一、“单例模式” 的实现1.1“饿汉模式”1.2 “懒汉模式”1.3 线程安全问题 二、“阻塞队列”的实现2.1阻塞队列2.2生产者消费者模型2.3 阻塞队列的实现2.4 再谈生产者消费者模型 一、“单例模式” 的实现 “单例模式”即…...

go使用mysql实现增删改查操作

1、安装MySQL驱动 go get -u github.com/go-sql-driver/mysql2、go连接MySQL import ("database/sql""log"_ "github.com/go-sql-driver/mysql" // 导入 mysql 驱动 )type Users struct {ID intName stringEmail string }var db *sql.DBfu…...

【Rust】unsafe rust入门

这篇文章简单介绍下unsafe rust的几个要点 1. 解引用裸指针 裸指针其实就是C或者说C的指针&#xff0c;与C的指针不同的是&#xff0c;Rust的裸指针还是要分为可变和不可变&#xff0c;*const T 和 *mut T&#xff1a; 基于引用创建裸指针 let mut num 5;let r1 &num …...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础

第三周 Day 3 &#x1f3af; 今日目标 理解类&#xff08;class&#xff09;和对象&#xff08;object&#xff09;的关系学会定义类的属性、方法和构造函数&#xff08;init&#xff09;掌握对象的创建与使用初识封装、继承和多态的基本概念&#xff08;预告&#xff09; &a…...

Python 高级应用10:在python 大型项目中 FastAPI 和 Django 的相互配合

无论是python&#xff0c;或者java 的大型项目中&#xff0c;都会涉及到 自身平台微服务之间的相互调用&#xff0c;以及和第三发平台的 接口对接&#xff0c;那在python 中是怎么实现的呢&#xff1f; 在 Python Web 开发中&#xff0c;FastAPI 和 Django 是两个重要但定位不…...

精益数据分析(98/126):电商转化率优化与网站性能的底层逻辑

精益数据分析&#xff08;98/126&#xff09;&#xff1a;电商转化率优化与网站性能的底层逻辑 在电子商务领域&#xff0c;转化率与网站性能是决定商业成败的核心指标。今天&#xff0c;我们将深入解析不同类型电商平台的转化率基准&#xff0c;探讨页面加载速度对用户行为的…...

统计学(第8版)——统计抽样学习笔记(考试用)

一、统计抽样的核心内容与问题 研究内容 从总体中科学抽取样本的方法利用样本数据推断总体特征&#xff08;均值、比率、总量&#xff09;控制抽样误差与非抽样误差 解决的核心问题 在成本约束下&#xff0c;用少量样本准确推断总体特征量化估计结果的可靠性&#xff08;置…...

npm安装electron下载太慢,导致报错

npm安装electron下载太慢&#xff0c;导致报错 背景 想学习electron框架做个桌面应用&#xff0c;卡在了安装依赖&#xff08;无语了&#xff09;。。。一开始以为node版本或者npm版本太低问题&#xff0c;调整版本后还是报错。偶尔执行install命令后&#xff0c;可以开始下载…...

AT模式下的全局锁冲突如何解决?

一、全局锁冲突解决方案 1. 业务层重试机制&#xff08;推荐方案&#xff09; Service public class OrderService {GlobalTransactionalRetryable(maxAttempts 3, backoff Backoff(delay 100))public void createOrder(OrderDTO order) {// 库存扣减&#xff08;自动加全…...