zoukankan      html  css  js  c++  java
  • NGUI无限滑动

    http://www.unity蛮牛.com/blog-9383-1391.html

    最近由于工作需要,就开始研究NGUI滑动。刚开始参考NGUI自带的循环滑动,利用隐藏和显示,提高GPU的渲染,但是效果依旧不是很理想。在同事提醒下,添加缓存列表,不断刷新当前裁剪区域里的数据,最总完成了需求。在网上也参考了很多资料,今天恰好闲下来,就拿出来大家分享下,哈哈。代码附上:

     
    主要分为三部分
    1.重写UIScrollView和UICustomDragScrollView两个脚本
    ////////////////////////////////////////////////////////////////////////////////
    修改 UIScrollView 为 UICustomScrollView
    ////////////////////////////////////////////////////////////////////////////////
    using UnityEngine;
    using System.Collections;

    /// <summary>
    /// 修改 UIScrollView 为 UICustomScrollView
    /// </summary>

    public class UICustomDragScrollView : MonoBehaviour
    {
        /// <summary>
        /// Reference to the scroll view that will be dragged by the script.
        /// </summary>

        public UICustomScrollView scrollView;

        // Legacy functionality, kept for backwards compatibility. Use 'scrollView' instead.
        [HideInInspector][SerializeField] UICustomScrollView draggablePanel;

        Transform mTrans;
        UICustomScrollView mScroll;
        bool mAutoFind = false;
        bool mStarted = false;

        /// <summary>
        /// Automatically find the scroll view if possible.
        /// </summary>

        void OnEnable ()
        {
            mTrans = transform;

            // Auto-upgrade
            if (scrollView == null && draggablePanel != null)
            {
                scrollView = draggablePanel;
                draggablePanel = null;
            }

            if (mStarted && (mAutoFind || mScroll == null))
                FindScrollView();
        }

        /// <summary>
        /// Find the scroll view.
        /// </summary>

        void Start ()
        {
            mStarted = true;
            FindScrollView();
        }

        /// <summary>
        /// Find the scroll view to work with.
        /// </summary>

        void FindScrollView ()
        {
            // If the scroll view is on a parent, don't try to remember it (as we want it to be dynamic in case of re-parenting)
            UICustomScrollView sv = NGUITools.FindInParents<UICustomScrollView>(mTrans);

            if (scrollView == null)
            {
                scrollView = sv;
                mAutoFind = true;
            }
            else if (scrollView == sv)
            {
                mAutoFind = true;
            }
            mScroll = scrollView;
        }

        /// <summary>
        /// Create a plane on which we will be performing the dragging.
        /// </summary>

        void OnPress (bool pressed)
        {
            // If the scroll view has been set manually, don't try to find it again
            if (mAutoFind && mScroll != scrollView)
            {
                mScroll = scrollView;
                mAutoFind = false;
            }

            if (scrollView && enabled && NGUITools.GetActive(gameObject))
            {
                scrollView.Press(pressed);
                
                if (!pressed && mAutoFind)
                {
                    scrollView = NGUITools.FindInParents<UICustomScrollView>(mTrans);
                    mScroll = scrollView;
                }
            }
        }

        /// <summary>
        /// Drag the object along the plane.
        /// </summary>

        void OnDrag (Vector2 delta)
        {
            if (scrollView && NGUITools.GetActive(this))
                scrollView.Drag();
        }

        /// <summary>
        /// If the object should support the scroll wheel, do it.
        /// </summary>

        void OnScroll (float delta)
        {
            if (scrollView && NGUITools.GetActive(this))
                scrollView.Scroll(delta);
        }
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////
    重写UICustomDragScrollView
    ////////////////////////////////////////////////////////////////////////////////////////////////////

    //----------------------------------------------
    //            NGUI: Next-Gen UI kit
    // Copyright © 2011-2014 Tasharen Entertainment
    //----------------------------------------------

    using UnityEngine;

    /// <summary>
    /// This script, when attached to a panel turns it into a scroll view.
    /// You can then attach UIDragScrollView to colliders within to make it draggable.
    /// </summary>

    public class UICustomScrollView : MonoBehaviour
    {
        static public BetterList<UICustomScrollView> list = new BetterList<UICustomScrollView>();

        public enum Movement
        {
            Horizontal,
            Vertical,
            Unrestricted,
            Custom,
        }

        public enum DragEffect
        {
            None,
            Momentum,
            MomentumAndSpring,
        }

        public enum ShowCondition
        {
            Always,
            OnlyIfNeeded,
            WhenDragging,
        }

        public delegate void OnDragFinished ();

        /// <summary>
        /// Type of movement allowed by the scroll view.
        /// </summary>

        public Movement movement = Movement.Horizontal;

        /// <summary>
        /// Effect to apply when dragging.
        /// </summary>

        public DragEffect dragEffect = DragEffect.MomentumAndSpring;

        /// <summary>
        /// Whether the dragging will be restricted to be within the scroll view's bounds.
        /// </summary>

        public bool restrictWithinPanel = true;

        /// <summary>
        /// Whether dragging will be disabled if the contents fit.
        /// </summary>

        public bool disableDragIfFits = false;

        /// <summary>
        /// Whether the drag operation will be started smoothly, or if if it will be precise (but will have a noticeable "jump").
        /// </summary>

        public bool smoothDragStart = true;

        /// <summary>
        /// Whether to use iOS drag emulation, where the content only drags at half the speed of the touch/mouse movement when the content edge is within the clipping area.
        /// </summary>    
        
        public bool iOSDragEmulation = true;

        /// <summary>
        /// Effect the scroll wheel will have on the momentum.
        /// </summary>

        public float scrollWheelFactor = 0.25f;

        /// <summary>
        /// How much momentum gets applied when the press is released after dragging.
        /// </summary>

        public float momentumAmount = 35f;
        
        /// <summary>
        /// Horizontal scrollbar used for visualization.
        /// </summary>

        public UIProgressBar horizontalScrollBar;

        /// <summary>
        /// Vertical scrollbar used for visualization.
        /// </summary>

        public UIProgressBar verticalScrollBar;

        /// <summary>
        /// Condition that must be met for the scroll bars to become visible.
        /// </summary>

        public ShowCondition showScrollBars = ShowCondition.OnlyIfNeeded;

        /// <summary>
        /// Custom movement, if the 'movement' field is set to 'Custom'.
        /// </summary>

        public Vector2 customMovement = new Vector2(1f, 0f);

        /// <summary>
        /// Content's pivot point -- where it originates from by default.
        /// </summary>

        public UIWidget.Pivot contentPivot = UIWidget.Pivot.TopLeft;

        /// <summary>
        /// Event callback to trigger when the drag process finished. Can be used for additional effects, such as centering on some object.
        /// </summary>

        public OnDragFinished onDragFinished;

        // Deprecated functionality. Use 'movement' instead.
        [HideInInspector][SerializeField] Vector3 scale = new Vector3(1f, 0f, 0f);

        // Deprecated functionality. Use 'contentPivot' instead.
        [SerializeField][HideInInspector] Vector2 relativePositionOnReset = Vector2.zero;

        protected Transform mTrans;
        protected UIPanel mPanel;
        protected Plane mPlane;
        protected Vector3 mLastPos;
        protected bool mPressed = false;
        protected Vector3 mMomentum = Vector3.zero;
        protected float mScroll = 0f;
        protected Bounds mBounds;
        protected bool mCalculatedBounds = false;
        protected bool mShouldMove = false;
        protected bool mIgnoreCallbacks = false;
        protected int mDragID = -10;
        protected Vector2 mDragStartOffset = Vector2.zero;
        protected bool mDragStarted = false;

        /// <summary>
        /// Panel that's being dragged.
        /// </summary>

        public UIPanel panel { get { return mPanel; } }

        /// <summary>
        /// Whether the scroll view is being dragged.
        /// </summary>

        public bool isDragging { get { return mPressed && mDragStarted; } }

        /// <summary>
        /// Calculate the bounds used by the widgets.
        /// </summary>

        public virtual Bounds bounds
        {
            get
            {
                //if (!mCalculatedBounds)
                //{
                //    mCalculatedBounds = true;
                //    mTrans = transform;
                //    mBounds = NGUIMath.CalculateRelativeWidgetBounds(mTrans, mTrans, true);
                //}
                return mBounds;
            }
            set
            {
                mBounds = value;
            }
        }

        /// <summary>
        /// Whether the scroll view can move horizontally.
        /// </summary>

        public bool canMoveHorizontally
        {
            get
            {
                return movement == Movement.Horizontal ||
                    movement == Movement.Unrestricted ||
                    (movement == Movement.Custom && customMovement.x != 0f);
            }
        }

        /// <summary>
        /// Whether the scroll view can move vertically.
        /// </summary>

        public bool canMoveVertically
        {
            get
            {
                return movement == Movement.Vertical ||
                    movement == Movement.Unrestricted ||
                    (movement == Movement.Custom && customMovement.y != 0f);
            }
        }

        /// <summary>
        /// Whether the scroll view should be able to move horizontally (contents don't fit).
        /// </summary>

        public virtual bool shouldMoveHorizontally
        {
            get
            {
                float size = bounds.size.x;
                if (mPanel.clipping == UIDrawCall.Clipping.SoftClip) size += mPanel.clipSoftness.x * 2f;
                return Mathf.RoundToInt(size - mPanel.width) > 0;
            }
        }

        /// <summary>
        /// Whether the scroll view should be able to move vertically (contents don't fit).
        /// </summary>

        public virtual bool shouldMoveVertically
        {
            get
            {
                float size = bounds.size.y;
                if (mPanel.clipping == UIDrawCall.Clipping.SoftClip) size += mPanel.clipSoftness.y * 2f;
                return Mathf.RoundToInt(size - mPanel.height) > 0;
            }
        }

        /// <summary>
        /// Whether the contents of the scroll view should actually be draggable depends on whether they currently fit or not.
        /// </summary>

        protected virtual bool shouldMove
        {
            get
            {
                if (!disableDragIfFits) return true;

                if (mPanel == null) mPanel = GetComponent<UIPanel>();
                Vector4 clip = mPanel.finalClipRegion;
                Bounds b = bounds;

                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) return true;
                    if (b.max.x > clip.x + hx) return true;
                }

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

        /// <summary>
        /// Current momentum, exposed just in case it's needed.
        /// </summary>

        public Vector3 currentMomentum { get { return mMomentum; } set { mMomentum = value; mShouldMove = true; } }

        /// <summary>
        /// Cache the transform and the panel.
        /// </summary>

        void Awake ()
        {
            mTrans = transform;
            mPanel = GetComponent<UIPanel>();

            if (mPanel.clipping == UIDrawCall.Clipping.None)
                mPanel.clipping = UIDrawCall.Clipping.ConstrainButDontClip;
            
            // Auto-upgrade
            if (movement != Movement.Custom && scale.sqrMagnitude > 0.001f)
            {
                if (scale.x == 1f && scale.y == 0f)
                {
                    movement = Movement.Horizontal;
                }
                else if (scale.x == 0f && scale.y == 1f)
                {
                    movement = Movement.Vertical;
                }
                else if (scale.x == 1f && scale.y == 1f)
                {
                    movement = Movement.Unrestricted;
                }
                else
                {
                    movement = Movement.Custom;
                    customMovement.x = scale.x;
                    customMovement.y = scale.y;
                }
                scale = Vector3.zero;
    #if UNITY_EDITOR
                NGUITools.SetDirty(this);
    #endif
            }

            // Auto-upgrade
            if (contentPivot == UIWidget.Pivot.TopLeft && relativePositionOnReset != Vector2.zero)
            {
                contentPivot = NGUIMath.GetPivot(new Vector2(relativePositionOnReset.x, 1f - relativePositionOnReset.y));
                relativePositionOnReset = Vector2.zero;
    #if UNITY_EDITOR
                NGUITools.SetDirty(this);
    #endif
            }
        }

        void OnEnable () { list.Add(this); }
        void OnDisable () { list.Remove(this); }

        /// <summary>
        /// Set the initial drag value and register the listener delegates.
        /// </summary>

        protected virtual void Start ()
        {
            //UpdatePosition();

            if (Application.isPlaying)
            {
                if (horizontalScrollBar != null)
                {
                    EventDelegate.Add(horizontalScrollBar.onChange, OnScrollBar);
                    horizontalScrollBar.alpha = ((showScrollBars == ShowCondition.Always) || shouldMoveHorizontally) ? 1f : 0f;
                }

                if (verticalScrollBar != null)
                {
                    EventDelegate.Add(verticalScrollBar.onChange, OnScrollBar);
                    verticalScrollBar.alpha = ((showScrollBars == ShowCondition.Always) || shouldMoveVertically) ? 1f : 0f;
                }
            }
        }

        /// <summary>
        /// Restrict the scroll view's contents to be within the scroll view's bounds.
        /// </summary>

        public bool RestrictWithinBounds (bool instant) { return RestrictWithinBounds(instant, true, true); }

        /// <summary>
        /// Restrict the scroll view's contents to be within the scroll view's bounds.
        /// </summary>

        public bool RestrictWithinBounds (bool instant, bool horizontal, bool vertical)
        {
            Bounds b = bounds;
            Vector3 constraint = mPanel.CalculateConstrainOffset(b.min, b.max);

            if (!horizontal) constraint.x = 0f;
            if (!vertical) constraint.y = 0f;
           
            if (constraint.sqrMagnitude > 1f)
            {

                if (!instant && dragEffect == DragEffect.MomentumAndSpring)
                {
                    // Spring back into place
                    Vector3 pos = mTrans.localPosition + constraint;
                    pos.x = Mathf.Round(pos.x);
                    pos.y = Mathf.Round(pos.y);
                    SpringPanel.Begin(mPanel.gameObject, pos, 13f);
                }
                else
                {
                    // Jump back into place
                    MoveRelative(constraint);
                    mMomentum = Vector3.zero;
                    mScroll = 0f;
                }
                return true;
            }
            return false;
        }

        /// <summary>
        /// Disable the spring movement.
        /// </summary>

        public void DisableSpring ()
        {
            SpringPanel sp = GetComponent<SpringPanel>();
            if (sp != null) sp.enabled = false;
        }

        /// <summary>
        /// Update the values of the associated scroll bars.
        /// </summary>

        public void UpdateScrollbars () { UpdateScrollbars(true); }

        /// <summary>
        /// Update the values of the associated scroll bars.
        /// </summary>

        public virtual void UpdateScrollbars (bool recalculateBounds)
        {
            if (mPanel == null) return;

            if (horizontalScrollBar != null || verticalScrollBar != null)
            {
                if (recalculateBounds)
                {
                    mCalculatedBounds = false;
                    mShouldMove = shouldMove;
                }

                Bounds b = bounds;
                Vector2 bmin = b.min;
                Vector2 bmax = b.max;

                if (horizontalScrollBar != null && bmax.x > bmin.x)
                {
                    Vector4 clip = mPanel.finalClipRegion;
                    int intViewSize = Mathf.RoundToInt(clip.z);
                    if ((intViewSize & 1) != 0) intViewSize -= 1;
                    float halfViewSize = intViewSize * 0.5f;
                    halfViewSize = Mathf.Round(halfViewSize);

                    if (mPanel.clipping == UIDrawCall.Clipping.SoftClip)
                        halfViewSize -= mPanel.clipSoftness.x;

                    float contentSize = bmax.x - bmin.x;
                    float viewSize = halfViewSize * 2f;
                    float contentMin = bmin.x;
                    float contentMax = bmax.x;
                    float viewMin = clip.x - halfViewSize;
                    float viewMax = clip.x + halfViewSize;

                    contentMin = viewMin - contentMin;
                    contentMax = contentMax - viewMax;

                    UpdateScrollbars(horizontalScrollBar, contentMin, contentMax, contentSize, viewSize, false);
                }

                if (verticalScrollBar != null && bmax.y > bmin.y)
                {
                    Vector4 clip = mPanel.finalClipRegion;
                    int intViewSize = Mathf.RoundToInt(clip.w);
                    if ((intViewSize & 1) != 0) intViewSize -= 1;
                    float halfViewSize = intViewSize * 0.5f;
                    halfViewSize = Mathf.Round(halfViewSize);

                    if (mPanel.clipping == UIDrawCall.Clipping.SoftClip)
                        halfViewSize -= mPanel.clipSoftness.y;

                    float contentSize = bmax.y - bmin.y;
                    float viewSize = halfViewSize * 2f;
                    float contentMin = bmin.y;
                    float contentMax = bmax.y;
                    float viewMin = clip.y - halfViewSize;
                    float viewMax = clip.y + halfViewSize;

                    contentMin = viewMin - contentMin;
                    contentMax = contentMax - viewMax;

                    UpdateScrollbars(verticalScrollBar, contentMin, contentMax, contentSize, viewSize, true);
                }
            }
            else if (recalculateBounds)
            {
                mCalculatedBounds = false;
            }
        }

        /// <summary>
        /// Helper function used in UpdateScrollbars(float) function above.
        /// </summary>

        protected void UpdateScrollbars (UIProgressBar slider, float contentMin, float contentMax, float contentSize, float viewSize, bool inverted)
        {
            if (slider == null) return;

            mIgnoreCallbacks = true;
            {
                float contentPadding;

                if (viewSize < contentSize)
                {
                    contentMin = Mathf.Clamp01(contentMin / contentSize);
                    contentMax = Mathf.Clamp01(contentMax / contentSize);

                    contentPadding = contentMin + contentMax;
                    slider.value = inverted ? ((contentPadding > 0.001f) ? 1f - contentMin / contentPadding : 0f) :
                        ((contentPadding > 0.001f) ? contentMin / contentPadding : 1f);
                }
                else
                {
                    contentMin = Mathf.Clamp01(-contentMin / contentSize);
                    contentMax = Mathf.Clamp01(-contentMax / contentSize);

                    contentPadding = contentMin + contentMax;
                    slider.value = inverted ? ((contentPadding > 0.001f) ? 1f - contentMin / contentPadding : 0f) :
                        ((contentPadding > 0.001f) ? contentMin / contentPadding : 1f);

                    if (contentSize > 0)
                    {
                        contentMin = Mathf.Clamp01(contentMin / contentSize);
                        contentMax = Mathf.Clamp01(contentMax / contentSize);
                        contentPadding = contentMin + contentMax;
                    }
                }

                UIScrollBar sb = slider as UIScrollBar;
                if (sb != null) sb.barSize = 1f - contentPadding;
            }
            mIgnoreCallbacks = false;
        }

        /// <summary>
        /// Changes the drag amount of the scroll view to the specified 0-1 range values.
        /// (0, 0) is the top-left corner, (1, 1) is the bottom-right.
        /// </summary>

        public virtual void SetDragAmount (float x, float y, bool updateScrollbars)
        {
            if (mPanel == null) mPanel = GetComponent<UIPanel>();

            DisableSpring();

            Bounds b = bounds;
            if (b.min.x == b.max.x || b.min.y == b.max.y) return;

            Vector4 clip = mPanel.finalClipRegion;

            float hx = clip.z * 0.5f;
            float hy = clip.w * 0.5f;
            float left = b.min.x + hx;
            float right = b.max.x - hx;
            float bottom = b.min.y + hy;
            float top = b.max.y - hy;

            if (mPanel.clipping == UIDrawCall.Clipping.SoftClip)
            {
                left -= mPanel.clipSoftness.x;
                right += mPanel.clipSoftness.x;
                bottom -= mPanel.clipSoftness.y;
                top += mPanel.clipSoftness.y;
            }

            // Calculate the offset based on the scroll value
            float ox = Mathf.Lerp(left, right, x);
            float oy = Mathf.Lerp(top, bottom, y);

            // Update the position
            if (!updateScrollbars)
            {
                Vector3 pos = mTrans.localPosition;
                if (canMoveHorizontally) pos.x += clip.x - ox;
                if (canMoveVertically) pos.y += clip.y - oy;
                mTrans.localPosition = pos;
            }

            if (canMoveHorizontally) clip.x = ox;
            if (canMoveVertically) clip.y = oy;

            // Update the clipping offset
            Vector4 cr = mPanel.baseClipRegion;
            mPanel.clipOffset = new Vector2(clip.x - cr.x, clip.y - cr.y);

            // Update the scrollbars, reflecting this change
            if (updateScrollbars) UpdateScrollbars(mDragID == -10);
        }

        /// <summary>
        /// Reset the scroll view's position to the top-left corner.
        /// It's recommended to call this function before AND after you re-populate the scroll view's contents (ex: switching window tabs).
        /// Another option is to populate the scroll view's contents, reset its position, then call this function to reposition the clipping.
        /// </summary>

        [ContextMenu("Reset Clipping Position")]
        public void ResetPosition()
        {
            if (NGUITools.GetActive(this))
            {
                // Invalidate the bounds
                mCalculatedBounds = false;
                Vector2 pv = NGUIMath.GetPivotOffset(contentPivot);

                // First move the position back to where it would be if the scroll bars got reset to zero
                SetDragAmount(pv.x, 1f - pv.y, false);

                // Next move the clipping area back and update the scroll bars
                SetDragAmount(pv.x, 1f - pv.y, true);
            }
        }

        /// <summary>
        /// Call this function after you adjust the scroll view's bounds if you want it to maintain the current scrolled position
        /// </summary>

        public void UpdatePosition ()
        {
            if (!mIgnoreCallbacks && (horizontalScrollBar != null || verticalScrollBar != null))
            {
                mIgnoreCallbacks = true;
                mCalculatedBounds = false;
                Vector2 pv = NGUIMath.GetPivotOffset(contentPivot);
                float x = (horizontalScrollBar != null) ? horizontalScrollBar.value : pv.x;
                float y = (verticalScrollBar != null) ? verticalScrollBar.value : 1f - pv.y;
                SetDragAmount(x, y, false);
                UpdateScrollbars(true);
                mIgnoreCallbacks = false;
            }
        }

        /// <summary>
        /// Triggered by the scroll bars when they change.
        /// </summary>

        public void OnScrollBar ()
        {
            if (!mIgnoreCallbacks)
            {
                mIgnoreCallbacks = true;
                float x = (horizontalScrollBar != null) ? horizontalScrollBar.value : 0f;
                float y = (verticalScrollBar != null) ? verticalScrollBar.value : 0f;
                SetDragAmount(x, y, false);
                mIgnoreCallbacks = false;
            }
        }

        /// <summary>
        /// Move the scroll view by the specified amount.
        /// </summary>

        public virtual void MoveRelative (Vector3 relative)
        {
            mTrans.localPosition += relative;
            Vector2 co = mPanel.clipOffset;
            co.x -= relative.x;
            co.y -= relative.y;
            mPanel.clipOffset = co;

            // Update the scroll bars
            UpdateScrollbars(false);
        }

        /// <summary>
        /// Move the scroll view by the specified amount.
        /// </summary>

        public void MoveAbsolute (Vector3 absolute)
        {
            Vector3 a = mTrans.InverseTransformPoint(absolute);
            Vector3 b = mTrans.InverseTransformPoint(Vector3.zero);
            MoveRelative(a - b);
        }

        /// <summary>
        /// Create a plane on which we will be performing the dragging.
        /// </summary>

        public void Press (bool pressed)
        {
            if (smoothDragStart && pressed)
            {
                mDragStarted = false;
                mDragStartOffset = Vector2.zero;
            }

            if (enabled && NGUITools.GetActive(gameObject))
            {
                if (!pressed && mDragID == UICamera.currentTouchID) mDragID = -10;

                mCalculatedBounds = false;
                mShouldMove = shouldMove;
                if (!mShouldMove) return;
                mPressed = pressed;

                if (pressed)
                {
                    // Remove all momentum on press
                    mMomentum = Vector3.zero;
                    mScroll = 0f;

                    // Disable the spring movement
                    DisableSpring();

                    // Remember the hit position
                    mLastPos = UICamera.lastHit.point;

                    // Create the plane to drag along
                    mPlane = new Plane(mTrans.rotation * Vector3.back, mLastPos);

                    // Ensure that we're working with whole numbers, keeping everything pixel-perfect
                    Vector2 co = mPanel.clipOffset;
                    co.x = Mathf.Round(co.x);
                    co.y = Mathf.Round(co.y);
                    mPanel.clipOffset = co;

                    Vector3 v = mTrans.localPosition;
                    v.x = Mathf.Round(v.x);
                    v.y = Mathf.Round(v.y);
                    mTrans.localPosition = v;
                }
                else
                {
                    if (restrictWithinPanel && mPanel.clipping != UIDrawCall.Clipping.None && dragEffect == DragEffect.MomentumAndSpring)
                        RestrictWithinBounds(false, canMoveHorizontally, canMoveVertically);

                    if (onDragFinished != null)
                        onDragFinished();
                }
            }
        }

        /// <summary>
        /// Drag the object along the plane.
        /// </summary>

        public void Drag ()
        {
            if (enabled && NGUITools.GetActive(gameObject) && mShouldMove)
            {
                if (mDragID == -10) mDragID = UICamera.currentTouchID;
                UICamera.currentTouch.clickNotification = UICamera.ClickNotification.BasedOnDelta;

                // Prevents the drag "jump". Contributed by 'mixd' from the Tasharen forums.
                if (smoothDragStart && !mDragStarted)
                {
                    mDragStarted = true;
                    mDragStartOffset = UICamera.currentTouch.totalDelta;
                }

                Ray ray = smoothDragStart ?
                    UICamera.currentCamera.ScreenPointToRay(UICamera.currentTouch.pos - mDragStartOffset) :
                    UICamera.currentCamera.ScreenPointToRay(UICamera.currentTouch.pos);

                float dist = 0f;

                if (mPlane.Raycast(ray, out dist))
                {
                    Vector3 currentPos = ray.GetPoint(dist);
                    Vector3 offset = currentPos - mLastPos;
                    mLastPos = currentPos;

                    if (offset.x != 0f || offset.y != 0f || offset.z != 0f)
                    {
                        offset = mTrans.InverseTransformDirection(offset);

                        if (movement == Movement.Horizontal)
                        {
                            offset.y = 0f;
                            offset.z = 0f;
                        }
                        else if (movement == Movement.Vertical)
                        {
                            offset.x = 0f;
                            offset.z = 0f;
                        }
                        else if (movement == Movement.Unrestricted)
                        {
                            offset.z = 0f;
                        }
                        else
                        {
                            offset.Scale((Vector3)customMovement);
                        }
                        offset = mTrans.TransformDirection(offset);
                    }

                    // Adjust the momentum
                    mMomentum = Vector3.Lerp(mMomentum, mMomentum + offset * (0.01f * momentumAmount), 0.67f);

                    // Move the scroll view
                
                    if (!iOSDragEmulation || dragEffect != DragEffect.MomentumAndSpring)
                    {
                        MoveAbsolute(offset);    
                    }
                    else
                    {
                        Vector3 constraint = mPanel.CalculateConstrainOffset(bounds.min, bounds.max);

                        if (constraint.magnitude > 1f)
                        {
                            MoveAbsolute(offset * 0.5f);
                            mMomentum *= 0.5f;
                        }
                        else
                        {
                            MoveAbsolute(offset);
                        }
                    }

                    // We want to constrain the UI to be within bounds
                    if (restrictWithinPanel &&
                        mPanel.clipping != UIDrawCall.Clipping.None &&
                        dragEffect != DragEffect.MomentumAndSpring)
                    {
                        RestrictWithinBounds(true, canMoveHorizontally, canMoveVertically);
                    }
                }
            }
        }

        /// <summary>
        /// If the object should support the scroll wheel, do it.
        /// </summary>

        public void Scroll (float delta)
        {
            if (enabled && NGUITools.GetActive(gameObject) && scrollWheelFactor != 0f)
            {
                DisableSpring();
                mShouldMove = shouldMove;
                if (Mathf.Sign(mScroll) != Mathf.Sign(delta)) mScroll = 0f;
                mScroll += delta * scrollWheelFactor;
            }
        }

        /// <summary>
        /// Apply the dragging momentum.
        /// </summary>

        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;
                }
            }

            // Apply momentum
            if (mShouldMove && !mPressed)
            {
                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));
                }

                if (mMomentum.magnitude > 0.0001f)
                {
                    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)
                        RestrictWithinBounds(false, canMoveHorizontally, canMoveVertically);
                    
                    if (mMomentum.magnitude < 0.0001f && onDragFinished != null) 
                        onDragFinished();
                    
                    return;
                }
                else
                {
                    mScroll = 0f;
                    mMomentum = Vector3.zero;
                }
            }
            else mScroll = 0f;

            // Dampen the momentum
            NGUIMath.SpringDampen(ref mMomentum, 9f, delta);
        }

    #if UNITY_EDITOR

        /// <summary>
        /// Draw a visible orange outline of the bounds.
        /// </summary>

        void OnDrawGizmos ()
        {
            if (mPanel != null)
            {
                if (!Application.isPlaying) mCalculatedBounds = false;
                Bounds b = bounds;
                Gizmos.matrix = transform.localToWorldMatrix;
                Gizmos.color = new Color(1f, 0.4f, 0f);
                Gizmos.DrawWireCube(new Vector3(b.center.x, b.center.y, b.min.z), new Vector3(b.size.x, b.size.y, 0f));
            }
        }
    #endif
    }

    2.核心脚本NGUIDynamicScrollBase ,计算滑动和播放位移动画

    [code]csharpcode:

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    
    /// <summary>
    /// 扩展NGUIScroll滑动类,需要继承该类进行开发
    /// </summary>
    public abstract  class NGUIDynamicScrollBase : MonoBehaviour
    {
    
        //每个列表项数据初始化
        abstract protected void ResetItemData(GameObject go, int index);
        public UIPanel panel;
        public UIGrid grid;
        //目标prefab
        public GameObject prefab;
        //宽度
        public int cellHeight = 60;
        //高度
        public int cellWidth = 700;
        //裁剪区的高度
        private float m_height;
        //裁剪区的宽度
        private int m_maxLine;
        //当前滑动的列表
        protected GameObject[] m_cellList;
        //当前需要滑动的列表总数
        private int m_dataListCount;
        //自定义滑动
        private UICustomScrollView mDrag;
        //最后一次的滑动位置
        private float lastY = -1;
        private Vector3 defaultVec;
    
        // Use this for initialization
        protected void BaseOnEnable()
        {
            GetConfiguration();
        }
    
        // Update is called once per frame
        protected void BaseUpdate()
        {
            if (panel.transform.localPosition.y != lastY)
            {
                Validate();
                lastY = panel.transform.localPosition.y;
            }
        }
        //设置当前列表中的
        protected int DataListCount
        {
            get { return m_dataListCount; }
    
            set{
                m_dataListCount = value;
                
                AddItem(m_dataListCount);
                PlayMoveAnimation(m_cellList);
            }
        }
    
    
    
        #region private Functions
    
        //初始化配置数据
        private void GetConfiguration()
        {
            //物体默认位置
            defaultVec = new Vector3(0, cellHeight, 0);
            //裁剪区域的高度
            m_height = panel.height;
            //裁剪区域中最多显示的cellItem数量
            m_maxLine = Mathf.CeilToInt(m_height / cellHeight) + 1;
            //初始化CellList
            m_cellList = new GameObject[m_maxLine];
            //创建Item,默认为不可显示状态
            CreateItem();
        }
        //创建Item
        private void CreateItem()
        {
            for (int i = 0; i < m_maxLine; i++)
            {
                GameObject go = null;
                go = (GameObject)Instantiate(prefab);
                go.gameObject.SetActive(false);
                go.GetComponent<UICustomDragScrollView>().scrollView = panel.GetComponent<UICustomScrollView>();
                AddChild(grid.gameObject, go);
                go.transform.localScale = Vector3.one;
                go.transform.localPosition = new Vector3(cellWidth * AllScale.ResolutionScale, -i * cellHeight, 0);
                m_cellList[i] = go;
                go.gameObject.SetActive(false);
            }
        }
    
    
        //验证当前区域中的需要显示的CellItem
        private void Validate()
        {
            Vector3 position = panel.transform.localPosition;
    
            float _ver = Mathf.Max(position.y, 0);
    
            int startIndex = Mathf.FloorToInt(_ver / cellHeight);
    
            int endIndex = Mathf.Min(DataListCount, startIndex + m_maxLine);
    
            GameObject cell;
            int index = 0;
            for (int i = startIndex; i < startIndex + m_maxLine; i++)
            {
                cell = m_cellList[index];
    
                if (i < endIndex)
                {
                    //开始渲染
                    cell.gameObject.SetActive(true);
                    //重新填充数据
                    ResetItemData(cell, i);
                    //改变位置
                    cell.transform.localPosition = new Vector3(cell.transform.localPosition.x, i * -cellHeight, 0);
                    cell.name = "Item_" + index;
                }
                else
                {
                    cell.transform.localPosition = defaultVec;
                  //  cell.gameObject.SetActive(false);
                }
    
                index++;
            }
        }
    
        //重新计算包围合的大小
        private void UpdateBounds(int count)
        {
            Vector3 vMin = new Vector3();
            vMin.x = -grid.transform.localPosition.x;
            vMin.y = grid.transform.localPosition.y - count * cellHeight;
            vMin.z = grid.transform.localPosition.z;
            Bounds b = new Bounds(vMin, Vector3.one);
            b.Encapsulate(grid.transform.localPosition);
            if (mDrag == null) mDrag = panel.GetComponent<UICustomScrollView>();
            mDrag.bounds = b;
            mDrag.UpdateScrollbars(true);
            mDrag.RestrictWithinBounds(true);
        }
    
    
        //根据新的数量来重新绘制
        private void AddItem(int count)
        {
            Validate();
            UpdateBounds(count);
        }
        
        //增加孩子节点
        void AddChild(GameObject parent, GameObject go)
        {
            Transform t = go.transform;
            t.parent = parent.transform;
            t.localPosition = Vector3.zero;
            t.localRotation = Quaternion.identity;
            t.localScale = Vector3.one;
            go.layer = parent.layer;
        }
    
        //播放开始加载的位移动画
        void PlayMoveAnimation(GameObject[] list)
        {
            Vector3 to;
            Vector3 from;
            for (int i = 0; i < list.Length; i++)
            {
                from = list[i].transform.localPosition;
                from = new Vector3(cellWidth*AllScale.ResolutionScale, from.y, 0);
                to = new Vector3(0, from.y, 0);
                list[i].transform.localPosition = from;
                TweenPosition tp = TweenPosition.Begin(list[i], 0.8f, to);
                tp.delay = 0.1f;
                tp.from = from;
                tp.to = to;
                tp.duration = (i + 2) * 0.1f;
                tp.method = UITweener.Method.EaseIn;
            }
        }
        #endregion
    
    
       
    }
    
    3.将列表中的Prefab设置为向上对齐
  • 相关阅读:
    dp
    康拓展开
    MST + 树形 dp
    树上对抗搜索
    求树上任意一点所能到达的最远距离
    将一棵树变成一个环
    树形dp
    区间dp
    区间dp
    day07作业
  • 原文地址:https://www.cnblogs.com/123ing/p/4056105.html
Copyright © 2011-2022 走看看