| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474 |
- using UnityEngine;
- using UnityEngine.Events;
- using UnityEngine.EventSystems;
- using System;
- using System.Collections.Generic;
- using LuaInterface;
- namespace UnityEngine.UI
- {
- //Lua中调用的回调函数
- public delegate void LuaUpdateCellCallback(LuaTable self, GameObject go, int dataIndex);
- [AddComponentMenu("")]
- [DisallowMultipleComponent]
- [RequireComponent(typeof(RectTransform))]
- public abstract class LoopScrollRect : UIBehaviour, IInitializePotentialDragHandler, IBeginDragHandler, IEndDragHandler, IDragHandler, IScrollHandler, ICanvasElement, ILayoutElement, ILayoutGroup
- {
- /// <summary>
- /// 更新Cell中的回调函数
- /// </summary>
- /// <param name="go"></param>
- /// <param name="dataIndex"></param>
- public delegate void UpdateCellCallback(GameObject go,int dataIndex);
- //==========LoopScrollRect==========
- [HideInInspector]
- public int totalCount; //negative means INFINITE mode
- [HideInInspector]
- [NonSerialized]
-
- public object[] objectsToFill = null;
- [HideInInspector]
-
- public bool reverseDirection = false;
- [HideInInspector]
-
- public float rubberScale = 1;
- [HideInInspector]
-
- public float threshold = 100;
- [HideInInspector]
- public bool lowGrid = false;
- private int m_nFrame = 3;
- private bool m_bClampedMove = false;
- protected int itemTypeStart = 0;
- protected int itemTypeEnd = 0;
- protected abstract float GetSize(RectTransform item);
- protected abstract float GetDimension(Vector2 vector);
- protected abstract Vector2 GetVector(float value);
- protected int directionSign = 0;
- private float m_ContentSpacing = -1;
- protected GridLayoutGroup m_GridLayout = null;
- protected float contentSpacing
- {
- get
- {
- if (m_ContentSpacing >= 0)
- {
- return m_ContentSpacing;
- }
- m_ContentSpacing = 0;
- if (content != null)
- {
- HorizontalOrVerticalLayoutGroup layout1 = content.GetComponent<HorizontalOrVerticalLayoutGroup>();
- if (layout1 != null)
- {
- m_ContentSpacing = layout1.spacing;
- }
- m_GridLayout = content.GetComponent<GridLayoutGroup>();
- if (m_GridLayout != null)
- {
- m_ContentSpacing = GetDimension(m_GridLayout.spacing);
- }
- }
- return m_ContentSpacing;
- }
- }
- protected int mContentCount = 0;
- public int ContentCount
- {
- get { return mContentCount; }
- set { mContentCount = value; }
- }
- private UpdateCellCallback mCellCallback = null;
- int mMovePos = 0;
- bool dirty = false;
- bool force = false;
-
- public UpdateCellCallback CellCallback
- {
- set { mCellCallback = value; }
- }
- private LuaUpdateCellCallback mLuaCellCallback = null;
- private LuaTable luaSelf = null;
- private LuaFunction mCellCallbackLua = null;
- public LuaFunction CellCallbackLua
- {
- set { mCellCallbackLua = value; }
- }
- private LuaFunction mLuaCellCallbackLua = null;
- private int m_ContentConstraintCount = 0;
- public int contentConstraintCount
- {
- get
- {
- if (m_ContentConstraintCount > 0)
- {
- return m_ContentConstraintCount;
- }
- m_ContentConstraintCount = 1;
- if (content != null)
- {
- GridLayoutGroup layout2 = content.GetComponent<GridLayoutGroup>();
- if (layout2 != null)
- {
- if (layout2.constraint == GridLayoutGroup.Constraint.Flexible)
- {
- DebugHelper.Log("[LoopScrollRect] Flexible not supported yet");
- }
- m_ContentConstraintCount = layout2.constraintCount;
- }
- }
- return m_ContentConstraintCount;
- }
- }
- public int ItemTypeStart
- {
- get { return itemTypeStart; }
- }
- public int ItemTypeEnd
- {
- get { return itemTypeEnd; }
- }
- protected virtual bool UpdateItems(Bounds viewBounds, Bounds contentBounds) { return false; }
- //==========LoopScrollRect==========
- public enum MovementType
- {
- Unrestricted, // Unrestricted movement -- can scroll forever
- Elastic, // Restricted but flexible -- can go past the edges, but springs back in place
- Clamped, // Restricted movement where it's not possible to go past the edges
- }
- public enum ScrollbarVisibility
- {
- Permanent,
- AutoHide,
- AutoHideAndExpandViewport,
- }
- [Serializable]
- public class ScrollRectEvent : UnityEvent<Vector2> { }
- [SerializeField]
- private Transform m_Cell;
- public Transform Cell { get { return m_Cell; } set { m_Cell = value; } }
- [SerializeField]
- private RectTransform m_Content;
-
- public RectTransform content { get { return m_Content; } set { m_Content = value; } }
- [SerializeField]
- private bool m_Horizontal = true;
-
- public bool horizontal { get { return m_Horizontal; } set { m_Horizontal = value; } }
- [SerializeField]
- private bool m_Vertical = true;
-
- public bool vertical { get { return m_Vertical; } set { m_Vertical = value; } }
- [SerializeField]
- private MovementType m_MovementType = MovementType.Elastic;
-
- public MovementType movementType { get { return m_MovementType; } set { m_MovementType = value; } }
- [SerializeField]
- private float m_Elasticity = 0.1f; // Only used for MovementType.Elastic
-
- public float elasticity { get { return m_Elasticity; } set { m_Elasticity = value; } }
- [SerializeField]
- private bool m_Inertia = true;
-
- public bool inertia { get { return m_Inertia; } set { m_Inertia = value; } }
- [SerializeField]
- private float m_DecelerationRate = 0.135f; // Only used when inertia is enabled
-
- public float decelerationRate { get { return m_DecelerationRate; } set { m_DecelerationRate = value; } }
- [SerializeField]
- private float m_ScrollSensitivity = 1.0f;
-
- public float scrollSensitivity { get { return m_ScrollSensitivity; } set { m_ScrollSensitivity = value; } }
- [SerializeField]
- private RectTransform m_Viewport;
-
- public RectTransform viewport { get { return m_Viewport; } set { m_Viewport = value; SetDirtyCaching(); } }
- [SerializeField]
- private Scrollbar m_HorizontalScrollbar;
-
- public Scrollbar horizontalScrollbar
- {
- get
- {
- return m_HorizontalScrollbar;
- }
- set
- {
- if (m_HorizontalScrollbar)
- m_HorizontalScrollbar.onValueChanged.RemoveListener(SetHorizontalNormalizedPosition);
- m_HorizontalScrollbar = value;
- if (m_HorizontalScrollbar)
- m_HorizontalScrollbar.onValueChanged.AddListener(SetHorizontalNormalizedPosition);
- SetDirtyCaching();
- }
- }
- [SerializeField]
- private Scrollbar m_VerticalScrollbar;
-
- public Scrollbar verticalScrollbar
- {
- get
- {
- return m_VerticalScrollbar;
- }
- set
- {
- if (m_VerticalScrollbar)
- m_VerticalScrollbar.onValueChanged.RemoveListener(SetVerticalNormalizedPosition);
- m_VerticalScrollbar = value;
- if (m_VerticalScrollbar)
- m_VerticalScrollbar.onValueChanged.AddListener(SetVerticalNormalizedPosition);
- SetDirtyCaching();
- }
- }
- [SerializeField]
- private ScrollbarVisibility m_HorizontalScrollbarVisibility;
-
- public ScrollbarVisibility horizontalScrollbarVisibility { get { return m_HorizontalScrollbarVisibility; } set { m_HorizontalScrollbarVisibility = value; SetDirtyCaching(); } }
- [SerializeField]
- private ScrollbarVisibility m_VerticalScrollbarVisibility;
-
- public ScrollbarVisibility verticalScrollbarVisibility { get { return m_VerticalScrollbarVisibility; } set { m_VerticalScrollbarVisibility = value; SetDirtyCaching(); } }
- [SerializeField]
- private float m_HorizontalScrollbarSpacing;
-
- public float horizontalScrollbarSpacing { get { return m_HorizontalScrollbarSpacing; } set { m_HorizontalScrollbarSpacing = value; SetDirty(); } }
- [SerializeField]
- private float m_VerticalScrollbarSpacing;
-
- public float verticalScrollbarSpacing { get { return m_VerticalScrollbarSpacing; } set { m_VerticalScrollbarSpacing = value; SetDirty(); } }
- [SerializeField]
- private ScrollRectEvent m_OnValueChanged = new ScrollRectEvent();
-
- public ScrollRectEvent onValueChanged { get { return m_OnValueChanged; } set { m_OnValueChanged = value; } }
- // The offset from handle position to mouse down position
- private Vector2 m_PointerStartLocalCursor = Vector2.zero;
- private Vector2 m_ContentStartPosition = Vector2.zero;
- private RectTransform m_ViewRect;
- protected RectTransform viewRect
- {
- get
- {
- if (m_ViewRect == null)
- m_ViewRect = m_Viewport;
- if (m_ViewRect == null)
- m_ViewRect = (RectTransform)transform;
- return m_ViewRect;
- }
- }
- private Bounds m_ContentBounds;
- private Bounds m_ViewBounds;
- private Vector2 m_Velocity;
-
- public Vector2 velocity { get { return m_Velocity; } set { m_Velocity = value; } }
- private bool m_Dragging;
- public bool IsDragging { get { return m_Dragging; } }
- private Vector2 m_PrevPosition = Vector2.zero;
- private Bounds m_PrevContentBounds;
- private Bounds m_PrevViewBounds;
- [NonSerialized]
- private bool m_HasRebuiltLayout = false;
- private bool m_HSliderExpand;
- private bool m_VSliderExpand;
- private float m_HSliderHeight;
- private float m_VSliderWidth;
- [System.NonSerialized]
- private RectTransform m_Rect;
- private RectTransform rectTransform
- {
- get
- {
- if (m_Rect == null)
- m_Rect = GetComponent<RectTransform>();
- return m_Rect;
- }
- }
- private RectTransform m_HorizontalScrollbarRect;
- private RectTransform m_VerticalScrollbarRect;
- private DrivenRectTransformTracker m_Tracker;
- public System.Action mOnBeginDragAction = null;
- public System.Action mOnDragingAction = null;
- public System.Action mOnEndDragAction = null;
- private LuaFunction mOnBeginDragLuaFun = null;
- private LuaFunction mOnDragLuaFun = null;
- private LuaFunction mOnEndDragLuaFun = null;
- protected LoopScrollRect()
- {
- flexibleWidth = -1;
- }
- public void ForbidMove()
- {
- m_MovementType = MovementType.Clamped;
- }
- int preIdx = 0;
- //==========LoopScrollRect==========
- void UpdateScrollCell(Transform go,int idx)
- {
- if(mCellCallback != null)
- {
- mCellCallback(go.gameObject, idx);
- }
- if(luaSelf!=null && mLuaCellCallback!=null)
- {
- preIdx = idx;
- mLuaCellCallback.DynamicInvoke(luaSelf, go.gameObject,idx);
- }
- }
- public void ClearCells()
- {
- if (Application.isPlaying)
- {
- /*Vector2 sizeDelta = m_Content.sizeDelta;
- sizeDelta.x = 0;
- sizeDelta.y = 0;
- m_Content.sizeDelta = sizeDelta;*/
- itemTypeStart = 0;
- itemTypeEnd = 0;
- totalCount = 0;
- objectsToFill = null;
- for (int i = content.childCount - 1; i >= 0; i--)
- {
- GarbageGo(content.GetChild(i).gameObject);
- }
- //m_Content.anchoredPosition3D = Vector3.zero;
- }
- }
- public void ClearAnchoredPostion()
- {
- if (null == m_Content)
- return;
- m_Content.anchoredPosition3D = Vector3.zero;
- }
- public void ResetClampOffset()
- {
- m_nFrame = 3;
- m_bClampedMove = true;
- }
- public void Reset()
- {
- itemTypeStart = 0;
- itemTypeEnd = 0;
- totalCount = 0;
- objectsToFill = null;
- }
- public void DestroyCells()
- {
- DestroyCells(false);
- }
- public void DestroyCells(bool immediate)
- {
- itemTypeStart = 0;
- itemTypeEnd = 0;
- totalCount = 0;
- for (int i = content.childCount-1; i>=0;i--)
- {
- //这里改成DestroyImmediate确保childCount立即更新
- if(immediate)
- {
- content.GetChild(i).gameObject.DestroyImmediate();
- }
- else
- {
- GameObject.Destroy(content.GetChild(i).gameObject);
- }
- //
- }
- while(mAvailableObj.Count > 0)
- {
- if(immediate)
- {
- var go = mAvailableObj.Pop();
- if (go != null)
- go.DestroyImmediate();
- }
- else
- {
- GameObject.Destroy(mAvailableObj.Pop());
- }
- }
- }
- public void ResetItemTypeStart()
- {
- itemTypeStart = 0;
- }
- public void RefreshCells()
- {
- if (Application.isPlaying && this.isActiveAndEnabled)
- {
- itemTypeEnd = itemTypeStart;
- // recycle items if we can
- for (int i = 0; i < content.childCount; i++)
- {
- if (itemTypeEnd < totalCount)
- {
- UpdateScrollCell(content.GetChild(i), itemTypeEnd);
- itemTypeEnd++;
- }
- else
- {
- GarbageGo(content.GetChild(i).gameObject);
- i--;
- }
- }
- }
- }
- public void RefreshCellsData()
- {
- if (Application.isPlaying && this.isActiveAndEnabled)
- {
- for (int idx = itemTypeStart; idx < totalCount; idx++)
- {
- int childIdx = idx - itemTypeStart;
- if (childIdx < content.childCount)
- {
- UpdateScrollCell(content.GetChild(childIdx), idx);
- }
- }
- }
- }
- public void MoveTo(int index)
- {
- if (index < 0 || index >= totalCount)
- return;
- mMovePos = index;
- dirty = true;
- force = false;
- }
- public void ForceMoveTo(int index)
- {
- if (index < 0 || index >= totalCount)
- return;
- mMovePos = index;
- dirty = true;
- force = true;
- }
- public void SetItemStartIdx(int index)
- {
- itemTypeStart = index;
- itemTypeEnd = index;
- }
- public void SetUpdateCellCallback(LuaTable self,LuaUpdateCellCallback cb)
- {
- luaSelf = self;
- mLuaCellCallback = cb;
- }
- public void SetDragLuaCallback(LuaFunction cb)
- {
- mOnDragLuaFun = cb;
- }
- public void SetOnDragLuaCallback(LuaFunction cb)
- {
- mOnBeginDragLuaFun = cb;
- }
- public void SetOnEndDragLuaCallback(LuaFunction cb)
- {
- mOnEndDragLuaFun = cb;
- }
- protected float NewItemAtStart()
- {
- if (totalCount >= 0 && itemTypeStart - contentConstraintCount < 0)
- {
- return 0;
- }
- float size = 0;
- for (int i = 0; i < contentConstraintCount; i++)
- {
- itemTypeStart--;
- RectTransform newItem = InstantiateNextItem(itemTypeStart);
- newItem.SetAsFirstSibling();
- size = Mathf.Max(GetSize(newItem), size);
- }
- if (!reverseDirection)
- {
- Vector2 offset = GetVector(size);
- content.anchoredPosition += offset;
- m_PrevPosition += offset;
- m_ContentStartPosition += offset;
- }
- return size;
- }
- protected float DeleteItemAtStart()
- {
- if ((totalCount >= 0 && itemTypeEnd >= totalCount - 1) || content.childCount == 0)
- {
- return 0;
- }
- float size = 0;
- for (int i = 0; i < contentConstraintCount; i++)
- {
- RectTransform oldItem = content.GetChild(0) as RectTransform;
- size = Mathf.Max(GetSize(oldItem), size);
- GarbageGo(oldItem.gameObject);
- itemTypeStart++;
- if (content.childCount == 0)
- {
- break;
- }
- }
- if (!reverseDirection)
- {
- Vector2 offset = GetVector(size);
- content.anchoredPosition -= offset;
- m_PrevPosition -= offset;
- m_ContentStartPosition -= offset;
- }
- return size;
- }
- /// <summary>
- /// 在尾部追加一个元素
- /// </summary>
- /// <returns></returns>
- protected float NewItemAtEnd()
- {
- if (totalCount >= 0 && itemTypeEnd >= totalCount)
- {
- return 0;
- }
- float size = 0;
- // issue 4: fill lines to end first
- int count = contentConstraintCount - (content.childCount % contentConstraintCount);
- for (int i = 0; i < count; i++)
- {
- RectTransform newItem = InstantiateNextItem(itemTypeEnd);
- size = Mathf.Max(GetSize(newItem), size);
- itemTypeEnd++;
- if (totalCount >= 0 && itemTypeEnd >= totalCount)
- {
- break;
- }
- }
- if (reverseDirection)
- {
- Vector2 offset = GetVector(size);
- content.anchoredPosition -= offset;
- m_PrevPosition -= offset;
- m_ContentStartPosition -= offset;
- }
- return size;
- }
- /// <summary>
- /// 删除列表后面的元素
- /// </summary>
- /// <returns></returns>
- protected float DeleteItemAtEnd()
- {
- if ((totalCount >= 0 && itemTypeStart < contentConstraintCount) || content.childCount == 0 || itemTypeEnd == 0)
- {
- return 0;
- }
- float size = 0;
- for (int i = 0; i < contentConstraintCount; i++)
- {
-
- RectTransform oldItem = content.GetChild(content.childCount - 1) as RectTransform;
- size = Mathf.Max(GetSize(oldItem), size);
- GarbageGo(oldItem.gameObject);
- itemTypeEnd--;
- if (itemTypeEnd % contentConstraintCount == 0 || content.childCount == 0)
- {
- break; //just delete the whole row
- }
- }
- if (reverseDirection)
- {
- Vector2 offset = GetVector(size);
- content.anchoredPosition += offset;
- m_PrevPosition += offset;
- m_ContentStartPosition += offset;
- }
- return size;
- }
- private RectTransform InstantiateNextItem(int itemIdx)
- {
- GameObject go = CreateGO();
- if (go == null) return null;
- RectTransform nextItem = go.GetComponent<RectTransform>();
- nextItem.transform.SetParent(content, false);
- nextItem.gameObject.SetActive(true);
- UpdateScrollCell(nextItem, itemIdx);
- return nextItem;
- }
- Stack<GameObject> mAvailableObj = new Stack<GameObject>();
- GameObject CreateGO()
- {
- if (m_Cell == null) return null;
- GameObject go = null;
- if(mAvailableObj.Count > 0)
- {
- go = mAvailableObj.Pop();
- }else
- {
- go = GameObject.Instantiate(m_Cell.gameObject);
- go.transform.SetParent(content, false);
- go.transform.localScale = m_Cell.transform.localScale;
- }
- return go;
- }
- void GarbageGo(GameObject go)
- {
- go.SetActive(false);
- go.transform.SetParent(this.transform, false);
- mAvailableObj.Push(go);
- }
- //==========LoopScrollRect==========
-
- public virtual void Rebuild(CanvasUpdate executing)
- {
- if (executing == CanvasUpdate.Prelayout)
- {
- UpdateCachedData();
- }
- if (executing == CanvasUpdate.PostLayout)
- {
- UpdateBounds(false);
- UpdateScrollbars(Vector2.zero);
- UpdatePrevData();
- m_HasRebuiltLayout = true;
- }
- }
-
- public virtual void LayoutComplete()
- { }
-
- public virtual void GraphicUpdateComplete()
- { }
- void UpdateCachedData()
- {
- Transform transform = this.transform;
- m_HorizontalScrollbarRect = m_HorizontalScrollbar == null ? null : m_HorizontalScrollbar.transform as RectTransform;
- m_VerticalScrollbarRect = m_VerticalScrollbar == null ? null : m_VerticalScrollbar.transform as RectTransform;
- // These are true if either the elements are children, or they don't exist at all.
- bool viewIsChild = (viewRect.parent == transform);
- bool hScrollbarIsChild = (!m_HorizontalScrollbarRect || m_HorizontalScrollbarRect.parent == transform);
- bool vScrollbarIsChild = (!m_VerticalScrollbarRect || m_VerticalScrollbarRect.parent == transform);
- bool allAreChildren = (viewIsChild && hScrollbarIsChild && vScrollbarIsChild);
- m_HSliderExpand = allAreChildren && m_HorizontalScrollbarRect && horizontalScrollbarVisibility == ScrollbarVisibility.AutoHideAndExpandViewport;
- m_VSliderExpand = allAreChildren && m_VerticalScrollbarRect && verticalScrollbarVisibility == ScrollbarVisibility.AutoHideAndExpandViewport;
- m_HSliderHeight = (m_HorizontalScrollbarRect == null ? 0 : m_HorizontalScrollbarRect.rect.height);
- m_VSliderWidth = (m_VerticalScrollbarRect == null ? 0 : m_VerticalScrollbarRect.rect.width);
- }
- protected override void OnEnable()
- {
- base.OnEnable();
- if (m_HorizontalScrollbar)
- m_HorizontalScrollbar.onValueChanged.AddListener(SetHorizontalNormalizedPosition);
- if (m_VerticalScrollbar)
- m_VerticalScrollbar.onValueChanged.AddListener(SetVerticalNormalizedPosition);
- CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
- }
- protected override void OnDisable()
- {
- CanvasUpdateRegistry.UnRegisterCanvasElementForRebuild(this);
- if (m_HorizontalScrollbar)
- m_HorizontalScrollbar.onValueChanged.RemoveListener(SetHorizontalNormalizedPosition);
- if (m_VerticalScrollbar)
- m_VerticalScrollbar.onValueChanged.RemoveListener(SetVerticalNormalizedPosition);
- m_HasRebuiltLayout = false;
- m_Tracker.Clear();
- m_Velocity = Vector2.zero;
- LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
- base.OnDisable();
- }
-
- public override bool IsActive()
- {
- return base.IsActive() && m_Content != null;
- }
- private void EnsureLayoutHasRebuilt()
- {
- if (!m_HasRebuiltLayout && !CanvasUpdateRegistry.IsRebuildingLayout())
- Canvas.ForceUpdateCanvases();
- }
-
- public virtual void StopMovement()
- {
- m_Velocity = Vector2.zero;
- }
- public void SetScrollToPosition(Vector2 pos)
- {
- DebugHelper.LogError(pos);
- SetContentAnchoredPosition(pos);
- }
-
- public virtual void OnScroll(PointerEventData data)
- {
- if (!IsActive())
- return;
- EnsureLayoutHasRebuilt();
- UpdateBounds();
- Vector2 delta = data.scrollDelta;
- // Down is positive for scroll events, while in UI system up is positive.
- delta.y *= -1;
- if (vertical && !horizontal)
- {
- if (Mathf.Abs(delta.x) > Mathf.Abs(delta.y))
- delta.y = delta.x;
- delta.x = 0;
- }
- if (horizontal && !vertical)
- {
- if (Mathf.Abs(delta.y) > Mathf.Abs(delta.x))
- delta.x = delta.y;
- delta.y = 0;
- }
- Vector2 position = m_Content.anchoredPosition;
- position += delta * m_ScrollSensitivity;
- if (m_MovementType == MovementType.Clamped)
- position += CalculateOffset(position - m_Content.anchoredPosition);
- SetContentAnchoredPosition(position);
- UpdateBounds();
- }
-
- public virtual void OnInitializePotentialDrag(PointerEventData eventData)
- {
- if (eventData.button != PointerEventData.InputButton.Left)
- return;
- m_Velocity = Vector2.zero;
- }
-
- public virtual void OnBeginDrag(PointerEventData eventData)
- {
- if (eventData.button != PointerEventData.InputButton.Left)
- return;
- if (!IsActive())
- return;
- UpdateBounds();
- m_PointerStartLocalCursor = Vector2.zero;
- RectTransformUtility.ScreenPointToLocalPointInRectangle(viewRect, eventData.position, eventData.pressEventCamera, out m_PointerStartLocalCursor);
- m_ContentStartPosition = m_Content.anchoredPosition;
- m_Dragging = true;
- if (mOnBeginDragAction != null)
- mOnBeginDragAction();
- if(mOnBeginDragLuaFun != null && luaSelf != null)
- mOnBeginDragLuaFun.Call(luaSelf);
- }
-
- public virtual void OnEndDrag(PointerEventData eventData)
- {
- if (eventData.button != PointerEventData.InputButton.Left)
- return;
- m_Dragging = false;
- if (mOnEndDragAction != null)
- mOnEndDragAction();
- if (mOnEndDragLuaFun != null && luaSelf != null)
- mOnEndDragLuaFun.Call(luaSelf);
- }
-
- public virtual void OnDrag(PointerEventData eventData)
- {
- if (eventData.button != PointerEventData.InputButton.Left)
- return;
- if (!IsActive())
- return;
- Vector2 localCursor;
- if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(viewRect, eventData.position, eventData.pressEventCamera, out localCursor))
- return;
- UpdateBounds();
- var pointerDelta = localCursor - m_PointerStartLocalCursor;
- Vector2 position = m_ContentStartPosition + pointerDelta;
- // Offset to get content into place in the view.
- Vector2 offset = CalculateOffset(position - m_Content.anchoredPosition);
- position += offset;
- if (m_MovementType == MovementType.Elastic)
- {
- //==========LoopScrollRect==========
- if (offset.x != 0)
- position.x = position.x - RubberDelta(offset.x, m_ViewBounds.size.x) * rubberScale;
- if (offset.y != 0)
- position.y = position.y - RubberDelta(offset.y, m_ViewBounds.size.y) * rubberScale;
- //==========LoopScrollRect==========
- }
- SetContentAnchoredPosition(position);
- if (mOnDragingAction != null)
- mOnDragingAction();
- if (mOnDragLuaFun != null && luaSelf != null)
- mOnDragLuaFun.Call(luaSelf);
- }
- protected virtual void SetContentAnchoredPosition(Vector2 position)
- {
- if (!m_Horizontal)
- position.x = m_Content.anchoredPosition.x;
- if (!m_Vertical)
- position.y = m_Content.anchoredPosition.y;
- if (position != m_Content.anchoredPosition)
- {
- m_Content.anchoredPosition = position;
- UpdateBounds();
- }
- }
- protected virtual void LateUpdate()
- {
- if (!m_Content)
- return;
- EnsureLayoutHasRebuilt();
- UpdateScrollbarVisibility();
- UpdateBounds();
- float deltaTime = Time.unscaledDeltaTime;
- Vector2 offset = CalculateOffset(Vector2.zero);
- if (!m_Dragging && (offset != Vector2.zero || m_Velocity != Vector2.zero))
- {
- Vector2 position = m_Content.anchoredPosition;
- for (int axis = 0; axis < 2; axis++)
- {
- // Apply spring physics if movement is elastic and content has an offset from the view.
- if (m_MovementType == MovementType.Elastic && offset[axis] != 0)
- {
- float speed = m_Velocity[axis];
- position[axis] = Mathf.SmoothDamp(m_Content.anchoredPosition[axis], m_Content.anchoredPosition[axis] + offset[axis], ref speed, m_Elasticity, Mathf.Infinity, deltaTime);
- m_Velocity[axis] = speed;
- }
- // Else move content according to velocity with deceleration applied.
- else if (m_Inertia)
- {
- m_Velocity[axis] *= Mathf.Pow(m_DecelerationRate, deltaTime);
- if (Mathf.Abs(m_Velocity[axis]) < 1)
- m_Velocity[axis] = 0;
- position[axis] += m_Velocity[axis] * deltaTime;
- }
- // If we have neither elaticity or friction, there shouldn't be any velocity.
- else
- {
- m_Velocity[axis] = 0;
- }
- }
- if (m_Velocity != Vector2.zero)
- {
- if (m_MovementType == MovementType.Clamped)
- {
- offset = CalculateOffset(position - m_Content.anchoredPosition);
- position += offset;
- }
- SetContentAnchoredPosition(position);
- }
- }
- //Clamped 模式 三帧后强制对齐(确保加载后)在iphonex适配下启用
- if(m_bClampedMove)
- {
- if (m_nFrame != 0)
- m_nFrame -= 1;
- if (m_MovementType == MovementType.Clamped && offset.y != 0.0f && m_nFrame == 0)
- {
- Vector2 v2Postion = m_Content.anchoredPosition + offset;
- SetContentAnchoredPosition(v2Postion);
- m_bClampedMove = false;
- }
- }
- if (m_Dragging && m_Inertia)
- {
- Vector3 newVelocity = (m_Content.anchoredPosition - m_PrevPosition) / deltaTime;
- m_Velocity = Vector3.Lerp(m_Velocity, newVelocity, deltaTime * 10);
- }
- if (m_ViewBounds != m_PrevViewBounds || m_ContentBounds != m_PrevContentBounds || m_Content.anchoredPosition != m_PrevPosition)
- {
- UpdateScrollbars(offset);
- m_OnValueChanged.Invoke(normalizedPosition);
- UpdatePrevData();
- }
-
- if (dirty && (mMovePos > 0 || force) && content.childCount >= mContentCount)
- {
- if (mMovePos == totalCount - 1)
- {
- itemTypeStart = totalCount - content.childCount + 1;
- }
- else if((mMovePos + content.childCount) >= totalCount -1)
- {
- itemTypeStart = totalCount - mContentCount;
- }
- else
- itemTypeStart = mMovePos;
- RefreshCells();
- dirty = false;
- mMovePos = 0;
- force = false;
- }
- }
- private void UpdatePrevData()
- {
- if (m_Content == null)
- m_PrevPosition = Vector2.zero;
- else
- m_PrevPosition = m_Content.anchoredPosition;
- m_PrevViewBounds = m_ViewBounds;
- m_PrevContentBounds = m_ContentBounds;
- }
- private void UpdateScrollbars(Vector2 offset)
- {
- if (m_HorizontalScrollbar)
- {
- //==========LoopScrollRect==========
- if (m_ContentBounds.size.x > 0 && totalCount > 0)
- {
- m_HorizontalScrollbar.size = Mathf.Clamp01((m_ViewBounds.size.x - Mathf.Abs(offset.x)) / m_ContentBounds.size.x * (itemTypeEnd - itemTypeStart) / totalCount);
- }
- //==========LoopScrollRect==========
- else
- m_HorizontalScrollbar.size = 1;
- m_HorizontalScrollbar.value = horizontalNormalizedPosition;
- }
- if (m_VerticalScrollbar)
- {
- //==========LoopScrollRect==========
- if (m_ContentBounds.size.y > 0 && totalCount > 0)
- {
- m_VerticalScrollbar.size = Mathf.Clamp01((m_ViewBounds.size.y - Mathf.Abs(offset.y)) / m_ContentBounds.size.y * (itemTypeEnd - itemTypeStart) / totalCount);
- }
- //==========LoopScrollRect==========
- else
- m_VerticalScrollbar.size = 1;
- m_VerticalScrollbar.value = verticalNormalizedPosition;
- }
- }
- public Vector2 normalizedPosition
- {
- get
- {
- return new Vector2(horizontalNormalizedPosition, verticalNormalizedPosition);
- }
- set
- {
- SetNormalizedPosition(value.x, 0);
- SetNormalizedPosition(value.y, 1);
- }
- }
- public float horizontalNormalizedPosition
- {
- get
- {
- UpdateBounds(false);
- //==========LoopScrollRect==========
- if(totalCount > 0 && itemTypeEnd > itemTypeStart)
- {
- //TODO: space
- float elementSize = m_ContentBounds.size.x / (itemTypeEnd - itemTypeStart);
- float totalSize = elementSize * totalCount;
- float offset = m_ContentBounds.min.x - elementSize * itemTypeStart;
- if (totalSize <= m_ViewBounds.size.x)
- return (m_ViewBounds.min.x > offset) ? 1 : 0;
- return (m_ViewBounds.min.x - offset) / (totalSize - m_ViewBounds.size.x);
- }
- else
- return 0.5f;
- //==========LoopScrollRect==========
- }
- set
- {
- SetNormalizedPosition(value, 0);
- }
- }
- public float verticalNormalizedPosition
- {
- get
- {
- UpdateBounds(false);
- //==========LoopScrollRect==========
- if(totalCount > 0 && itemTypeEnd > itemTypeStart)
- {
- //TODO: space
- float elementSize = m_ContentBounds.size.y / (itemTypeEnd - itemTypeStart);
- float totalSize = elementSize * totalCount;
- float offset = m_ContentBounds.max.y + elementSize * itemTypeStart;
- if (totalSize <= m_ViewBounds.size.y)
- return (offset > m_ViewBounds.max.y) ? 1 : 0;
- return (offset - m_ViewBounds.max.y) / (totalSize - m_ViewBounds.size.y);
- }
- else
- return 0.5f;
- //==========LoopScrollRect==========
- }
- set
- {
- SetNormalizedPosition(value, 1);
- }
- }
-
- private void SetHorizontalNormalizedPosition(float value) { SetNormalizedPosition(value, 0); }
- private void SetVerticalNormalizedPosition(float value) { SetNormalizedPosition(value, 1); }
- private void SetNormalizedPosition(float value, int axis)
- {
- //==========LoopScrollRect==========
- if (totalCount <= 0 || itemTypeEnd <= itemTypeStart)
- return;
- //==========LoopScrollRect==========
- EnsureLayoutHasRebuilt();
- UpdateBounds();
- //==========LoopScrollRect==========
- Vector3 localPosition = m_Content.localPosition;
- float newLocalPosition = localPosition[axis];
- if (axis == 0)
- {
- float elementSize = m_ContentBounds.size.x / (itemTypeEnd - itemTypeStart);
- float totalSize = elementSize * totalCount;
- float offset = m_ContentBounds.min.x - elementSize * itemTypeStart;
-
- newLocalPosition += m_ViewBounds.min.x - value * (totalSize - m_ViewBounds.size[axis]) - offset;
- }
- else if(axis == 1)
- {
- float elementSize = m_ContentBounds.size.y / (itemTypeEnd - itemTypeStart);
- float totalSize = elementSize * totalCount;
- float offset = m_ContentBounds.max.y + elementSize * itemTypeStart;
-
- newLocalPosition -= offset - value * (totalSize - m_ViewBounds.size.y) - m_ViewBounds.max.y;
- }
- //==========LoopScrollRect==========
- if (Mathf.Abs(localPosition[axis] - newLocalPosition) > 0.01f)
- {
- localPosition[axis] = newLocalPosition;
- m_Content.localPosition = localPosition;
- m_Velocity[axis] = 0;
- UpdateBounds();
- }
- }
- private static float RubberDelta(float overStretching, float viewSize)
- {
- return (1 - (1 / ((Mathf.Abs(overStretching) * 0.55f / viewSize) + 1))) * viewSize * Mathf.Sign(overStretching);
- }
- protected override void OnRectTransformDimensionsChange()
- {
- SetDirty();
- }
- private bool hScrollingNeeded
- {
- get
- {
- if (Application.isPlaying)
- return m_ContentBounds.size.x > m_ViewBounds.size.x + 0.01f;
- return true;
- }
- }
- private bool vScrollingNeeded
- {
- get
- {
- if (Application.isPlaying)
- return m_ContentBounds.size.y > m_ViewBounds.size.y + 0.01f;
- return true;
- }
- }
-
- public virtual void CalculateLayoutInputHorizontal() { }
-
- public virtual void CalculateLayoutInputVertical() { }
-
- public virtual float minWidth { get { return -1; } }
-
- public virtual float preferredWidth { get { return -1; } }
-
- public virtual float flexibleWidth { get; private set; }
-
- public virtual float minHeight { get { return -1; } }
-
- public virtual float preferredHeight { get { return -1; } }
-
- public virtual float flexibleHeight { get { return -1; } }
-
- public virtual int layoutPriority { get { return -1; } }
-
- public virtual void SetLayoutHorizontal()
- {
- m_Tracker.Clear();
- if (m_HSliderExpand || m_VSliderExpand)
- {
- m_Tracker.Add(this, viewRect,
- DrivenTransformProperties.Anchors |
- DrivenTransformProperties.SizeDelta |
- DrivenTransformProperties.AnchoredPosition);
- // Make view full size to see if content fits.
- viewRect.anchorMin = Vector2.zero;
- viewRect.anchorMax = Vector2.one;
- viewRect.sizeDelta = Vector2.zero;
- viewRect.anchoredPosition = Vector2.zero;
- // Recalculate content layout with this size to see if it fits when there are no scrollbars.
- LayoutRebuilder.ForceRebuildLayoutImmediate(content);
- m_ViewBounds = new Bounds(viewRect.rect.center, viewRect.rect.size);
- m_ContentBounds = GetBounds();
- }
- // If it doesn't fit vertically, enable vertical scrollbar and shrink view horizontally to make room for it.
- if (m_VSliderExpand && vScrollingNeeded)
- {
- viewRect.sizeDelta = new Vector2(-(m_VSliderWidth + m_VerticalScrollbarSpacing), viewRect.sizeDelta.y);
- // Recalculate content layout with this size to see if it fits vertically
- // when there is a vertical scrollbar (which may reflowed the content to make it taller).
- LayoutRebuilder.ForceRebuildLayoutImmediate(content);
- m_ViewBounds = new Bounds(viewRect.rect.center, viewRect.rect.size);
- m_ContentBounds = GetBounds();
- }
- // If it doesn't fit horizontally, enable horizontal scrollbar and shrink view vertically to make room for it.
- if (m_HSliderExpand && hScrollingNeeded)
- {
- viewRect.sizeDelta = new Vector2(viewRect.sizeDelta.x, -(m_HSliderHeight + m_HorizontalScrollbarSpacing));
- m_ViewBounds = new Bounds(viewRect.rect.center, viewRect.rect.size);
- m_ContentBounds = GetBounds();
- }
- // If the vertical slider didn't kick in the first time, and the horizontal one did,
- // we need to check again if the vertical slider now needs to kick in.
- // If it doesn't fit vertically, enable vertical scrollbar and shrink view horizontally to make room for it.
- if (m_VSliderExpand && vScrollingNeeded && viewRect.sizeDelta.x == 0 && viewRect.sizeDelta.y < 0)
- {
- viewRect.sizeDelta = new Vector2(-(m_VSliderWidth + m_VerticalScrollbarSpacing), viewRect.sizeDelta.y);
- }
- }
-
- public virtual void SetLayoutVertical()
- {
- UpdateScrollbarLayout();
- m_ViewBounds = new Bounds(viewRect.rect.center, viewRect.rect.size);
- m_ContentBounds = GetBounds();
- }
- void UpdateScrollbarVisibility()
- {
- if (m_VerticalScrollbar && m_VerticalScrollbarVisibility != ScrollbarVisibility.Permanent && m_VerticalScrollbar.gameObject.activeSelf != vScrollingNeeded)
- m_VerticalScrollbar.gameObject.SetActive(vScrollingNeeded);
- if (m_HorizontalScrollbar && m_HorizontalScrollbarVisibility != ScrollbarVisibility.Permanent && m_HorizontalScrollbar.gameObject.activeSelf != hScrollingNeeded)
- m_HorizontalScrollbar.gameObject.SetActive(hScrollingNeeded);
- }
- void UpdateScrollbarLayout()
- {
- if (m_VSliderExpand && m_HorizontalScrollbar)
- {
- m_Tracker.Add(this, m_HorizontalScrollbarRect,
- DrivenTransformProperties.AnchorMinX |
- DrivenTransformProperties.AnchorMaxX |
- DrivenTransformProperties.SizeDeltaX |
- DrivenTransformProperties.AnchoredPositionX);
- m_HorizontalScrollbarRect.anchorMin = new Vector2(0, m_HorizontalScrollbarRect.anchorMin.y);
- m_HorizontalScrollbarRect.anchorMax = new Vector2(1, m_HorizontalScrollbarRect.anchorMax.y);
- m_HorizontalScrollbarRect.anchoredPosition = new Vector2(0, m_HorizontalScrollbarRect.anchoredPosition.y);
- if (vScrollingNeeded)
- m_HorizontalScrollbarRect.sizeDelta = new Vector2(-(m_VSliderWidth + m_VerticalScrollbarSpacing), m_HorizontalScrollbarRect.sizeDelta.y);
- else
- m_HorizontalScrollbarRect.sizeDelta = new Vector2(0, m_HorizontalScrollbarRect.sizeDelta.y);
- }
- if (m_HSliderExpand && m_VerticalScrollbar)
- {
- m_Tracker.Add(this, m_VerticalScrollbarRect,
- DrivenTransformProperties.AnchorMinY |
- DrivenTransformProperties.AnchorMaxY |
- DrivenTransformProperties.SizeDeltaY |
- DrivenTransformProperties.AnchoredPositionY);
- m_VerticalScrollbarRect.anchorMin = new Vector2(m_VerticalScrollbarRect.anchorMin.x, 0);
- m_VerticalScrollbarRect.anchorMax = new Vector2(m_VerticalScrollbarRect.anchorMax.x, 1);
- m_VerticalScrollbarRect.anchoredPosition = new Vector2(m_VerticalScrollbarRect.anchoredPosition.x, 0);
- if (hScrollingNeeded)
- m_VerticalScrollbarRect.sizeDelta = new Vector2(m_VerticalScrollbarRect.sizeDelta.x, -(m_HSliderHeight + m_HorizontalScrollbarSpacing));
- else
- m_VerticalScrollbarRect.sizeDelta = new Vector2(m_VerticalScrollbarRect.sizeDelta.x, 0);
- }
- }
- private void UpdateBounds(bool updateItems = true)
- {
- m_ViewBounds = new Bounds(viewRect.rect.center, viewRect.rect.size);
- m_ContentBounds = GetBounds();
- if (m_Content == null)
- return;
- // ============LoopScrollRect============
- // Don't do this in Rebuild
- if (Application.isPlaying && updateItems && UpdateItems(m_ViewBounds, m_ContentBounds))
- {
- Canvas.ForceUpdateCanvases();
- m_ContentBounds = GetBounds();
- }
- // ============LoopScrollRect============
- // Make sure content bounds are at least as large as view by adding padding if not.
- // One might think at first that if the content is smaller than the view, scrolling should be allowed.
- // However, that's not how scroll views normally work.
- // Scrolling is *only* possible when content is *larger* than view.
- // We use the pivot of the content rect to decide in which directions the content bounds should be expanded.
- // E.g. if pivot is at top, bounds are expanded downwards.
- // This also works nicely when ContentSizeFitter is used on the content.
- Vector3 contentSize = m_ContentBounds.size;
- Vector3 contentPos = m_ContentBounds.center;
- Vector3 excess = m_ViewBounds.size - contentSize;
- if (excess.x > 0)
- {
- contentPos.x -= excess.x * (m_Content.pivot.x - 0.5f);
- contentSize.x = m_ViewBounds.size.x;
- }
- if (excess.y > 0)
- {
- contentPos.y -= excess.y * (m_Content.pivot.y - 0.5f);
- contentSize.y = m_ViewBounds.size.y;
- }
- m_ContentBounds.size = contentSize;
- m_ContentBounds.center = contentPos;
- }
- private readonly Vector3[] m_Corners = new Vector3[4];
- private Bounds GetBounds()
- {
- if (m_Content == null)
- return new Bounds();
- var vMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
- var vMax = new Vector3(float.MinValue, float.MinValue, float.MinValue);
- var toLocal = viewRect.worldToLocalMatrix;
- m_Content.GetWorldCorners(m_Corners);
- for (int j = 0; j < 4; j++)
- {
- Vector3 v = toLocal.MultiplyPoint3x4(m_Corners[j]);
- vMin = Vector3.Min(v, vMin);
- vMax = Vector3.Max(v, vMax);
- }
- var bounds = new Bounds(vMin, Vector3.zero);
- bounds.Encapsulate(vMax);
- return bounds;
- }
- private Vector2 CalculateOffset(Vector2 delta)
- {
- Vector2 offset = Vector2.zero;
- if (m_MovementType == MovementType.Unrestricted)
- return offset;
- Vector2 min = m_ContentBounds.min;
- Vector2 max = m_ContentBounds.max;
- if (m_Horizontal)
- {
- min.x += delta.x;
- max.x += delta.x;
- if (min.x > m_ViewBounds.min.x)
- offset.x = m_ViewBounds.min.x - min.x;
- else if (max.x < m_ViewBounds.max.x)
- offset.x = m_ViewBounds.max.x - max.x;
- }
- if (m_Vertical)
- {
- min.y += delta.y;
- max.y += delta.y;
- if (max.y < m_ViewBounds.max.y)
- offset.y = m_ViewBounds.max.y - max.y;
- else if (min.y > m_ViewBounds.min.y)
- offset.y = m_ViewBounds.min.y - min.y;
- }
- return offset;
- }
- protected void SetDirty()
- {
- if (!IsActive())
- return;
- LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
- }
- protected void SetDirtyCaching()
- {
- if (!IsActive())
- return;
- CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
- LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
- }
- #if UNITY_EDITOR
- protected override void OnValidate()
- {
- SetDirtyCaching();
- }
- #endif
- }
- }
|