//---------------------------------------------- // NGUI: Next-Gen UI kit // Copyright © 2011-2015 Tasharen Entertainment //---------------------------------------------- using UnityEngine; using System.Collections.Generic; using Coolape; /// /// Ever wanted to be able to auto-center on an object within a draggable panel? /// Attach this script to the container that has the objects to center on as its children. /// [AddComponentMenu("NGUI/Interaction/Center Scroll View on Child")] public class UICenterOnChild : MonoBehaviour { public delegate void OnCenterCallback (GameObject centeredObject); /// /// The strength of the spring. /// public float springStrength = 8f; /// /// If set to something above zero, it will be possible to move to the next page after dragging past the specified threshold. /// public float nextPageThreshold = 0f; /// /// Callback to be triggered when the centering operation completes. /// public SpringPanel.OnFinished onFinished; /// /// Callback triggered whenever the script begins centering on a new child object. /// public OnCenterCallback onCenter; UIScrollView mScrollView; GameObject mCenteredObject; /// /// Game object that the draggable panel is currently centered on. /// public GameObject centeredObject { get { return mCenteredObject; } } void Start () { Recenter(); } void OnEnable () { if (mScrollView) { mScrollView.centerOnChild = this; Recenter(); } } void OnDisable () { if (mScrollView) mScrollView.centerOnChild = null; } void OnDragFinished () { if (enabled) Recenter(); } /// /// Ensure that the threshold is always positive. /// void OnValidate () { nextPageThreshold = Mathf.Abs(nextPageThreshold); } /// /// Recenter the draggable list on the center-most child. /// [ContextMenu("Execute")] public void Recenter () { if (mScrollView == null) { mScrollView = NGUITools.FindInParents(gameObject); if (mScrollView == null) { Debug.LogWarning(GetType() + " requires " + typeof(UIScrollView) + " on a parent object in order to work", this); enabled = false; return; } else { if (mScrollView) { mScrollView.centerOnChild = this; mScrollView.onDragFinished += OnDragFinished; } if (mScrollView.horizontalScrollBar != null) mScrollView.horizontalScrollBar.onDragFinished += OnDragFinished; if (mScrollView.verticalScrollBar != null) mScrollView.verticalScrollBar.onDragFinished += OnDragFinished; } } if (mScrollView.panel == null) return; Transform trans = transform; if (trans.childCount == 0) return; // Calculate the panel's center in world coordinates Vector3[] corners = mScrollView.panel.worldCorners; Vector3 panelCenter = (corners[2] + corners[0]) * 0.5f; // Offset this value by the momentum Vector3 momentum = mScrollView.currentMomentum * mScrollView.momentumAmount; Vector3 moveDelta = NGUIMath.SpringDampen(ref momentum, 9f, 2f); Vector3 pickingPoint = panelCenter - moveDelta * 0.01f; // Magic number based on what "feels right" float min = float.MaxValue; Transform closest = null; int index = 0; int ignoredIndex = 0; // Determine the closest child for (int i = 0, imax = trans.childCount, ii = 0; i < imax; ++i) { Transform t = trans.GetChild(i); if (!t.gameObject.activeInHierarchy) continue; float sqrDist = Vector3.SqrMagnitude(t.position - pickingPoint); if (sqrDist < min) { min = sqrDist; closest = t; index = i; ignoredIndex = ii; } ++ii; } // If we have a touch in progress and the next page threshold set if (nextPageThreshold > 0f && UICamera.currentTouch != null) { // If we're still on the same object if (mCenteredObject != null && mCenteredObject.transform == trans.GetChild(index)) { Vector3 totalDelta = UICamera.currentTouch.totalDelta; totalDelta = transform.rotation * totalDelta; float delta = 0f; switch (mScrollView.movement) { case UIScrollView.Movement.Horizontal: { delta = totalDelta.x; break; } case UIScrollView.Movement.Vertical: { delta = totalDelta.y; break; } default: { delta = totalDelta.magnitude; break; } } if (Mathf.Abs(delta) > nextPageThreshold) { UIGrid grid = GetComponent(); CLUILoopGrid loopGrid = GetComponent(); // add by chenbin if (loopGrid == null) { if (grid != null && grid.sorting != UIGrid.Sorting.None) { List list = grid.GetChildList (); if (delta > nextPageThreshold) { // Next page if (ignoredIndex > 0) closest = list [ignoredIndex - 1]; else closest = (GetComponent () == null) ? list [0] : list [list.Count - 1]; } else if (delta < -nextPageThreshold) { // Previous page if (ignoredIndex < list.Count - 1) closest = list [ignoredIndex + 1]; else closest = (GetComponent () == null) ? list [list.Count - 1] : list [0]; } } else Debug.LogWarning ("Next Page Threshold requires a sorted UIGrid in order to work properly", this); #region add by chenbin } else { int _index = NumEx.stringToInt(closest.name); if (delta > nextPageThreshold) { // Next page if (_index > 0) { _index--; closest = trans.Find(NumEx.nStrForLen(_index, 6)); } } else if (delta < -nextPageThreshold) { // Previous page if (_index < loopGrid.list.Count - 1) { _index++; closest = trans.Find(NumEx.nStrForLen(_index, 6)); } } } #endregion } } } CenterOn(closest, panelCenter); } /// /// Center the panel on the specified target. /// void CenterOn (Transform target, Vector3 panelCenter) { if (target != null && mScrollView != null && mScrollView.panel != null) { Transform panelTrans = mScrollView.panel.cachedTransform; mCenteredObject = target.gameObject; // Figure out the difference between the chosen child and the panel's center in local coordinates Vector3 cp = panelTrans.InverseTransformPoint(target.position); Vector3 cc = panelTrans.InverseTransformPoint(panelCenter); Vector3 localOffset = cp - cc; // Offset shouldn't occur if blocked if (!mScrollView.canMoveHorizontally) localOffset.x = 0f; if (!mScrollView.canMoveVertically) localOffset.y = 0f; localOffset.z = 0f; // Spring the panel to this calculated position #if UNITY_EDITOR if (!Application.isPlaying) { panelTrans.localPosition = panelTrans.localPosition - localOffset; Vector4 co = mScrollView.panel.clipOffset; co.x += localOffset.x; co.y += localOffset.y; mScrollView.panel.clipOffset = co; } else #endif { SpringPanel.Begin(mScrollView.panel.cachedGameObject, panelTrans.localPosition - localOffset, springStrength).onFinished = onFinished; } } else mCenteredObject = null; // Notify the listener if (onCenter != null) onCenter(mCenteredObject); } /// /// Center the panel on the specified target. /// public void CenterOn (Transform target) { if (mScrollView != null && mScrollView.panel != null) { Vector3[] corners = mScrollView.panel.worldCorners; Vector3 panelCenter = (corners[2] + corners[0]) * 0.5f; CenterOn(target, panelCenter); } } }