Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Unity實現滑頁嵌套(解決ScrollRect嵌套沖突問題)

Unity實現滑頁嵌套(解決ScrollRect嵌套沖突問題)

編輯:關於Android編程

簡介

由於項目需要+有網友咨詢,所以做了個橫向滑頁+某一橫向滑頁中有豎向滑頁的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;

    /// 
    /// 逗比單例模式
    /// 
    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;

    /// 
    /// 拖動起始判斷參數,可自行更改
    /// 
    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;
    }

    /// 
    /// 防空保護函數,無用處,可自行優化
    /// 
    ///
    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;
    }

    /// 
    /// 判斷是否超出靜止范圍,用static速度更快
    /// 
    ///
    ///
    /// 
    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
{

    /// 
    /// 橫向滾動條
    /// 
    public Scrollbar m_HScrollBar;

    /// 
    /// 豎向滾動條
    /// 
    public Scrollbar[] m_VScrollBars;

    /// 
    /// 有豎向滾動的頁面
    /// 
    public int[] m_VScrollIndexs;

    /// 
    /// 頁面個數
    /// 
    public int m_Num;

    /// 
    /// 設置移動超過多少百分比之後向下翻頁
    /// 
    public float m_NextLimit;

    /// 
    /// 滑動敏感值
    /// 
    public float m_Sensitive;

    /// 
    /// 鼠標上一次的位置
    /// 
    private Vector3 mOldPosition;

    /// 
    /// 記錄上一次的value
    /// 
    private float mOldValue;

    private float mTargetPosition = 0.5f;

    private int mCurrentIndex = 3;

    private int mTargetIndex = 3;

    /// 
    /// 是否可以移動
    /// 
    private bool mCanMove = false;

    /// 
    /// 初始移動速度
    /// 
    private float mMoveSpeed;

    /// 
    /// 平滑移動參數
    /// 
    private const float SMOOTH_TIME = 0.2F;

    private float mDragParam = 0;
    private float mPageWidth = 0;

    /// 
    /// 是否需要進行滑動方向判定
    /// 
    private bool mNeedCaculate = false;

    /// 
    /// 是否進行豎向滾動
    /// 
    private bool mIsScollV = false;

    /// 
    /// 豎向臨時滾動條
    /// 
    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);
            }

        }
    }
}
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved