当前位置: 首页 > 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 …...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

PHP和Node.js哪个更爽?

先说结论&#xff0c;rust完胜。 php&#xff1a;laravel&#xff0c;swoole&#xff0c;webman&#xff0c;最开始在苏宁的时候写了几年php&#xff0c;当时觉得php真的是世界上最好的语言&#xff0c;因为当初活在舒适圈里&#xff0c;不愿意跳出来&#xff0c;就好比当初活在…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

JDK 17 新特性

#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持&#xff0c;不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的&#xff…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...