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'))) { ...
随机推荐
- SQL SERVER全面优化-------写出好语句是习惯
前几篇文章已经从整体提供了诊断数据库的各个方面问题的基本思路...也许对你很有用,也许你觉得离自己太远.那么今天我们从语句的一些优化写法及一些简单优化方法做一个介绍.这对于很多开发人员来说还是很有用的 ...
- Code First开发系列之数据库迁移
返回<8天掌握EF的Code First开发>总目录 本篇目录 开启并运行迁移 使用迁移API 应用迁移 给已存在的数据库添加迁移 EF的其他功能 本章小结 自我测试 本系列的源码本人已托 ...
- Redis性能问题排查解决手册(七)
阅读目录: 性能相关的数据指标 内存使用率used_memory 命令处理总数total_commands_processed 延迟时间 内存碎片率 回收key 总结 性能相关的数据指标 通过Red ...
- ARM的常数表达式
ARM的常数表达式 如果说Intel指令中的立即数,相信大家都很熟悉.类似的,Arm指令中的“立即数”就是常数表达式.之所以称为常数表达式,而不称为立即数是有原因的. Intel指令属于CISC指 ...
- TODO:小程序开发环境搭建
TODO:小程序开发环境搭建 1.第一步当然是要先注册小程序了 2.登录到小程序 a)完善小程序信息,如名称,图标,描述 3.绑定开发者 4.获取AppID,并设置服务器信息 5.下载并安装开发者工具 ...
- 一个上好的C# http/https类
直接Copy拿去用吧: 新的 tls 协议需要新的.net版本, tls 至少更新到.net4吧,尽量用最新的.net! 不然出错了就折腾... using System; using System. ...
- salesforce 零基础学习(四十三)运算取余
工作中遇到一个简单的小问题,判断两个数是否整除,如果不整除,获取相关的余数. 习惯java的我毫不犹豫的写下了代码 public Boolean isDivisibility(Integer divi ...
- 在drawable 画胶囊状
<solid android:color="@color/colorAccent"></solid> <corners android:radius= ...
- 高德地图-搜索服务-POI搜索
高德地图-搜索服务-POI搜索 之前公司项目收货地址仿饿了么的收货地址,结果发现自己实现的关键字搜索和周边搜索,搜索到的poi列表跟饿了么的并不完全一样,后来考虑了下,应该是搜索的范围.类型之类的设置 ...
- Spill data to tempdb
查看Execution Plan时,在Sort Operator上,发现一个Warning:Operator used tempdb to spill data during execution wi ...