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'))) { ...
随机推荐
- Reactive Extensions介绍
Reactive Extensions(Rx)是对LINQ的一种扩展,他的目标是对异步的集合进行操作,也就是说,集合中的元素是异步填充的,比如说从Web或者云端获取数据然后对集合进行填充.Rx起源于M ...
- 分享基于Entity Framework的Repository模式设计(附源码)
关于Repository模式,在这篇文章中有介绍,Entity Framework返回IEnumerable还是IQueryable? 这篇文章介绍的是使用Entity Framework实现的Rep ...
- NodeJS写个爬虫,把文章放到kindle中阅读
这两天看了好几篇不错的文章,有的时候想把好的文章 down 下来放到 kindle 上看,便写了个爬虫脚本,因为最近都在搞 node,所以就很自然的选择 node 来爬咯- 本文地址:http://w ...
- 使用C#给Linux写Shell脚本(下篇)
在上篇的<使用C#给Linux写Shell脚本>结尾中,我们留下了一个关于C#如何调用BashShell的问题.在文章发布之后,我留意到有读者留言推荐使用“Pash”(一款类PowerSh ...
- [Unity][Heap sort]用Unity动态演示堆排序的过程(How Heap Sort Works)
[Unity][Heap sort]用Unity动态演示堆排序的过程 How Heap Sort Works 最近做了一个用Unity3D动态演示堆排序过程的程序. I've made this ap ...
- Objective-C三方库: ZXEasyCoding
对FastCoding做了二次封装, 实现更加便捷的存储和读取数据, 分享给大家 ZXEasyCoding 说明: 对FastCording进行封装, 更便捷存储和读取对象数据 安装: 添加ZXEas ...
- How To Install Proxmox Nested on VMware ESXi (Full Support OpenVZ & KVM)
https://imanudin.net/2015/03/04/how-to-install-proxmox-nested-on-vmware-esxi-full-support-openvz-kvm ...
- EL
- 简易版的TimSort排序算法
欢迎探讨,如有错误敬请指正 如需转载,请注明出处http://www.cnblogs.com/nullzx/ 1. 简易版本TimSort排序算法原理与实现 TimSort排序算法是Python和Ja ...
- CSS系列:CSS中盒子之间的关系
1. 标准文档流 标准文档流是值在不使用其他的雨排列和定位相关的特殊CSS规则时,各种元素的排列规则. 1.1 块级元素(block level) 块级元素不会排在同一行中,总是以一个块的形式表现出来 ...