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设置为向上对齐

最新文章

  1. 初识java泛型
  2. #linux包之sysstat之iostat命令
  3. pcap文件的文件头的link type
  4. HDFS(Hadoop Distributed File System )
  5. Redis学习手册(Set数据类型)
  6. 一起来说 Vim 语
  7. 【题解】A-B
  8. js返回值
  9. 嵌入式MCU开发群资源
  10. ArrayList源码阅读
  11. CoordinatorLayout 嵌套 AppBarLayout RecyclerView ,通过代码控制,使得CoordinatorLayout 自动滑动到tab置顶的位置
  12. js 字符串操作方法
  13. Jupyter Notebook 快捷键使用指南
  14. LeetCode算法题-Happy Number(Java实现)
  15. 【python】正则替换
  16. RESTful记录-RESTful内容
  17. Java比较两个Date日期的大小
  18. SQLServer2008数据库卸载图解
  19. 从Java的堆栈到Equals和==的比較
  20. Android设计中的.9.png图片

热门文章

  1. Ztree异步加载自动展开节点
  2. Unity 3D本地发布WebPlayer版时Failed to download data file解决方案
  3. Win2003x64系统
  4. oracle 分区表
  5. Calender的使用详解
  6. 【poj1962】 Corporative Network
  7. (BZOJ4538)HNOI2016 网络
  8. Redis Installation、Configuration、Program Based On Redis Learning
  9. Android Studio学习笔记
  10. EasyUI queryParams属性 在请求远程数据同时给action方法传参