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'))) { ...
随机推荐
- EasyPR--开发详解(3)高斯模糊、灰度化和Sobel算子
在上篇文章中我们了解了PlateLocate的过程中的所有步骤.在本篇文章中我们对前3个步骤,分别是高斯模糊.灰度化和Sobel算子进行分析. 一.高斯模糊 1.目标 对图像去噪,为边缘检测算法做准备 ...
- 在Visual Studio上开发Node.js程序
[题外话] 最近准备用Node.js做些东西,于是找找看能否有Visual Studio上的插件以方便开发.结果还真找到了一个,来自微软的Node.js Tools for Visual Studio ...
- Tomcat7基于Redis的Session共享实战一
本文主要介绍如何使用redis对tomcat7的session进行托管. 1.安装Redisredis安装比较简单,此处略过. 2.配置两个Tomcat在本机上配置两个Tomcat,分别为tomcat ...
- js array queue (队列)
前言 今天项目中做一个图片效果展示,需要实时从后台获取图片数据,前段做展示.想想用到队列,比较好实现这个功能,只需要展示队列里的数据就可以了.于是写了个js 对列. js code /** * [Qu ...
- Windows内网渗透提权的几个实用命令
1.获取操作系统信息 查看所有环境变量:set 识别系统体系结构:echo %PROCESSOR_ARCHITECTURE% AMD64 识别操作系统名称及版本:systeminfo 查看某特定用户 ...
- JAVA集合
为了保存数量不确定的数据或者提供映射关系的数据,Java提供了集合类,也称作集合类,Collection和Map分别为两个根接口.两个接口体系的继承系如下图 (图片来源于网络) Collection接 ...
- UITableView 一直显示滚动条(ScrollBar Indicators)、滚动条Width(宽度)、滚动条Color(颜色)
在 IOS 中,对 UIScrollView 的滚动条(ScrollBar Indicators)的自定义设置接口,一直都是很少的.除了能自定义简单的样式(UIScrollViewIndicatorS ...
- Sql Server系列:排序函数
在SQL Server中有4个排序函数:ROW_NUMBER().RANK().DENSE_RANK()及NTILE()函数. 1. ROW_NUMBER()函数 ROW_NUMBER()函数为每条记 ...
- XenServer pool 移除server 设置master
如果因为Pool中Master主机由于某种原因导致失效,会引起整个Pool进入紧急模式,恢复步骤如下: 在成员服务器上输入如下命令 # xe host-emergency-ha-disable ...
- MVC4做网站后台:用户管理 ——用户组
用户管理这块包含用户和用户组两部分. 用户组包括浏览 用户组列表,添加.修改.删除用户组等.按照前面思路系统是依据用户组来判断用户权限的,用户组的最主要目的是划分权限.权限这块以后单独在做. 下面实现 ...