zoukankan      html  css  js  c++  java
  • 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);
                }
    
            }
        }
    }
    
    

    总结

    目前来看效果还可以,两种滑动无干扰,有简单的阻尼滑动效果,滑动分页界限可以设置
    
    其他若有什么问题,欢迎留言
  • 相关阅读:
    类型约束的本质:泛型是不完备类型,只有合乎要求的构造才能正确使用和访问。
    函数的泛型约束是函数签名的一部分,不符合约束的初始调用将不能查找到函数(报错)
    泛型约束-swift
    swift语言的特点(相对于oc)
    extension Kingfisher where Base: Image:泛型类型的具体化与实例化
    “标准查询运算符”是组成语言集成查询 (LINQ) 模式的方法
    int 和bigint差别有多大?
    MySql5.7 配置文件 my.cnf 设置
    关于mysql 出现 1264 Out of range value for column 错误的解决办法
    git中Please enter a commit message to explain why this merge is necessary.
  • 原文地址:https://www.cnblogs.com/coldcode/p/5383412.html
Copyright © 2011-2022 走看看