Unity NGUI之ScrollView扩展-2

大伙在使用UIScrollView时,经常和UICenterOn脚本配合使用,但是随着需求的不断增加,会出现这个需求:第一个列表在拖动后不让它在最中间显示,还是保留在UIScrollView裁剪区域的其实部分,比如,一些非常多的列表,要求一条条显示,同时又不能出现半个,大伙第一个就能想到UICenterOn,但是拖着列表过程中,第一个列表就被固定在了中间,这样显示很难看。怎样解决这个问题呢?我在看UIScrollView代码的过成中看到了这个方法:

public bool RestrictWithinBounds (bool instant, bool horizontal, bool vertical)

这个方法的作用是让列表的显示限制在裁剪区域

那怎么判断这个列表超出了这个区域了呢(即列表的起始,末尾部分往中间显示)

我写了一个方法来判断,至于是什么原理,大伙通过看代码来研究了:

    ///

    /// 可以填充区域 但没有填充区域
    ///


    private bool IsOutOfBoundsPanel()
    {
        if (mPanel == null) mPanel = GetComponent();
        Vector4 clip = mPanel.finalClipRegion;
        Bounds b = GetSpecialBounds(transform);


        float hx = (clip.z == 0f) ? Screen.width : clip.z * 0.5f;
        float hy = (clip.w == 0f) ? Screen.height : clip.w * 0.5f;


        if (canMoveHorizontally)
        {
            if ((b.min.x > clip.x - hx) && (b.max.x > clip.x + hx)) return true;
            if ((b.max.x < clip.x + hx) && (b.min.x < clip.x - hx)) return true;
        }


        if (canMoveVertically)
        {
            if ((b.min.y > clip.y - hy) && (b.max.y > clip.y + hy)) return true;
            if ((b.max.y < clip.y + hy) && (b.min.y < clip.y - hy)) return true;
            return true;
        }
        return false;
    }

注意里面的GetSpecialBounds方法就是我在上一栏中写的方法,大伙也可以用UIScrollView 的bounds属性


最后在改动UIScrollView 的lateupdate方法(幸好lateupdate方法可以完全重写,否则要改动UIScrollView的脚本了):

我把改动的部分给粘上

                // Restrict the contents to be within the scroll view's bounds
                if (restrictWithinPanel && mPanel.clipping != UIDrawCall.Clipping.None)
                {
                    if (NGUITools.GetActive(centerOnChild))
                    {
                        if (centerOnChild.nextPageThreshold != 0f)
                        {
                            mMomentum = Vector3.zero;
                            mScroll = 0f;
                        }
                        else
                        {
                            if (restrictWithinPanelIgnoreCenterOnChild && IsOutOfBoundsPanel())
                            {
                                RestrictWithinBounds(false, canMoveHorizontally, canMoveVertically);
                            }
                            else
                            {
                                centerOnChild.Recenter();
                            }
                        }
                    }
                    else
                    {
                        RestrictWithinBounds(false, canMoveHorizontally, canMoveVertically);
                    }
                }

最后附上这个脚本的源码,供大家参考

using UnityEngine;
using System.Collections;
using System.Collections.Generic;


public class UIScrollViewForSpecialBounds : UIScrollView
{
    ///


    /// 限制区域填充的时候是否忽略UICenterOnChild脚本的作用
    ///

    public bool restrictWithinPanelIgnoreCenterOnChild=false;
    ///
    /// 针对改名字获取相应的bounds
    ///

