前言:CR作为SuperCell的热卖大作,受到很多用户的追捧.
玩法新颖,游戏性突出这些都不说了.它的UI体验也是别具一格令人感觉整个UI交互就像一个辅助生活的APP一样十分好用.
本系列最终效果展示:
[底部Button变换以及控制ScrollView翻页]
[水平滑动具有相册翻页效果同时底部Button响应]
[支持垂直滑动与水平滑动]
今天就来说说如何用NGUI实现CR的横向竖向都支持的滚动列表.
仔细观察CR的UI的滚动效果会发现,当你成功垂直滑动后按住不放,发现只能垂直滑动了,同样当你成功水平滑动后按住不放,后续也只能水平滑动.
那么思路便有了,检测到用户首次按下之后记录下射线检测到的位置,记为:mLastPos,然后当用户企图Drag时,分析onDrag函数传入的参数:Vector2 delta,如果delta.x的绝对值大于delta.y的绝对值那么就启用横向滑动列表,反之则启用垂直滑动列表.
开始我在每个ScrollView上Add了NGUI的UIGrid以及UIScrollView,为了响应拖动又在每个UISprite添加了UIDragScrollView.
然而这还不能实现我们想要的效果.
观察UIDragScrollView.cs中的源码:
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<UIScrollView>(mTrans);
mScroll = scrollView;
}
}
}
注意到,在检测到按入或按出时即onPress函数会调用UIScrollView的Press函数,并把是否按入\按出的信息传入.
再观察UIScrollView.cs中的对应源码,在Press函数中会有这么一段:
if (pressed)
{
// Remove all momentum on press
mMomentum = Vector3.zero;
mScroll = 0f;
// Disable the spring movement
DisableSpring();
// Remember the hit position
mLastPos = UICamera.lastWorldPosition;
// 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;
if (!smoothDragStart)
{
mDragStarted = true;
mDragStartOffset = Vector2.zero;
if (onDragStarted != null) onDragStarted();
}
}
注意这里
// Remember the hit position
mLastPos = UICamera.lastWorldPosition;
这是最关键的,我们希望在按入时相关的逻辑在分析出究竟使用场景中的HScrollView还是VScrollView后再进行处理.
因此我们需要把if(pressed){…}花括号里面的代码剪切走,延后执行.
为了不扰乱NGUI的正常功能,我分别对UIScrollView.cs以及UIDragScrollView.cs做了复制,重命名以及修改.
为了方便,我直接把全部代码放在这里:
(注:剪切走的代码放到了这里:)
//----------------------------------------------
// NGUI: Next-Gen UI kit
// Copyright © 2011-2015 Tasharen Entertainment
//----------------------------------------------
using UnityEngine;
///
/// 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.
///
[ExecuteInEditMode]
[RequireComponent(typeof(UIPanel))]
[AddComponentMenu("NGUI/Custom/Custom Scroll View")]
public class UICustomScrollView : MonoBehaviour
{
static public BetterList list = new BetterList();
public enum Movement
{
Horizontal,
Vertical,
Unrestricted,
Custom,
}
public enum DragEffect
{
None,
Momentum,
MomentumAndSpring,
}
public enum ShowCondition
{
Always,
OnlyIfNeeded,
WhenDragging,
}
public delegate void OnDragNotification ();
///
/// Type of movement allowed by the scroll view.
///
public Movement movement = Movement.Horizontal;
///
/// Effect to apply when dragging.
///
public DragEffect dragEffect = DragEffect.MomentumAndSpring;
///
/// Whether the dragging will be restricted to be within the scroll view's bounds.
///
public bool restrictWithinPanel = true;
///
/// Whether dragging will be disabled if the contents fit.
///
public bool disableDragIfFits = false;
///
/// Whether the drag operation will be started smoothly, or if if it will be precise (but will have a noticeable "jump").
///
public bool smoothDragStart = true;
///
/// 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.
///
public bool iOSDragEmulation = true;
///
/// Effect the scroll wheel will have on the momentum.
///
public float scrollWheelFactor = 0.25f;
///
/// How much momentum gets applied when the press is released after dragging.
///
public float momentumAmount = 35f;
///
/// Strength of the spring dampening effect.
///
public float dampenStrength = 9f;
///
/// Horizontal scrollbar used for visualization.
///
public UIProgressBar horizontalScrollBar;
///
/// Vertical scrollbar used for visualization.
///
public UIProgressBar verticalScrollBar;
///
/// Condition that must be met for the scroll bars to become visible.
///
public ShowCondition showScrollBars = ShowCondition.OnlyIfNeeded;
///
/// Custom movement, if the 'movement' field is set to 'Custom'.
///
public Vector2 customMovement = new Vector2(1f, 0f);
///
/// Content's pivot point -- where it originates from by default.
///
public UIWidget.Pivot contentPivot = UIWidget.Pivot.TopLeft;
///
/// Event callback to trigger when the drag process begins.
///
public OnDragNotification onDragStarted;
///
/// Event callback to trigger when the drag process finished. Can be used for additional effects, such as centering on some object.
///
public OnDragNotification onDragFinished;
///
/// Event callback triggered when the scroll view is moving as a result of momentum in between of OnDragFinished and OnStoppedMoving.
///
public OnDragNotification onMomentumMove;
///
/// Event callback to trigger when the scroll view's movement ends.
///
public OnDragNotification onStoppedMoving;
// 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;
///
/// Panel that's being dragged.
///
public UIPanel panel { get { return mPanel; } }
///
/// Whether the scroll view is being dragged.
///
public bool isDragging { get { return mPressed && mDragStarted; } }
///
/// Calculate the bounds used by the widgets.
///
public virtual Bounds bounds
{
get
{
if (!mCalculatedBounds)
{
mCalculatedBounds = true;
mTrans = transform;
mBounds = NGUIMath.CalculateRelativeWidgetBounds(mTrans, mTrans);
}
return mBounds;
}
}
///
/// Whether the scroll view can move horizontally.
///
public bool canMoveHorizontally
{
get
{
return movement == Movement.Horizontal ||
movement == Movement.Unrestricted ||
(movement == Movement.Custom && customMovement.x != 0f);
}
}
///
/// Whether the scroll view can move vertically.
///
public bool canMoveVertically
{
get
{
return movement == Movement.Vertical ||
movement == Movement.Unrestricted ||
(movement == Movement.Custom && customMovement.y != 0f);
}
}
///
/// Whether the scroll view should be able to move horizontally (contents don't fit).
///
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;
}
}
///
/// Whether the scroll view should be able to move vertically (contents don't fit).
///
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;
}
}
///
/// Whether the contents of the scroll view should actually be draggable depends on whether they currently fit or not.
///
protected virtual bool shouldMove
{
get
{
if (!disableDragIfFits) return true;
if (mPanel == null) mPanel = GetComponent();
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;
}
}
///
/// Current momentum, exposed just in case it's needed.
///
public Vector3 currentMomentum
{
get
{
return mMomentum;
}
set
{
mMomentum = value;
mShouldMove = true;
}
}
///
/// Cache the transform and the panel.
///
void Awake ()
{
mTrans = transform;
mPanel = GetComponent();
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
}
}
[System.NonSerialized] bool mStarted = false;
void OnEnable ()
{
list.Add(this);
if (mStarted && Application.isPlaying) CheckScrollbars();
}
void Start ()
{
mStarted = true;
if (Application.isPlaying) CheckScrollbars();
}
void CheckScrollbars ()
{
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;
}
}
void OnDisable () { list.Remove(this); }
///
/// Restrict the scroll view's contents to be within the scroll view's bounds.
///
public bool RestrictWithinBounds (bool instant) { return RestrictWithinBounds(instant, true, true); }
///
/// Restrict the scroll view's contents to be within the scroll view's bounds.
///
public bool RestrictWithinBounds (bool instant, bool horizontal, bool vertical)
{
if (mPanel == null) return false;
Bounds b = bounds;
Vector3 constraint = mPanel.CalculateConstrainOffset(b.min, b.max);
if (!horizontal) constraint.x = 0f;
if (!vertical) constraint.y = 0f;
if (constraint.sqrMagnitude > 0.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).strength = 8f;
}
else
{
// Jump back into place
MoveRelative(constraint);
// Clear the momentum in the constrained direction
if (Mathf.Abs(constraint.x) > 0.01f) mMomentum.x = 0;
if (Mathf.Abs(constraint.y) > 0.01f) mMomentum.y = 0;
if (Mathf.Abs(constraint.z) > 0.01f) mMomentum.z = 0;
mScroll = 0f;
}
return true;
}
return false;
}
///
/// Disable the spring movement.
///
public void DisableSpring ()
{
SpringPanel sp = GetComponent();
if (sp != null) sp.enabled = false;
}
///
/// Update the values of the associated scroll bars.
///
public void UpdateScrollbars () { UpdateScrollbars(true); }
///
/// Update the values of the associated scroll bars.
///
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;
}
}
///
/// Helper function used in UpdateScrollbars(float) function above.
///
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;
}
///
/// 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.
///
public virtual void SetDragAmount (float x, float y, bool updateScrollbars)
{
if (mPanel == null) mPanel = GetComponent();
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);
}
///
/// Manually invalidate the scroll view's bounds so that they update next time.
///
public void InvalidateBounds () { mCalculatedBounds = false; }
///
/// 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.
///
[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);
}
}
///
/// Call this function after you adjust the scroll view's bounds if you want it to maintain the current scrolled position
///
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;
}
}
///
/// Triggered by the scroll bars when they change.
///
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;
}
}
///
/// Move the scroll view by the specified local space amount.
///
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);
}
///
/// Move the scroll view by the specified world space amount.
///
public void MoveAbsolute (Vector3 absolute)
{
Vector3 a = mTrans.InverseTransformPoint(absolute);
Vector3 b = mTrans.InverseTransformPoint(Vector3.zero);
MoveRelative(a - b);
}
///
/// Create a plane on which we will be performing the dragging.
///
public void Press (bool pressed)
{
if (UICamera.currentScheme == UICamera.ControlScheme.Controller) return;
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)
{
}
else if (centerOnChild)
{
centerOnChild.Recenter();
}
else
{
if (restrictWithinPanel && mPanel.clipping != UIDrawCall.Clipping.None)
RestrictWithinBounds(dragEffect == DragEffect.None, canMoveHorizontally, canMoveVertically);
if (mDragStarted && onDragFinished != null) onDragFinished();
if (!mShouldMove && onStoppedMoving != null)
onStoppedMoving();
}
}
}
public void OnDelayPressEnter(Vector3 lastPos)
{
// Remove all momentum on press
mMomentum = Vector3.zero;
mScroll = 0f;
// Disable the spring movement
DisableSpring();
// Remember the hit position
mLastPos = lastPos;
// 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;
if (!smoothDragStart)
{
mDragStarted = true;
mDragStartOffset = Vector2.zero;
if (onDragStarted != null) onDragStarted();
}
}
///
/// Drag the object along the plane.
///
public void Drag ()
{
if (UICamera.currentScheme == UICamera.ControlScheme.Controller) return;
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;
if (onDragStarted != null) onDragStarted();
}
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
if (dragEffect == DragEffect.None) mMomentum = Vector3.zero;
else 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);
}
}
}
}
[HideInInspector]
public UICenterOnChild centerOnChild = null;
///
/// If the object should support the scroll wheel, do it.
///
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;
}
}
///
/// Apply the dragging momentum.
///
void LateUpdate ()
{
if (!Application.isPlaying) return;
float delta = RealTime.deltaTime;
// Fade the scroll bars if needed
if (showScrollBars != ShowCondition.Always && (verticalScrollBar || horizontalScrollBar))
{
bool vertical = false;
bool horizontal = false;
if (showScrollBars != ShowCondition.WhenDragging || mDragID != -10 || mMomentum.magnitude > 0.01f)
{
vertical = shouldMoveVertically;
horizontal = shouldMoveHorizontally;
}
if (verticalScrollBar)
{
float alpha = verticalScrollBar.alpha;
alpha += vertical ? delta * 6f : -delta * 3f;
alpha = Mathf.Clamp01(alpha);
if (verticalScrollBar.alpha != alpha) verticalScrollBar.alpha = alpha;
}
if (horizontalScrollBar)
{
float alpha = horizontalScrollBar.alpha;
alpha += horizontal ? delta * 6f : -delta * 3f;
alpha = Mathf.Clamp01(alpha);
if (horizontalScrollBar.alpha != alpha) horizontalScrollBar.alpha = alpha;
}
}
if (!mShouldMove) return;
// Apply momentum
if (!mPressed)
{
if (mMomentum.magnitude > 0.0001f || mScroll != 0f)
{
if (movement == Movement.Horizontal)
{
mMomentum -= mTrans.TransformDirection(new Vector3(mScroll * 0.05f, 0f, 0f));
}
else if (movement == Movement.Vertical)
{
mMomentum -= mTrans.TransformDirection(new Vector3(0f, mScroll * 0.05f, 0f));
}
else if (movement == Movement.Unrestricted)
{
mMomentum -= mTrans.TransformDirection(new Vector3(mScroll * 0.05f, mScroll * 0.05f, 0f));
}
else
{
mMomentum -= mTrans.TransformDirection(new Vector3(
mScroll * customMovement.x * 0.05f,
mScroll * customMovement.y * 0.05f, 0f));
}
mScroll = NGUIMath.SpringLerp(mScroll, 0f, 20f, delta);
// Move the scroll view
Vector3 offset = NGUIMath.SpringDampen(ref mMomentum, dampenStrength, delta);
MoveAbsolute(offset);
// Restrict the contents to be within the scroll view's bounds
if (restrictWithinPanel && mPanel.clipping != UIDrawCall.Clipping.None)
{
if (NGUITools.GetActive(centerOnChild))
{
if (centerOnChild.nextPageThreshold != 0f)
{
mMomentum = Vector3.zero;
mScroll = 0f;
}
else centerOnChild.Recenter();
}
else
{
RestrictWithinBounds(false, canMoveHorizontally, canMoveVertically);
}
}
if (onMomentumMove != null)
onMomentumMove();
}
else
{
mScroll = 0f;
mMomentum = Vector3.zero;
SpringPanel sp = GetComponent();
if (sp != null && sp.enabled) return;
mShouldMove = false;
if (onStoppedMoving != null)
onStoppedMoving();
}
}
else
{
// Dampen the momentum
mScroll = 0f;
NGUIMath.SpringDampen(ref mMomentum, 9f, delta);
}
}
#if UNITY_EDITOR
///
/// Draw a visible orange outline of the bounds.
///
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
}
另外一个响应脚本:
//----------------------------------------------
// NGUI: Next-Gen UI kit
// Copyright © 2011-2015 Tasharen Entertainment
//----------------------------------------------
using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;
using System;
///
/// Allows dragging of the specified scroll view by mouse or touch.
///
[AddComponentMenu("NGUI/Custom/HV Drag Scroll View")]
public class UI_HV_DragScrollView : MonoBehaviour
{
///
/// Reference to the scroll view that will be dragged by the script.
///
public UICustomScrollView scrollView;
// Legacy functionality, kept for backwards compatibility. Use 'scrollView' instead.
[HideInInspector][SerializeField] UICustomScrollView draggablePanel;
Transform mTrans;
UICustomScrollView mScroll;
UICustomScrollView hScroll;//水平滚动的ScrollView
UICustomScrollView vScroll;//垂直滚动的ScrollView
UICustomScrollView currentScroll = null;
bool mAutoFind = false;
bool mStarted = false;
Vector3 mLastPos;
///
/// Automatically find the scroll view if possible.
///
void OnEnable ()
{
// mTrans = transform;
//
// // Auto-upgrade
// if (scrollView == null && draggablePanel != null)
// {
// scrollView = draggablePanel;
// draggablePanel = null;
// }
//
// if (mStarted && (mAutoFind || mScroll == null))
// FindScrollView();
}
///
/// Find the scroll view.
///
void Start ()
{
mStarted = true;
Initialize ();
}
void Initialize()
{
vScroll = transform.parent.GetComponent ();
hScroll = transform.parent.parent.GetComponent ();
}
///
/// Find the scroll view to work with.
///
///
/// Create a plane on which we will be performing the dragging.
///
void OnPress (bool pressed)
{
hScroll.Press (pressed);
vScroll.Press (pressed);
if (pressed)
{
mLastPos = UICamera.lastWorldPosition;
}
else
{
currentScroll = null;
}
}
///
/// Drag the object along the plane.
///
void OnDrag (Vector2 delta)
{
if (currentScroll == null)
{
//Debug.LogFormat ("delta.x == {0} delta.y == {1}",delta.x,delta.y);
if (Math.Abs (delta.x) > Math.Abs (delta.y)) {
currentScroll = hScroll;
} else
{
currentScroll = vScroll;
}
currentScroll.OnDelayPressEnter (mLastPos);
}
currentScroll.Drag ();
}
///
/// If the object should support the scroll wheel, do it.
///
void OnScroll (float delta)
{
if (scrollView && NGUITools.GetActive(this))
scrollView.Scroll(delta);
}
}
今天先到这里,接下来我会继续对效果进行补充和完善.