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

NGUI无限滑动的更多相关文章

  1. ViewPager结合view无限滑动

    使用viewPager进无限滑动,这里的实现是在适配器里面进行,当然在外头使用滑动监听也行. import android.support.v4.view.PagerAdapter; import a ...

  2. ViewPager无限滑动

    2016-6-19 前言 View轮播效果在app中很常见,一想到左右滑动的效果就很容易想到使用ViewPager来实现.对于像我们常说的banner这样的效果,具备无限滑动的功能是可以用ViewPa ...

  3. 使用ViewPager实现左右“无限”滑动的万年历

    有时候就是这样,研究一个问题,一开始想到了一个觉得可行的方案,然后去尝试:尝试了很久.很多次,已经要放弃了,关掉电脑心里 想这个需求没办法实现:在去上厕所的路上突然想到了一个点子,第二天一试,尼玛,搞 ...

  4. ViewPager结合Fragment进行无限滑动

    实现ViewPager结合Fragment实现无限循环切换,这里也是在适配器里面进行的,当然使用滑动监听也能够实现 import android.support.v4.app.Fragment; im ...

  5. Viewpage实现左右无限滑动

    实现逻辑参考:http://www.cnblogs.com/xinye/archive/2013/06/09/3129140.html 代码:如下 public class MainActivity ...

  6. ViewPager 简单实现左右无限滑动.

    只需在在适配器中将getCount 给一个较大的值, 然后将currentItem 设为值的一半 就可以伪实现 无限循环. private static final int PAGE_COUNT = ...

  7. [UI列表]LoopScrollRect无限滑动不卡顿

    应用场景 对于背包界面,排行榜列表,聊天消息,等有大量的UI列表的界面,常规做法是为每一条数据生成一个格子,在数据量越大的情况下,会生成越来越多的Gameobject,引起卡顿. 这篇文章讲述的就是解 ...

  8. NGUI实现滑动屏幕的时候,进行环形旋转

    在滑动屏幕的时候,上图中的内容饶圆中心旋转,并且箭头的方向保持不变 每个Item上挂载的脚本: using UnityEngine; public class ItemTest : MonoBehav ...

  9. android 实现 波纹效果+图片左右无限滑动缩放效果

    项目中用到的 ,记录下.说不定下次又用到了.就提取出来了. 录制效果一般,将就看吧.代码地址如下 https://yunpan.cn/ckQaXMpYwdUnn (提取码:7ac7)

随机推荐

  1. 自定义带图片和文字的ImageTextButton

    今天我们来讲一下有关自定义控件的问题,今天讲的这篇是从布局自定义开始的,难度不大,一看就明白,估计有的同学或者开发者看了说,这种方式多此一举,但是小编我不这么认为,多一种解决方式,就多一种举一反三的学 ...

  2. (旧)子数涵数·PS ——素描效果

    一.准备素材(均为在百度上下载的) 二.打开ps,并在ps中打开第一张素材 三.复制图层(好习惯) 四.去色将图像变成黑白,图像->调整->去色,快捷键为Ctrl+Shift+U 五,复制 ...

  3. How to set China Azure Storage Connection String

    Configure Visual Studio to access China Azure Storage Open Visual Studio 2012, Server Explorer Add n ...

  4. JavaScript基础---AJAX

    内容提纲: 1.XMLHttpRequest 2.GET与POST 3.封装Ajax  发文不易,转载请注明链接出处,谢谢! 2005年Jesse James Garrett发表了一篇文章,标题为:“ ...

  5. final和static

    /*    final修饰符  1. final修饰的类不能被继承,没有子类  2. final修饰的方法不能被子类覆盖  3. final修饰的变量表示常量,只能被赋值一次  4. final 修饰 ...

  6. JavaEE EL的一些用法

    EL 可以在指示元素中设置EL是否使用 isELIgnored="true" true是不使用 也可以在web.xml中使用 <jsp-config> <jsp- ...

  7. jquery 的 sort 函数

    members = [45, 23, 12, 34];members = members.sort(function(a, b){return a-b; );这里面a-b为升序,b-a降序排列:但a, ...

  8. iOS边练边学--多线程练习的多图片下载 以及 使用第三方框架(SDWebImage)的多图片下载

    一.自己实现多图片下载应该注意的问题 沙盒缓存的问题 程序缓存的问题 cell重复利用显示图片混乱的问题 -- 用户拖拽快,下载图片慢导致的 解决图片混乱引入NSOperation集合的问题 资源下载 ...

  9. 【UVALive 3905】BUPT 2015 newbie practice #2 div2-D-3905 - Meteor

    http://acm.hust.edu.cn/vjudge/contest/view.action?cid=102419#problem/D The famous Korean internet co ...

  10. 【BZOJ-1588】营业额统计 Splay

    1588: [HNOI2002]营业额统计 Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 12485  Solved: 4508[Submit][Sta ...