Unity实现滑页嵌套(解决ScrollRect嵌套冲突问题)
简介
由于项目需要+有网友咨询,所以做了个横向滑页+某一横向滑页中有竖向滑页的demo,实现有点绕弯子,但基本功能还是比较完善,发上来共享一下。
效果
思路
第一步的思路是自己判断触屏拖动位置,然后控制界面横向或者纵向滑动。
然后,
由于UGUI组件重叠时会屏蔽事件
比如Button会屏蔽掉PointerDown
(PS:当然也可以采取继承UGUI组件的方式释放屏蔽事件,
这里对UGUI源码不熟,采取自己写一个事件分发器方便一点)
项目配置
这里就不赘述咯,我的前一篇blog有详细配置说明:
1.首先建立两个ScrollRect
2.分别给两个ScrollRect配置格子的ScrollBar,然后关掉以下设置
3.在最外层的ScrollRect配置ScrollControl代码
(PS:代码后续给出)
4.配置InputControl
(PS:新建一个Gameobjct就可以咯,也可以挂在已有物体上)
5.运行,检查效果...
代码
代码写的比较急,很多不规范的地方,使用者请看懂逻辑之后自行重构,直接使用者有坑勿怪
InputControl
using UnityEngine;
public delegate void MouseDownEvent(Vector2 mousePosition);
public delegate void MouseUpEvent(Vector2 mousePosition);
public delegate void MouseDragEvent(Vector2 dragVector);
public delegate void MouseClickEvent(Vector2 mousePosition);
public class InputControl : MonoBehaviour
{
private static InputControl mInstance;
/// <summary>
/// 逗比单例模式
/// </summary>
public static InputControl Instance
{
get
{
return mInstance;
}
}
private bool isPress;
private bool isClick;
private bool tempPress;
private Vector2 oldMousePosition;
private Vector2 tempMousePosition;
public event MouseDownEvent EVENT_MOUSE_DOWN;
public event MouseUpEvent EVENT_MOUSE_UP;
public event MouseDragEvent EVENT_MOUSE_DRAG;
public event MouseClickEvent EVENT_MOUSE_CLICK;
/// <summary>
/// 拖动起始判断参数,可自行更改
/// </summary>
public const float JUDGE_DISTANCE = 1F;
void Awake()
{
mInstance = this;
//以下代码可优化
EVENT_MOUSE_DOWN += AvoidEmpty;
EVENT_MOUSE_UP += AvoidEmpty;
EVENT_MOUSE_DRAG += AvoidEmpty;
EVENT_MOUSE_CLICK += AvoidEmpty;
}
void Start()
{
isPress = false;
isClick = false;
}
/// <summary>
/// 防空保护函数,无用处,可自行优化
/// </summary>
/// <param name="noUse"></param>
private void AvoidEmpty(Vector2 noUse) { }
void Update()
{
tempPress = Input.GetMouseButton(0);
tempMousePosition = Input.mousePosition;
// 两次状态不同,触发点击和抬起事件
if (tempPress != isPress)
{
// 按下事件
if (tempPress)
{
isClick = true;
EVENT_MOUSE_DOWN(tempMousePosition);
}
// 抬起事件
else
{
EVENT_MOUSE_UP(tempMousePosition);
// 点击事件
if (isClick)
{
EVENT_MOUSE_CLICK(tempMousePosition);
}
isClick = false;
}
}
// 按下的过程中发生了移动,发生事件变化
else if (isClick && JudgeMove(oldMousePosition, tempMousePosition))
{
isClick = false;
}
// 拖动事件
else if (tempPress && !isClick)
{
EVENT_MOUSE_DRAG(tempMousePosition - oldMousePosition);
}
isPress = tempPress;
oldMousePosition = tempMousePosition;
}
/// <summary>
/// 判断是否超出静止范围,用static速度更快
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <returns></returns>
private static bool JudgeMove(Vector2 p1, Vector2 p2)
{
return Mathf.Abs(p1.x - p2.x) > JUDGE_DISTANCE || Mathf.Abs(p1.y - p2.y) > JUDGE_DISTANCE;
}
}
ScrollControl
using UnityEngine;
using UnityEngine.UI;
public class ScrollControl : MonoBehaviour
{
/// <summary>
/// 横向滚动条
/// </summary>
public Scrollbar m_HScrollBar;
/// <summary>
/// 竖向滚动条
/// </summary>
public Scrollbar[] m_VScrollBars;
/// <summary>
/// 有竖向滚动的页面
/// </summary>
public int[] m_VScrollIndexs;
/// <summary>
/// 页面个数
/// </summary>
public int m_Num;
/// <summary>
/// 设置移动超过多少百分比之后向下翻页
/// </summary>
public float m_NextLimit;
/// <summary>
/// 滑动敏感值
/// </summary>
public float m_Sensitive;
/// <summary>
/// 鼠标上一次的位置
/// </summary>
private Vector3 mOldPosition;
/// <summary>
/// 记录上一次的value
/// </summary>
private float mOldValue;
private float mTargetPosition = 0.5f;
private int mCurrentIndex = 3;
private int mTargetIndex = 3;
/// <summary>
/// 是否可以移动
/// </summary>
private bool mCanMove = false;
/// <summary>
/// 初始移动速度
/// </summary>
private float mMoveSpeed;
/// <summary>
/// 平滑移动参数
/// </summary>
private const float SMOOTH_TIME = 0.2F;
private float mDragParam = 0;
private float mPageWidth = 0;
/// <summary>
/// 是否需要进行滑动方向判定
/// </summary>
private bool mNeedCaculate = false;
/// <summary>
/// 是否进行竖向滚动
/// </summary>
private bool mIsScollV = false;
/// <summary>
/// 竖向临时滚动条
/// </summary>
private Scrollbar mVScrollBar;
public void SetNextIndex(int pIndex)
{
mTargetIndex = pIndex;
mTargetPosition = (mTargetIndex - 1) * mPageWidth;
mIsScollV = false;
mCanMove = true;
}
private void OnPointerDown(Vector2 mousePosition)
{
// 记录当前value
mOldValue = m_HScrollBar.value;
mOldPosition = Input.mousePosition;
// mCanMove = false;
mCurrentIndex = GetCurrentIndex(mOldValue);
// 判断当前是否在可竖向滑动的页面上
for (int i = 0; i < m_VScrollIndexs.Length; ++i)
{
if (m_VScrollIndexs[i] == mCurrentIndex)
{
mNeedCaculate = true;
mVScrollBar = m_VScrollBars[i];
break;
}
}
}
private void OnDrag(Vector2 mousePosition)
{
Vector2 dragVector = Input.mousePosition - mOldPosition;
if (mNeedCaculate)
{
mNeedCaculate = false;
if (Mathf.Abs(dragVector.x) > Mathf.Abs(dragVector.y))
{
mIsScollV = false;
}
else
{
mIsScollV = true;
}
}
DragScreen(dragVector);
mOldPosition = Input.mousePosition;
}
private void OnPointerUp(Vector2 mousePosition)
{
Vector2 dragVector = Input.mousePosition - mOldPosition;
DragScreen(dragVector);
mOldPosition = Input.mousePosition;
float valueOffset = m_HScrollBar.value - mOldValue;
if (Mathf.Abs((valueOffset) / mPageWidth) > m_NextLimit)
{
mTargetIndex += valueOffset > 0 ? 1 : -1;
mTargetPosition = (mTargetIndex - 1) * mPageWidth;
}
mCanMove = true;
}
private int GetCurrentIndex(float pCurrentValue)
{
return Mathf.RoundToInt(pCurrentValue / mPageWidth + 1);
}
private void DragScreen(Vector2 pDragVector)
{
if (mIsScollV)
{
float oldValue = mVScrollBar.value;
mVScrollBar.value -= pDragVector.y / Screen.height * mVScrollBar.size;
mMoveSpeed = mVScrollBar.value - oldValue;
}
else
{
float oldValue = m_HScrollBar.value;
m_HScrollBar.value -= pDragVector.x / Screen.width * mDragParam;
mMoveSpeed = m_HScrollBar.value - oldValue;
}
}
void Awake()
{
if (m_Num <= 1)
{
Debug.LogError("参数错误:页面个数不对");
}
mDragParam = 1f / (m_Num - 1) * m_Sensitive;
mPageWidth = 1f / (m_Num - 1);
mCurrentIndex = GetCurrentIndex(m_HScrollBar.value);
mTargetIndex = mCurrentIndex;
}
void Start()
{
InputControl.Instance.EVENT_MOUSE_DOWN += OnPointerDown;
InputControl.Instance.EVENT_MOUSE_UP += OnPointerUp;
InputControl.Instance.EVENT_MOUSE_DRAG += OnDrag;
}
void OnDestory()
{
InputControl.Instance.EVENT_MOUSE_DOWN -= OnPointerDown;
InputControl.Instance.EVENT_MOUSE_UP -= OnPointerUp;
InputControl.Instance.EVENT_MOUSE_DRAG -= OnDrag;
}
void Update()
{
if (mCanMove)
{
if (mIsScollV)
{
mVScrollBar.value += mMoveSpeed;
float absValue = Mathf.Abs(mMoveSpeed);
absValue -= 0.001f;
if (absValue <= 0)
{
mCanMove = false;
}
else
{
mMoveSpeed = mMoveSpeed > 0 ? absValue : -absValue;
}
}
else
{
if (Mathf.Abs(m_HScrollBar.value - mTargetPosition) < 0.01f)
{
m_HScrollBar.value = mTargetPosition;
mCurrentIndex = mTargetIndex;
mCanMove = false;
return;
}
m_HScrollBar.value = Mathf.SmoothDamp(m_HScrollBar.value, mTargetPosition, ref mMoveSpeed, SMOOTH_TIME);
}
}
}
}
总结
目前来看效果还可以,两种滑动无干扰,有简单的阻尼滑动效果,滑动分页界限可以设置
其他若有什么问题,欢迎留言
Unity实现滑页嵌套(解决ScrollRect嵌套冲突问题)的更多相关文章
- Unity实现滑页效果(UGUI)
简介 项目需要...直接展示效果吧: 原理 使用UGUI提供的ScrollRect和ScrollBar组件实现基本滑动以及自己控制每次移动一页来达到滑页的效果. 实现过程 1.创建两个panel,上面 ...
- unity 解决ScrollRect嵌套滚动问题
在子级有ScrollRect组件的对象添加以下脚本: using UnityEngine; using System.Collections; using UnityEngine.UI; using ...
- 解决ScrollView嵌套ViewPager出现的滑动冲突问题
/** * 解决ScrollView嵌套ViewPager出现的滑动冲突问题 */ public class ScrollView1 extends ...
- Android ScrollView 嵌套 ListView、 ListView 嵌套ScrollView Scroll事件冲突解决办法
本人菜鸟一名,最近工作了,开始学习Android. 最近在做项目的时候,UX给了个design,大概就是下拉刷新的ListView中嵌套了ScrollView,而且还要在ScrollView中添加动画 ...
- 解决ScrollView中嵌套ListView滚动效果冲突问题
在ScrollView中嵌套使用ListView,ListView只会显示一行到两行的数据.起初我以为是样式的问题,一直在对XML文件的样 式进行尝试性设置,但始终得不到想要的效果.后来在网上查了查, ...
- 解决ScrollView嵌套RecyclerView的显示及滑动问题
项目中时常需要实现在ScrollView中嵌入一个或多个RecyclerView.这一做法通常会导致如下几个问题 页面滑动卡顿 ScrollView高度显示不正常 RecyclerView内容 ...
- Android在开发中的使用技巧之解决ScrollView嵌套RecyclerView出现的系列问题
根据已上线的app里总结出来的实用小技巧 相信大家都遇到过ScrollView嵌套RecyclerView或者RecyclerView嵌套RecyclerView来使用, 也会遇到一堆奇奇怪怪的问题, ...
- Android——MeasureSpec学习 - 解决ScrollView嵌套ListView和GridView冲突的方法
原文地址:http://blog.csdn.net/yuhailong626/article/details/20639217 在自定义View和ViewGroup的时候,我们经常会遇到int ...
- dede频道页实现三级栏目嵌套调用文章
dede频道页实现三级栏目嵌套调用文章: //支持arclist标签开始--> $typeid = $row['id']; if((class_exists('PartView'))) { ...
随机推荐
- .NET Core 跨平台发布(dotnet publish)
.NET Core 跨平台发布(dotnet publish) ,无需安装.NET Core SDK,就可以运行. 前面讲解了.NET Core 的VSCode 开发.现在来讲讲发布(dotnet p ...
- Hadoop学习笔记—19.Flume框架学习
START:Flume是Cloudera提供的一个高可用的.高可靠的开源分布式海量日志收集系统,日志数据可以经过Flume流向需要存储终端目的地.这里的日志是一个统称,泛指文件.操作记录等许多数据. ...
- 如何给CentOS安装字体库
很多时候,我们需要做一些图像生成工作(譬如验证码之类的),这时候,我们一般都需要用到系统的字体库.但事情却总非尽善人意,我们所使用的Linux操作系统无法像Windows操作系统那样足够“旗舰”,字体 ...
- 我如何介绍 Microservice
这篇文章转自我的 Github blog 一天我司招财猫姐(HR 大人)问我,你给我解释一下 Microservice 是什么吧.故成此文.一切都是从一个创业公司开始的. 故事 最近的创业潮非常火爆, ...
- SQL Server 数据库子查询基本语法
一.SQL子查询语句 1.单行子查询 select ename,deptno,sal from emp where deptno=(select deptno ...
- SQL Server中的窗口函数
简介 SQL Server 2012之后对窗口函数进行了极大的加强,但对于很多开发人员来说,对窗口函数却不甚了解,导致了这样强大的功能被浪费,因此本篇文章主要谈一谈SQL Server中窗口函 ...
- c#写windows服务
序言 前段时间做一个数据迁移项目,刚开始用B/S架构做的项目,但B/S要寄存在IIs中,而IIs又不稳定因素,如果重启IIs就要打开页面才能运行项目.有不便之处,就改用Windows服务实现.这篇就总 ...
- [WPF]带下拉列表的文本框
控件我已经弄好了,代码比较多,所以没办法全面介绍. 一开始我是直接继承Selector类来实现,做是做出来了,不过发现性能不太好.于是,我就想着自己来实现.毕竟我是做给自己用的,也不考虑过多的东西,也 ...
- Android随笔之——Android广播机制Broadcast详解
在Android中,有一些操作完成以后,会发送广播,比如说发出一条短信,或打出一个电话,如果某个程序接收了这个广播,就会做相应的处理.这个广播跟我们传统意义中的电台广播有些相似之处.之所以叫做广播,就 ...
- Connect(); // 2015 简要整理
去年 Connect(); 2014 Visual Studio Contact(); 直播笔记 对于我个人来说,今年 Connect(); 的三个重要发布: ASP.NET 5 RC1 Entity ...