Unity实现滑页嵌套(解决ScrollRect嵌套冲突问题)

来源:互联网 发布:淘宝店铺动态在哪里看 编辑:程序博客网 时间:2024/06/11 22:47

简介

由于项目需要+有网友咨询,所以做了个横向滑页+某一横向滑页中有竖向滑页的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);            }        }    }}

总结

目前来看效果还可以,两种滑动无干扰,有简单的阻尼滑动效果,滑动分页界限可以设置其他若有什么问题,欢迎留言
0 0
原创粉丝点击