简介

由于项目需要+有网友咨询,所以做了个横向滑页+某一横向滑页中有竖向滑页的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嵌套冲突问题)的更多相关文章

  1. Unity实现滑页效果(UGUI)

    简介 项目需要...直接展示效果吧: 原理 使用UGUI提供的ScrollRect和ScrollBar组件实现基本滑动以及自己控制每次移动一页来达到滑页的效果. 实现过程 1.创建两个panel,上面 ...

  2. unity 解决ScrollRect嵌套滚动问题

    在子级有ScrollRect组件的对象添加以下脚本: using UnityEngine; using System.Collections; using UnityEngine.UI; using ...

  3. 解决ScrollView嵌套ViewPager出现的滑动冲突问题

    /**       *         解决ScrollView嵌套ViewPager出现的滑动冲突问题       */       public class ScrollView1 extends ...

  4. Android ScrollView 嵌套 ListView、 ListView 嵌套ScrollView Scroll事件冲突解决办法

    本人菜鸟一名,最近工作了,开始学习Android. 最近在做项目的时候,UX给了个design,大概就是下拉刷新的ListView中嵌套了ScrollView,而且还要在ScrollView中添加动画 ...

  5. 解决ScrollView中嵌套ListView滚动效果冲突问题

    在ScrollView中嵌套使用ListView,ListView只会显示一行到两行的数据.起初我以为是样式的问题,一直在对XML文件的样 式进行尝试性设置,但始终得不到想要的效果.后来在网上查了查, ...

  6. 解决ScrollView嵌套RecyclerView的显示及滑动问题

        项目中时常需要实现在ScrollView中嵌入一个或多个RecyclerView.这一做法通常会导致如下几个问题 页面滑动卡顿 ScrollView高度显示不正常 RecyclerView内容 ...

  7. Android在开发中的使用技巧之解决ScrollView嵌套RecyclerView出现的系列问题

    根据已上线的app里总结出来的实用小技巧 相信大家都遇到过ScrollView嵌套RecyclerView或者RecyclerView嵌套RecyclerView来使用, 也会遇到一堆奇奇怪怪的问题, ...

  8. Android——MeasureSpec学习 - 解决ScrollView嵌套ListView和GridView冲突的方法

      原文地址:http://blog.csdn.net/yuhailong626/article/details/20639217   在自定义View和ViewGroup的时候,我们经常会遇到int ...

  9. dede频道页实现三级栏目嵌套调用文章

      dede频道页实现三级栏目嵌套调用文章: //支持arclist标签开始--> $typeid = $row['id']; if((class_exists('PartView'))) { ...

随机推荐

  1. .NET Core 跨平台发布(dotnet publish)

    .NET Core 跨平台发布(dotnet publish) ,无需安装.NET Core SDK,就可以运行. 前面讲解了.NET Core 的VSCode 开发.现在来讲讲发布(dotnet p ...

  2. Hadoop学习笔记—19.Flume框架学习

    START:Flume是Cloudera提供的一个高可用的.高可靠的开源分布式海量日志收集系统,日志数据可以经过Flume流向需要存储终端目的地.这里的日志是一个统称,泛指文件.操作记录等许多数据. ...

  3. 如何给CentOS安装字体库

    很多时候,我们需要做一些图像生成工作(譬如验证码之类的),这时候,我们一般都需要用到系统的字体库.但事情却总非尽善人意,我们所使用的Linux操作系统无法像Windows操作系统那样足够“旗舰”,字体 ...

  4. 我如何介绍 Microservice

    这篇文章转自我的 Github blog 一天我司招财猫姐(HR 大人)问我,你给我解释一下 Microservice 是什么吧.故成此文.一切都是从一个创业公司开始的. 故事 最近的创业潮非常火爆, ...

  5. SQL Server 数据库子查询基本语法

    一.SQL子查询语句 1.单行子查询        select ename,deptno,sal        from emp        where deptno=(select deptno ...

  6. SQL Server中的窗口函数

    简介     SQL Server 2012之后对窗口函数进行了极大的加强,但对于很多开发人员来说,对窗口函数却不甚了解,导致了这样强大的功能被浪费,因此本篇文章主要谈一谈SQL Server中窗口函 ...

  7. c#写windows服务

    序言 前段时间做一个数据迁移项目,刚开始用B/S架构做的项目,但B/S要寄存在IIs中,而IIs又不稳定因素,如果重启IIs就要打开页面才能运行项目.有不便之处,就改用Windows服务实现.这篇就总 ...

  8. [WPF]带下拉列表的文本框

    控件我已经弄好了,代码比较多,所以没办法全面介绍. 一开始我是直接继承Selector类来实现,做是做出来了,不过发现性能不太好.于是,我就想着自己来实现.毕竟我是做给自己用的,也不考虑过多的东西,也 ...

  9. Android随笔之——Android广播机制Broadcast详解

    在Android中,有一些操作完成以后,会发送广播,比如说发出一条短信,或打出一个电话,如果某个程序接收了这个广播,就会做相应的处理.这个广播跟我们传统意义中的电台广播有些相似之处.之所以叫做广播,就 ...

  10. Connect(); // 2015 简要整理

    去年 Connect(); 2014 Visual Studio Contact(); 直播笔记 对于我个人来说,今年 Connect(); 的三个重要发布: ASP.NET 5 RC1 Entity ...