NGUI无限滑动
http://www.unity蛮牛.com/blog-9383-1391.html
最近由于工作需要,就开始研究NGUI滑动。刚开始参考NGUI自带的循环滑动,利用隐藏和显示,提高GPU的渲染,但是效果依旧不是很理想。在同事提醒下,添加缓存列表,不断刷新当前裁剪区域里的数据,最总完成了需求。在网上也参考了很多资料,今天恰好闲下来,就拿出来大家分享下,哈哈。代码附上:
////////////////////////////////////////////////////////////////////////////////
修改 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
}
[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 }
NGUI无限滑动的更多相关文章
- ViewPager结合view无限滑动
使用viewPager进无限滑动,这里的实现是在适配器里面进行,当然在外头使用滑动监听也行. import android.support.v4.view.PagerAdapter; import a ...
- ViewPager无限滑动
2016-6-19 前言 View轮播效果在app中很常见,一想到左右滑动的效果就很容易想到使用ViewPager来实现.对于像我们常说的banner这样的效果,具备无限滑动的功能是可以用ViewPa ...
- 使用ViewPager实现左右“无限”滑动的万年历
有时候就是这样,研究一个问题,一开始想到了一个觉得可行的方案,然后去尝试:尝试了很久.很多次,已经要放弃了,关掉电脑心里 想这个需求没办法实现:在去上厕所的路上突然想到了一个点子,第二天一试,尼玛,搞 ...
- ViewPager结合Fragment进行无限滑动
实现ViewPager结合Fragment实现无限循环切换,这里也是在适配器里面进行的,当然使用滑动监听也能够实现 import android.support.v4.app.Fragment; im ...
- Viewpage实现左右无限滑动
实现逻辑参考:http://www.cnblogs.com/xinye/archive/2013/06/09/3129140.html 代码:如下 public class MainActivity ...
- ViewPager 简单实现左右无限滑动.
只需在在适配器中将getCount 给一个较大的值, 然后将currentItem 设为值的一半 就可以伪实现 无限循环. private static final int PAGE_COUNT = ...
- [UI列表]LoopScrollRect无限滑动不卡顿
应用场景 对于背包界面,排行榜列表,聊天消息,等有大量的UI列表的界面,常规做法是为每一条数据生成一个格子,在数据量越大的情况下,会生成越来越多的Gameobject,引起卡顿. 这篇文章讲述的就是解 ...
- NGUI实现滑动屏幕的时候,进行环形旋转
在滑动屏幕的时候,上图中的内容饶圆中心旋转,并且箭头的方向保持不变 每个Item上挂载的脚本: using UnityEngine; public class ItemTest : MonoBehav ...
- android 实现 波纹效果+图片左右无限滑动缩放效果
项目中用到的 ,记录下.说不定下次又用到了.就提取出来了. 录制效果一般,将就看吧.代码地址如下 https://yunpan.cn/ckQaXMpYwdUnn (提取码:7ac7)
随机推荐
- 自定义带图片和文字的ImageTextButton
今天我们来讲一下有关自定义控件的问题,今天讲的这篇是从布局自定义开始的,难度不大,一看就明白,估计有的同学或者开发者看了说,这种方式多此一举,但是小编我不这么认为,多一种解决方式,就多一种举一反三的学 ...
- (旧)子数涵数·PS ——素描效果
一.准备素材(均为在百度上下载的) 二.打开ps,并在ps中打开第一张素材 三.复制图层(好习惯) 四.去色将图像变成黑白,图像->调整->去色,快捷键为Ctrl+Shift+U 五,复制 ...
- How to set China Azure Storage Connection String
Configure Visual Studio to access China Azure Storage Open Visual Studio 2012, Server Explorer Add n ...
- JavaScript基础---AJAX
内容提纲: 1.XMLHttpRequest 2.GET与POST 3.封装Ajax 发文不易,转载请注明链接出处,谢谢! 2005年Jesse James Garrett发表了一篇文章,标题为:“ ...
- final和static
/* final修饰符 1. final修饰的类不能被继承,没有子类 2. final修饰的方法不能被子类覆盖 3. final修饰的变量表示常量,只能被赋值一次 4. final 修饰 ...
- JavaEE EL的一些用法
EL 可以在指示元素中设置EL是否使用 isELIgnored="true" true是不使用 也可以在web.xml中使用 <jsp-config> <jsp- ...
- jquery 的 sort 函数
members = [45, 23, 12, 34];members = members.sort(function(a, b){return a-b; );这里面a-b为升序,b-a降序排列:但a, ...
- iOS边练边学--多线程练习的多图片下载 以及 使用第三方框架(SDWebImage)的多图片下载
一.自己实现多图片下载应该注意的问题 沙盒缓存的问题 程序缓存的问题 cell重复利用显示图片混乱的问题 -- 用户拖拽快,下载图片慢导致的 解决图片混乱引入NSOperation集合的问题 资源下载 ...
- 【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 ...
- 【BZOJ-1588】营业额统计 Splay
1588: [HNOI2002]营业额统计 Time Limit: 5 Sec Memory Limit: 162 MBSubmit: 12485 Solved: 4508[Submit][Sta ...