    public string TargetWidgetBoundsName;
    public override Bounds bounds
    {
        get
        {
            mCalculatedBounds = true;
            mTrans = transform;
            return GetSpecialBounds(transform);
        }
    }
    void LateUpdate()
    {
        if (!Application.isPlaying) return;
        float delta = RealTime.deltaTime;


        // Fade the scroll bars if needed
        if (showScrollBars != ShowCondition.Always && (verticalScrollBar || horizontalScrollBar))
        {
            bool vertical = false;
            bool horizontal = false;


            if (showScrollBars != ShowCondition.WhenDragging || mDragID != -10 || mMomentum.magnitude > 0.01f)
            {
                vertical = shouldMoveVertically;
                horizontal = shouldMoveHorizontally;
            }


            if (verticalScrollBar)
            {
                float alpha = verticalScrollBar.alpha;
                alpha += vertical ? delta * 6f : -delta * 3f;
                alpha = Mathf.Clamp01(alpha);
                if (verticalScrollBar.alpha != alpha) verticalScrollBar.alpha = alpha;
            }


            if (horizontalScrollBar)
            {
                float alpha = horizontalScrollBar.alpha;
                alpha += horizontal ? delta * 6f : -delta * 3f;
                alpha = Mathf.Clamp01(alpha);
                if (horizontalScrollBar.alpha != alpha) horizontalScrollBar.alpha = alpha;
            }
        }


        if (!mShouldMove) return;


        // Apply momentum
        if (!mPressed)
        {
            if (mMomentum.magnitude > 0.0001f || mScroll != 0f)
            {
                if (movement == Movement.Horizontal)
                {
                    mMomentum -= mTrans.TransformDirection(new Vector3(mScroll * 0.05f, 0f, 0f));
                }
                else if (movement == Movement.Vertical)
                {
                    mMomentum -= mTrans.TransformDirection(new Vector3(0f, mScroll * 0.05f, 0f));
                }
                else if (movement == Movement.Unrestricted)
                {
                    mMomentum -= mTrans.TransformDirection(new Vector3(mScroll * 0.05f, mScroll * 0.05f, 0f));
                }
                else
                {
                    mMomentum -= mTrans.TransformDirection(new Vector3(
                        mScroll * customMovement.x * 0.05f,
                        mScroll * customMovement.y * 0.05f, 0f));
                }
                mScroll = NGUIMath.SpringLerp(mScroll, 0f, 20f, delta);


                // Move the scroll view
                Vector3 offset = NGUIMath.SpringDampen(ref mMomentum, 9f, delta);
                MoveAbsolute(offset);


                // Restrict the contents to be within the scroll view's bounds
                if (restrictWithinPanel && mPanel.clipping != UIDrawCall.Clipping.None)
                {
                    if (NGUITools.GetActive(centerOnChild))
                    {
                        if (centerOnChild.nextPageThreshold != 0f)
                        {
                            mMomentum = Vector3.zero;
                            mScroll = 0f;
                        }
                        else
                        {
                            if (restrictWithinPanelIgnoreCenterOnChild && IsOutOfBoundsPanel())
                            {
                                RestrictWithinBounds(false, canMoveHorizontally, canMoveVertically);
                            }
                            else
                            {
                                centerOnChild.Recenter();
                            }
                        }
                    }
                    else
                    {
                        RestrictWithinBounds(false, canMoveHorizontally, canMoveVertically);
                    }
                }


                if (onMomentumMove != null)
                    onMomentumMove();
            }
            else
            {
                mScroll = 0f;
                mMomentum = Vector3.zero;


                SpringPanel sp = GetComponent();
                if (sp != null && sp.enabled) return;


                mShouldMove = false;
                if (onStoppedMoving != null)
                    onStoppedMoving();
            }
        }
        else
        {
            // Dampen the momentum
            mScroll = 0f;
            NGUIMath.SpringDampen(ref mMomentum, 9f, delta);
        }
    }
    ///
    /// 可以填充区域 但没有填充区域
    ///

    private bool IsOutOfBoundsPanel()
    {
        if (mPanel == null) mPanel = GetComponent();
        Vector4 clip = mPanel.finalClipRegion;
        Bounds b = GetSpecialBounds(transform);


        float hx = (clip.z == 0f) ? Screen.width : clip.z * 0.5f;
        float hy = (clip.w == 0f) ? Screen.height : clip.w * 0.5f;


        if (canMoveHorizontally)
        {
            if ((b.min.x > clip.x - hx) && (b.max.x > clip.x + hx)) return true;
            if ((b.max.x < clip.x + hx) && (b.min.x < clip.x - hx)) return true;
        }


        if (canMoveVertically)
        {
            if ((b.min.y > clip.y - hy) && (b.max.y > clip.y + hy)) return true;
            if ((b.max.y < clip.y + hy) && (b.min.y < clip.y - hy)) return true;
            return true;
        }
        return false;
    }
    ///
    /// 获取特定的Bounds 按照gameobject的名字进行过滤
    ///

    private Bounds GetSpecialBounds(Transform scrollView)
    {
        Matrix4x4 toLocal = scrollView.worldToLocalMatrix;
        bool isSet = false;
        Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
        Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);
        if (!(scrollView == null || (!NGUITools.GetActive(scrollView.gameObject))))
        {
            Vector3[] corners = null;// p.worldCorners;


            List widigetList = new List();
            GetSpecialBoundsWidget(transform, TargetWidgetBoundsName, ref widigetList);


            for (int i = 0; i < widigetList.Count; i++)
            {
                UIWidget w = widigetList[i];
                corners = w.worldCorners;


                for (int j = 0; j < 4; ++j)
                {
                    Vector3 v = toLocal.MultiplyPoint3x4(corners[j]);


                    if (v.x > max.x) max.x = v.x;
                    if (v.y > max.y) max.y = v.y;
                    if (v.z > max.z) max.z = v.z;


                    if (v.x < min.x) min.x = v.x;
                    if (v.y < min.y) min.y = v.y;
                    if (v.z < min.z) min.z = v.z;


                    isSet = true;
                }
            }
        }
        if (isSet)
        {
            Bounds b = new Bounds(min, Vector3.zero);
            b.Encapsulate(max);
            return b;
        }
        return new Bounds(Vector3.zero,Vector3.zero);
    }
    private void GetSpecialBoundsWidget(Transform parent,string speciBoundsName,ref List list)
    {
        if (parent == null)
            return;
        foreach(Transform child in parent)
        {
            GetSpecialBoundsWidget(child,speciBoundsName,ref list);
        }


        if(parent.name==speciBoundsName)
        {
            list.Add(parent.GetComponent());
        }
    }
}

最后希望对大伙有所帮助。


你可能感兴趣的:(Unity,NGUI)