From 1826c50701bc2cfe07dc2663d1b7aa7ba3844a1f Mon Sep 17 00:00:00 2001
From: lcy <1459594991@qq.com>
Date: 星期三, 21 五月 2025 17:52:49 +0800
Subject: [PATCH] 59 子 【常规】邮件系统 / 【常规】邮件系统-客户端 摘取滚动条组件
---
Main/Component/UI/EnhancedScroller/EnhancedScrollerCellView.cs | 53
Main/System/WindowBase.meta | 8
Main/System/Skill/ScrollerController.cs | 622 ++++++++++
Main/Component/UI/EnhancedScroller/SmallList.cs.meta | 25
Main/Component/UI/EnhancedScroller/EnhancedScrollerCellView.cs.meta | 25
Main/Component/UI/EnhancedScroller/EnhancedScroller.cs.meta | 25
Main/System/Skill.meta | 8
Main/Component/UI/EnhancedScroller/IEnhancedScrollerDelegate.cs | 53
Main/System/Skill/CellView.cs.meta | 12
Main/System/Skill/ScrollerData.cs | 59
Main/System/Skill/ScrollerUI.cs | 11
Main/Component/UI/EnhancedScroller/SmallList.cs | 219 +++
Main/System/WindowBase/WidgetBehavior.cs | 84 +
Main/System/Skill/ScrollerData.cs.meta | 12
Main/System/Skill/CellView.cs | 106 +
Main/System/Skill/ScrollerController.cs.meta | 12
Main/System/WindowBase/WidgetBehavior.cs.meta | 11
Main/System/Skill/ScrollerUI.cs.meta | 12
Main/Component/UI/EnhancedScroller/EnhancedScroller.cs | 2260 +++++++++++++++++++++++++++++++++++++
Main/Component/UI/EnhancedScroller/IEnhancedScrollerDelegate.cs.meta | 25
20 files changed, 3,642 insertions(+), 0 deletions(-)
diff --git a/Main/Component/UI/EnhancedScroller/EnhancedScroller.cs b/Main/Component/UI/EnhancedScroller/EnhancedScroller.cs
new file mode 100644
index 0000000..ac9609a
--- /dev/null
+++ b/Main/Component/UI/EnhancedScroller/EnhancedScroller.cs
@@ -0,0 +1,2260 @@
+锘縰sing UnityEngine;
+using UnityEngine.UI;
+using System.Collections;
+using System;
+using System.Collections.Generic;
+
+namespace EnhancedUI.EnhancedScroller
+{
+ /// <summary>
+ /// This delegate handles the visibility changes of cell views
+ /// </summary>
+ /// <param name="cellView">The cell view that changed visibility</param>
+ public delegate void CellViewVisibilityChangedDelegate(EnhancedScrollerCellView cellView);
+ //濮旀墭 褰撳彲瑙佹�ф敼鍙樻椂锛屼紶鍏ョ殑鏄綋鍓嶆敼鍙樼殑CellView瀵硅薄锛堝璞$户鎵胯嚜EnhancedScrollerCellView) 浜嬩欢鍦� AddCellView鍜宊RecycleCell涓Е鍙�
+
+ /// <summary>
+ /// This delegate handles the scrolling callback of the ScrollRect.
+ /// </summary>
+ /// <param name="scroller">The scroller that called the delegate</param>
+ /// <param name="val">The scroll value of the scroll rect</param>
+ /// <param name="scrollPosition">The scroll position in pixels from the start of the scroller</param>
+ public delegate void ScrollerScrolledDelegate(EnhancedScroller scroller, Vector2 val, float scrollPosition);
+ //濮旀墭 褰搒croll valuechange 鏃讹紝鍦╫nvaluechange浜嬩欢涓Е鍙�
+
+ /// <summary>
+ /// This delegate handles the snapping of the scroller.
+ /// </summary>
+ /// <param name="scroller">The scroller that called the delegate</param>
+ /// <param name="cellIndex">The index of the cell view snapped on (this may be different than the data index in case of looping)</param>
+ /// <param name="dataIndex">The index of the data the view snapped on</param>
+ public delegate void ScrollerSnappedDelegate(EnhancedScroller scroller, int cellIndex, int dataIndex);
+ //濮旀墭 褰搒nap瀹屾垚鏃讹紝 鍦⊿napJumpComplete鏃惰Е鍙�(褰撳紑鍚痵nap鏃讹紝姣忔婊戝姩鍚庨兘浼氬幓杩涜瀹氫綅锛屽綋瀹氫綅鍚庡氨浼氳皟鐢⊿napJumpComplete锛�
+
+ /// <summary>
+ /// This delegate handles the change in state of the scroller (scrolling or not scrolling)
+ /// </summary>
+ /// <param name="scroller">The scroller that changed state</param>
+ /// <param name="scrolling">Whether or not the scroller is scrolling</param>
+ public delegate void ScrollerScrollingChangedDelegate(EnhancedScroller scroller, bool scrolling);
+ //濮旀墭 褰搒croll.velocity寮�濮嬩笉涓�0 鎴栦负0 鏃� 锛屽湪Update涓Е鍙戯紙鍗冲綋寮�濮嬫粦鍔ㄦ椂鎴栧綋鍋滄婊戝姩鏃惰Е鍙戯紝浠elocity涓哄熀鍑嗭紝涓�0鍜屼笉涓�0鏃跺垎鍒Е鍙戜竴娆★級
+
+ /// <summary>
+ /// This delegate handles the change in state of the scroller (jumping or not jumping)
+ /// </summary>
+ /// <param name="scroller">The scroller that changed state</param>
+ /// <param name="tweening">Whether or not the scroller is tweening</param>
+ public delegate void ScrollerTweeningChangedDelegate(EnhancedScroller scroller, bool tweening);
+ //濮旀墭 褰撳紑濮嬫挱鏀綯ween鍜屽仠姝ween鏃惰皟鐢� 锛屽湪JumpToDataIndex涓鏋滀娇鐢═ween杩涜杩囨浮瀹氫綅鏃讹紝浼氬湪寮�濮嬫挱鏀炬椂鍜岀粨鏉熸椂鍚勮Е鍙戜竴娆�
+
+ /// <summary>
+ /// The EnhancedScroller allows you to easily set up a dynamic scroller that will recycle views for you. This means
+ /// that using only a handful of views, you can display thousands of rows. This will save memory and processing
+ /// power in your application.
+ /// </summary>
+ [RequireComponent(typeof(ScrollRect))]
+ public class EnhancedScroller : MonoBehaviour
+ {
+ #region Public
+
+ /// <summary>
+ /// The direction this scroller is handling
+ /// </summary>
+ public enum ScrollDirectionEnum//婊戝姩鏂瑰紡
+ {
+ Vertical,
+ Horizontal
+ }
+
+ /// <summary>
+ /// Which side of a cell to reference.
+ /// For vertical scrollers, before means above, after means below.
+ /// For horizontal scrollers, before means to left of, after means to the right of.
+ /// </summary>
+ public enum CellViewPositionEnum//褰撳墠CellViewPrefab鐨勪笂鏂硅繕鏄笅鏂�
+ {
+ Before,
+ After
+ }
+
+ /// <summary>
+ /// This will set how the scroll bar should be shown based on the data. If no scrollbar
+ /// is attached, then this is ignored. OnlyIfNeeded will hide the scrollbar based on whether
+ /// the scroller is looping or there aren't enough items to scroll.
+ /// </summary>
+ public enum ScrollbarVisibilityEnum//鏄惁鏈夋粦鍔ㄦ潯锛屽湪looping妯″紡涓嬫槸涓嶄細鏄剧ず鐨�
+ {
+ OnlyIfNeeded,
+ Always,
+ Never
+ }
+
+ /// <summary>
+ /// The direction the scroller is handling
+ /// </summary>
+ public ScrollDirectionEnum scrollDirection;
+
+ /// <summary>
+ /// The number of pixels between cell views, starting after the first cell view
+ /// </summary>
+ public float spacing;
+
+ /// <summary>
+ /// The padding inside of the scroller: top, bottom, left, right.
+ /// </summary>
+ public RectOffset padding;
+
+ /// <summary>
+ /// Whether the scroller should loop the cell views
+ /// </summary>
+ [SerializeField]
+ private bool loop;
+
+ /// <summary>
+ /// Whether the scollbar should be shown
+ /// </summary>
+ [SerializeField]
+ private ScrollbarVisibilityEnum scrollbarVisibility;
+
+ /// <summary>
+ /// Whether snapping is turned on
+ /// </summary>
+ public bool snapping;//鏄惁寮�鍚畾浣�
+
+ /// <summary>
+ /// This is the speed that will initiate the snap. When the
+ /// scroller slows down to this speed it will snap to the location
+ /// specified.
+ /// </summary>
+ public float snapVelocityThreshold;//妫�娴嬪畾浣嶇殑闃�鍊硷紝褰撲綆浜庤繖涓�肩殑鏃跺�欏氨浼氳Е鍙戝畾浣�
+
+ /// <summary>
+ /// The snap offset to watch for. When the snap occurs, this
+ /// location in the scroller will be how which cell to snap to
+ /// is determined.
+ /// Typically, the offset is in the range 0..1, with 0 being
+ /// the top / left of the scroller and 1 being the bottom / right.
+ /// In most situations the watch offset and the jump offset
+ /// will be the same, they are just separated in case you need
+ /// that added functionality.
+ /// </summary>
+ public float snapWatchOffset;//瀹氫綅鍚庡綋鍓岰ellVeiw鍦ㄥ彲瑙嗗尯鍩熷唴鍋忕Щ锛屽綋涓�0鏃跺畾浣嶅湪鏈�涓婃柟锛屼负1鏃跺畾浣嶅湪鏈�涓嬫柟
+
+ /// <summary>
+ /// The snap location to move the cell to. When the snap occurs,
+ /// this location in the scroller will be where the snapped cell
+ /// is moved to.
+ /// Typically, the offset is in the range 0..1, with 0 being
+ /// the top / left of the scroller and 1 being the bottom / right.
+ /// In most situations the watch offset and the jump offset
+ /// will be the same, they are just separated in case you need
+ /// that added functionality.
+ /// </summary>
+ public float snapJumpToOffset;//璁剧疆瀹氫綅鐨勫亸绉伙紝瀹炶川涓婄粨鏋滃拰snapWatchOffset涓�鏍凤紝涔熸槸鍦�0~1涔嬮棿锛屽鍔犺繖涓睘鎬т富瑕佹槸鑰冭檻鍒板彲鑳戒細鍑虹幇涓�浜涚壒娈婃儏鍐佃浣跨敤鍒板畠
+
+ /// <summary>
+ /// Once the cell has been snapped to the scroller location, this
+ /// value will determine how the cell is centered on that scroller
+ /// location.
+ /// Typically, the offset is in the range 0..1, with 0 being
+ /// the top / left of the cell and 1 being the bottom / right.
+ /// </summary>
+ public float snapCellCenterOffset;//璁剧疆琚畾浣嶇殑CellVeiw瀹氫綅鍚庣殑涓績鍋忕Щ锛�0~1涔嬮棿鍙栧�硷紝濡傛灉榛樿鐨勮瘽浼氫互瀹冪殑涓婇儴涓哄熀鍑嗭紝涓嶈埇鏉ヨ搴旇璁剧疆涓�0.5锛屽畾浣嶅埌姝d腑蹇�
+
+ /// <summary>
+ /// Whether to include the spacing between cells when determining the
+ /// cell offset centering.
+ /// </summary>
+ public bool snapUseCellSpacing;//寮�鍚繖涓睘鎬х殑鏃跺�欙紝璁$畻瀹氫綅鍚庣殑鍋忕Щ灏嗗寘鎷畠鐨勪笂涓嬩袱涓棿璺濓紝鍚﹀垯鍗充娇鏈夐棿璺濅篃涓嶄細绾冲叆璁$畻鑼冨洿鍐�
+
+ /// <summary>
+ /// What function to use when interpolating between the current
+ /// scroll position and the snap location. This is also known as easing.
+ /// If you want to go immediately to the snap location you can either
+ /// set the snapTweenType to immediate or set the snapTweenTime to zero.
+ /// </summary>
+ public TweenType snapTweenType;//瀹氫綅鏃舵挱鏀惧姩鐢荤殑绫诲瀷
+
+ /// <summary>
+ /// The time it takes to interpolate between the current scroll
+ /// position and the snap location.
+ /// If you want to go immediately to the snap location you can either
+ /// set the snapTweenType to immediate or set the snapTweenTime to zero.
+ /// </summary>
+ public float snapTweenTime;//鎾斁鍔ㄧ敾鐨勬�绘椂闀�
+
+ public Action OnCompLoad;
+
+ /// <summary>
+ /// This delegate is called when a cell view is hidden or shown
+ /// </summary>
+ public CellViewVisibilityChangedDelegate cellViewVisibilityChanged;
+
+ /// <summary>
+ /// This delegate is called when the scroll rect scrolls
+ /// </summary>
+ public ScrollerScrolledDelegate scrollerScrolled;
+
+ /// <summary>
+ /// This delegate is called when the scroller has snapped to a position
+ /// </summary>
+ public ScrollerSnappedDelegate scrollerSnapped;
+
+ /// <summary>
+ /// This delegate is called when the scroller has started or stopped scrolling
+ /// </summary>
+ public ScrollerScrollingChangedDelegate scrollerScrollingChanged;
+
+ /// <summary>
+ /// This delegate is called when the scroller has started or stopped tweening
+ /// </summary>
+ public ScrollerTweeningChangedDelegate scrollerTweeningChanged;
+
+ /// <summary>
+ /// The Delegate is what the scroller will call when it needs to know information about
+ /// the underlying data or views. This allows a true MVC process.
+ /// </summary>
+ public IEnhancedScrollerDelegate Delegate { get { return _delegate; } set { _delegate = value; _reloadData = true; } }
+ /*杩欓噷瑕佸皢涓�涓疄鐜颁簡IEnhancedScrollerDelegate鎺ュ彛鐨勭被鐨勫璞¤祴鍊艰繃鏉ワ紝杩欎釜瀵硅薄鐢ㄤ簬鎺у埗鏁翠釜Scroll,閫氳繃瀹炵幇杩欎釜鎺ュ彛鐨勫嚑涓柟娉�
+ * 鍙互瀹氫箟锛� 1. 褰撳墠CellVeiw鐨勬�绘暟鐩�
+ *
+ * 2. 鏌恉ataIndex瀵瑰簲鐨凜ellView鍏冪礌鐨剆ize
+ *
+ * 3.濡備綍鑾峰彇锛堜粠寰幆姹犻噷鍙栵紝鎴栧疄渚嬪寲锛変竴涓狢ellView
+ * 骞跺緱鍒板叾CellView瀵硅薄锛岃�岃繖涓璞″張缁ф壙鑷狤nhancedScrollerCellView锛�
+ * 鎵�浠ュ疄闄呬笂鑾峰彇浜嗚繖涓狢ellView鐨� 锛�
+ * 1.cellIdentifier锛坰croll瀛樺湪涓嶅悓Prefab鏃剁敤浜庡尯鍒嗙殑瀛楃涓诧級
+ * 2.cellIndex dataIndex 锛坉ataIndex浠h〃鐨勬槸瑕佸惊鐜殑cellview鍏冪礌绱㈠紩锛岃�宑ellIndex浠h〃鐨勬槸闆嗗悎鍐呭厓绱犵殑绱㈠紩
+ * 褰撴病鏈夊紑鍚惊鐜ā寮忕殑鏃跺�欙紝闆嗗悎鍜屽厓绱犳槸涓�鑷寸殑锛屽畠浠苟娌℃湁浠�涔堜笉鍚岋紝閮借兘瀵瑰簲涓婄浉搴旂殑cellview鍏冪礌
+ * 锛屼絾褰撳紑鍚惊鐜悗锛岄泦鍚堜細琚墿鍏咃紙姣斿鎵╁厖3鍊嶏級锛屾鏃禿ataIndex鐨勬暣涓懆鏈熸墠鏄湡姝e搴攃ellview鍏冪礌鐨勬暣涓懆鏈燂級
+ * 3. active 鏄惁鏄縺娲荤姸鎬�
+ * 4.鎻愪緵涓�涓櫄鏂规硶渚涘瓙绫婚噸鍐欑敤鏉ュ疄鐜颁竴浜涘叿浣撶殑鍔熻兘
+ * 5.閫氬父杩欎釜瀵硅薄鏈韩涔熶細鎻愪緵涓�涓柟娉曠敤浜庡鍏惰繘琛屽垵濮嬪寲(姣斿Start()鎴栬�呯洿鎺ユ彁渚涗竴涓叕鏈夋柟娉曚緵澶栭儴涓诲姩璋冪敤锛�
+ *
+ *杩欎釜瀵硅薄鏄暣涓猻croll鐨勬牳蹇冿紝閫氳繃瀹炵幇瀹冪户鎵跨殑鎺ュ彛锛屽畾涔変簡scroll涓婥ellView鐨勬�绘暟鐩紝姣忎釜CellView鐨剆ize锛�
+ * 閫氳繃璋冪敤 EnhancedScroller 涓殑 ReloadData()鏂规硶鏉ュ垵濮嬪寲鏁翠釜Scroll
+ * 閫氳繃瀹炵幇GetCellView鏂规硶锛屽彲浠ヨ皟鐢‥nhancedScrolelr绫讳笅鐨凣etCellView锛堬級鏂规硶锛屼紶鍏ョ浉搴旂殑CellView Prefab锛岄�氳繃瀹氫箟鐨刢ellIdentifier
+ * 鏉ヤ粠寰幆姹犻噷鍙栧搴旂殑CellVeiw锛屽鏋滄病鎵惧埌鍒欏疄渚嬪寲涓�涓紝鑰屽緱鍒扮殑杩欎釜瀵硅薄鍙堝寘鍚叾鐩稿叧鐨勫睘鎬э紝绱㈠紩鍜屽垵濮嬪寲鐨勬柟娉�
+ * 閫氳繃澹版槑涓�绯诲垪鐨勪簨浠跺彲浠ョ粦瀹欵nhancedScroller涓殑濮旀墭鐢ㄤ簬鍚勭被浜嬩欢鐨勮Е鍙�
+ * */
+
+
+ /// <summary>
+ /// The absolute position in pixels from the start of the scroller
+ /// </summary>
+ public float ScrollPosition
+ {
+ get
+ {
+ return _scrollPosition;
+ }
+ set
+ {
+ // make sure the position is in the bounds of the current set of views
+ value = Mathf.Clamp(value, 0, GetScrollPositionForCellViewIndex(_cellViewSizeArray.Count - 1, CellViewPositionEnum.Before));
+ //灏嗕紶鍏ョ殑Value鐨勫ぇ灏忛檺鍒跺湪鏁翠釜_cellViewSizeArray闆嗗悎鍐咃紙娉ㄦ剰鏄渶鍚庝竴涓厓绱犵殑涓婃柟锛屼絾鏄繖涓泦鍚堢殑闀垮害涔熷彲鑳芥槸澶嶅埗杩囧悗鐨勶級
+ // only if the value has changed
+ if (_scrollPosition != value)
+ {
+ _scrollPosition = value;
+ if (scrollDirection == ScrollDirectionEnum.Vertical)
+ {
+ // set the vertical position
+ scrollRect.verticalNormalizedPosition = 1f - (_scrollPosition / _ScrollSize);
+ //杩欓噷瑕佹敞鎰忥紝濡傛灉闆嗗悎杩涜杩囧鍒讹紝閭d箞杩欓噷鐨刜scrollSize涔熶竴鏍蜂細姣斿師鏉ョ殑澧炲姞锛屽洜涓篲ScrollSize姘歌繙姣攃ontent鐨勬�诲ぇ灏忓皬涓�涓彲瑙嗗尯澶у皬
+
+ }
+ else
+ {
+ // set the horizontal position
+ scrollRect.horizontalNormalizedPosition = (_scrollPosition / _ScrollSize);
+ }
+
+ // flag that we need to refresh
+ _refreshActive = true;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Whether the scroller should loop the resulting cell views.
+ /// Looping creates three sets of internal size data, attempting
+ /// to keep the scroller in the middle set. If the scroller goes
+ /// outside of this set, it will jump back into the middle set,
+ /// giving the illusion of an infinite set of data.
+ /// </summary>
+ public bool Loop
+ {
+ get
+ {
+ return loop;
+ }
+ set
+ {
+ // only if the value has changed
+ if (loop != value)//濡傛灉鐩稿叧灞炴�у彂鐢熶簡鍙樺寲
+ {
+ // get the original position so that when we turn looping on
+ // we can jump back to this position
+ var originalScrollPosition = _scrollPosition;
+
+ loop = value;
+
+ // call resize to generate more internal elements if loop is on,
+ // remove the elements if loop is off
+ _Resize(false);
+
+ if (loop)
+ {
+ // set the new scroll position based on the middle set of data + the original position
+ ScrollPosition = _loopFirstScrollPosition + originalScrollPosition;
+ }
+ else
+ {
+ // set the new scroll position based on the original position and the first loop position
+ ScrollPosition = originalScrollPosition - _loopFirstScrollPosition;
+ }
+
+ // update the scrollbars
+ ScrollbarVisibility = scrollbarVisibility;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Sets how the visibility of the scrollbars should be handled
+ /// </summary>
+ public ScrollbarVisibilityEnum ScrollbarVisibility
+ {
+ get
+ {
+ return scrollbarVisibility;
+ }
+ set
+ {
+ scrollbarVisibility = value;
+
+ // only if the scrollbar exists
+ if (_scrollbar != null)
+ {
+ // make sure we actually have some cell views
+ if (_cellViewOffsetArray != null && _cellViewOffsetArray.Count > 0)
+ {
+ if (_cellViewOffsetArray.Last() < ScrollRectSize || loop)
+ {
+ // if the size of the scrollable area is smaller than the scroller
+ // or if we have looping on, hide the scrollbar unless the visibility
+ // is set to Always.
+ _scrollbar.SetActive(scrollbarVisibility == ScrollbarVisibilityEnum.Always);
+ }
+ else
+ {
+ // if the size of the scrollable areas is larger than the scroller
+ // or looping is off, then show the scrollbars unless visibility
+ // is set to Never.
+ _scrollbar.SetActive(scrollbarVisibility != ScrollbarVisibilityEnum.Never);
+ }
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// This is the velocity of the scroller.
+ /// </summary>
+ public Vector2 Velocity
+ {
+ get
+ {
+ return scrollRect.velocity;
+ }
+ set
+ {
+ scrollRect.velocity = value;
+ }
+ }
+
+ /// <summary>
+ /// The linear velocity is the velocity on one axis.
+ /// The scroller should only be moving one one axix.
+ /// </summary>
+ public float LinearVelocity //瀹炶川涓婃槸鎿嶄綔ScrollRect.velocity
+ //Get : 灏嗗悜閲忚浆涓篺loat绫诲瀷
+ //Set锛氱敤涓�涓猣loat绫诲瀷鏋勯�犱竴涓浉搴旂殑鍚戦噺
+ //澶栭儴鏂规硶鍙互閫氳繃璁块棶杩欎釜灞炴�ф潵浣縮croll杩愬姩璧锋潵
+ {
+ get
+ {
+ // return the velocity component depending on which direction this is scrolling
+ return (scrollDirection == ScrollDirectionEnum.Vertical ? scrollRect.velocity.y : scrollRect.velocity.x);
+ }
+ set
+ {
+ // set the appropriate component of the velocity
+ if (scrollDirection == ScrollDirectionEnum.Vertical)
+ {
+ scrollRect.velocity = new Vector2(0, value);
+ }
+ else
+ {
+ scrollRect.velocity = new Vector2(value, 0);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Whether the scroller is scrolling or not
+ /// </summary>
+ public bool IsScrolling
+ {
+ get; private set;
+ }
+
+ /// <summary>
+ /// Whether the scroller is tweening or not
+ /// </summary>
+ public bool IsTweening
+ {
+ get; private set;
+ }
+
+ /// <summary>
+ /// This is the first cell view index showing in the scroller's visible area
+ /// </summary>
+ public int StartCellViewIndex//鍙鍖哄唴绗竴涓兘鐪嬪埌鐨勫厓绱犵储寮曪紙鍙鑳界湅鍒板氨琛岋紝涓嶄竴瀹氳瀹屽叏鑳界湅鍒帮級
+ {
+ get
+ {
+ return _activeCellViewsStartIndex;
+ }
+ }
+
+ /// <summary>
+ /// This is the last cell view index showing in the scroller's visible area
+ /// </summary>
+ public int EndCellViewIndex
+ {
+ get
+ {
+ return _activeCellViewsEndIndex;
+ }
+ }
+
+ /// <summary>
+ /// This is the first data index showing in the scroller's visible area
+ /// </summary>
+ public int StartDataIndex//褰撳惊鐜紑鍚椂dataIndex浠h〃寰幆鍐呯殑绱㈠紩锛屽綋寮�鍚柊涓�杞惊鐜椂锛宒ataIndex涔熶細閲嶆柊璁℃暟
+ {
+ get
+ {
+ return _activeCellViewsStartIndex % NumberOfCells;
+ }
+ }
+
+ /// <summary>
+ /// This is the last data index showing in the scroller's visible area
+ /// </summary>
+ public int EndDataIndex
+ {
+ get
+ {
+ return _activeCellViewsEndIndex % NumberOfCells;
+ }
+ }
+
+ public int ActiveCellCnt {
+ get {
+ return _activeCellViews.Count;
+ }
+ }
+
+ /// <summary>
+ /// This is the number of cells in the scroller
+ /// </summary>
+ public int NumberOfCells//CellView鐨勬�讳釜鏁帮紝浠庢渶涓婃柟婊戝姩鍒版渶涓嬫柟鎬诲叡鏄剧ず鐨勬暟鐩�
+ {
+ get
+ {
+ return (_delegate != null ? _delegate.GetNumberOfCells(this) : 0);
+ }
+ }
+
+ /// <summary>
+ /// The size of the visible portion of the scroller
+ /// </summary>
+ public float ScrollRectSize//寰楀埌Scroll鐨勯珮鎴栧
+ {
+ get
+ {
+ if (scrollDirection == ScrollDirectionEnum.Vertical)
+ return _scrollRectTransform.rect.height;
+ else
+ return _scrollRectTransform.rect.width;
+ }
+ }
+
+ public event Action OnFirstLoadAllEvent;
+ private bool m_IsLoadAll = false;
+
+ /// <summary>
+ /// Create a cell view, or recycle one if it already exists
+ /// </summary>
+ /// <param name="cellPrefab">The prefab to use to create the cell view</param>
+ /// <returns></returns>
+ public EnhancedScrollerCellView GetCellView(EnhancedScrollerCellView cellPrefab)
+ {
+ // see if there is a view to recycle
+ var cellView = _GetRecycledCellView(cellPrefab);
+ if (cellView == null)
+ {
+ // no recyleable cell found, so we create a new view
+ // and attach it to our container
+ var go = Instantiate(cellPrefab.gameObject);
+ cellView = go.GetComponent<EnhancedScrollerCellView>();
+ cellView.transform.SetParent(_container);
+
+ }
+ Vector3 pos = cellView.transform.localPosition;
+ if (pos.x == float.NaN || pos.y == float.NaN)
+ {
+ pos = Vector3.zero;
+ }
+ pos.z = 0;
+ cellView.transform.localPosition = pos;
+ return cellView;
+ /*杩欎釜鏂规硶浼氶�氳繃涓�涓猚ellPrefab鏉ュ彇鍑轰竴涓猚ellView瀵硅薄锛岄鍏堜細鍏堜粠缂撳啿姹犻噷鍙栵紝濡傛灉鏈夌浉鍚宑ellIdentifier灞炴�х殑鐗╀綋
+ * 灏辨妸杩欎釜瀵硅薄浠庣紦鍐叉睜鍙栧嚭鏉ワ紝濡傛灉娌℃湁鐨勮瘽灏卞疄渚嬪寲涓�涓�
+ */
+ }
+
+ /// <summary>
+ /// This resets the internal size list and refreshes the cell views
+ /// </summary>
+ public void ReloadData()
+ {
+ _reloadData = false;
+
+ _scrollPosition = 0;
+
+ // recycle all the active cells so
+ // that we are sure to get fresh views
+ _RecycleAllCells();
+
+ // if we have a delegate handling our data, then
+ // call the resize
+ if (_delegate != null)
+ _Resize(false);
+ //杩欎釜鏂规硶鐢ㄤ簬鍒濆鍖栬繖涓粍浠舵垨閲嶆柊鍔犺浇杩欎釜缁勪欢
+ /*1.灏哶reloadData缃负false锛岀敤浜庢爣璁版缁勪欢宸茬粡鍒濆鍖栵紝Update()鏂规硶涓嶇敤鍐嶉噸鏂版墽琛�
+ *2.灏哶scrollPosition 璧嬪�间负 0锛屽綋瀹冧负0鏃讹紝鍚庣画鐨勫彲瑙嗗尯鍩熶細浠ュ畠涓哄熀鍑嗭紝婊戝姩鏉″皢绉诲姩鍒版渶涓婅竟鎴栨渶宸﹁竟
+ *3.濡傛灉鏈夊彲瑙佺殑鍏冪礌锛屽叏閮ㄧЩ鍔ㄥ埌缂撳啿姹�
+ *4.鎵цResize
+ * 1锛夊惊鐜ā寮忎笅锛屾墿鍏呭惊鐜泦鍚堝埌3鍊嶇殑澶у皬锛堝疄闄呬笂鍦ㄥ惊鐜ā寮忎笅锛屼笉绠℃�庝箞婊戝姩閮藉彧浼氬湪涓棿閭d釜寰幆鍐咃級
+ * 2锛夊鏋滀紶鍏alse鍒欏畾浣嶅埌璧峰鐐癸紝濡傛灉浼犲叆true鍒欏畾浣嶅埌褰撳墠_position锛堝惊鐜ā寮忎笅瀹氫綅鍒颁腑闂撮偅涓惊鐜殑瀵瑰簲鐐癸級
+ */
+ }
+
+ /// <summary>
+ /// This calls the RefreshCellView method on each active cell.
+ /// If you override the RefreshCellView method in your cells
+ /// then you can update the UI without having to reload the data.
+ /// Note: this will not change the cell sizes, you will need
+ /// to call ReloadData for that to work.
+ /// </summary>
+ public void RefreshActiveCellViews() //杩欐槸鎻愪緵缁欏鐣岀殑涓�涓柟娉曪紝鐢ㄤ簬鍘讳富鍔ㄦ搷浣滃綋鍓峉croll鍙鍖哄唴鎵�鏈夌殑鍙鍏冪礌
+ {
+ for (var i = 0; i < _activeCellViews.Count; i++)
+ {
+ _activeCellViews[i].RefreshCellView();//姣忎竴涓彲瑙佸厓绱犻兘鍙互閲嶅啓杩欎釜鏂规硶鏉ュ叿浣撴墽琛屾煇娈甸�昏緫
+ }
+ if (this.Delegate != null)
+ {
+ this.Delegate.OnRebuildComplete();
+ }
+ }
+
+ public EnhancedScrollerCellView GetActiveCellView(int _index)
+ {
+ for (int i = 0; i < _activeCellViews.Count; i++)
+ {
+ if (_activeCellViews[i].index == _index)
+ {
+ return _activeCellViews[i];
+ }
+ }
+ return null;
+ }
+
+ public SmallList<EnhancedScrollerCellView> GetActiveCellViews()
+ {
+ return _activeCellViews;
+ }
+
+ internal float GetCellSize(int _dataIndex)
+ {
+ if (_dataIndex >= 0 && _dataIndex < _cellViewSizeArray.Count)
+ {
+ return _cellViewSizeArray[_dataIndex];
+ }
+ return 0;
+ }
+
+ /// <summary>
+ /// Removes all the recycled cell views. This should only be used after you
+ /// load in a completely different set of cell views that will not use the
+ /// recycled views. This will call garbage collection.
+ /// </summary>
+ public void ClearRecycled()//涓诲姩璋冪敤杩欎釜鏂规硶浼氱珛鍗虫竻绌虹紦瀛樻睜骞堕噴鏀炬帀瀹冨崰鐢ㄧ殑鍐呭瓨锛屽彲浠ラ厤鍚堜笂闈㈢殑鏂规硶鍔ㄦ�佹洿鏂皊croll
+ {
+ for (var i = 0; i < _recycledCellViews.Count; i++)
+ {
+ DestroyImmediate(_recycledCellViews[i].gameObject);
+ }
+ _recycledCellViews.Clear();
+ }
+
+ /// <summary>
+ /// Turn looping on or off. This is just a helper function so
+ /// you don't have to keep track of the state of the looping
+ /// in your own scripts.
+ /// </summary>
+ public void ToggleLoop()//涓诲姩璋冪敤浼氬垏鎹㈠綋鍓嶇殑寰幆妯″紡
+ {
+ Loop = !loop;
+ }
+
+ /// <summary>
+ /// Jump to a position in the scroller based on a dataIndex. This overload allows you
+ /// to specify a specific offset within a cell as well.
+ /// </summary>
+ /// <param name="dataIndex">he data index to jump to</param>
+ /// <param name="scrollerOffset">The offset from the start (top / left) of the scroller in the range 0..1.
+ /// Outside this range will jump to the location before or after the scroller's viewable area</param>
+ /// <param name="cellOffset">The offset from the start (top / left) of the cell in the range 0..1</param>
+ /// <param name="useSpacing">Whether to calculate in the spacing of the scroller in the jump</param>
+ /// <param name="tweenType">What easing to use for the jump</param>
+ /// <param name="tweenTime">How long to interpolate to the jump point</param>
+ /// <param name="jumpComplete">This delegate is fired when the jump completes</param>
+ /// 璺宠浆鍒癲ataIndex瀵瑰簲鐨刢ellview鍏冪礌锛屽彲浠ラ�夋嫨鐩稿簲鐨則ween鍔ㄧ敾
+ public void JumpToDataIndex(int dataIndex,
+ float scrollerOffset = 0,
+ float cellOffset = 0,
+ bool useSpacing = true,
+ TweenType tweenType = TweenType.immediate,
+ float tweenTime = 0f,
+ Action jumpComplete = null
+ )
+ {
+ var cellOffsetPosition = 0f;
+
+ if (cellOffset != 0)
+ {
+ // calculate the cell offset position
+
+ // get the cell's size
+ var cellSize = (_delegate != null ? _delegate.GetCellViewSize(this, dataIndex) : 0);
+
+ if (useSpacing)
+ {
+ // if using spacing add spacing from one side
+ cellSize += spacing;
+
+ // if this is not a bounday cell, then add spacing from the other side
+ if (dataIndex > 0 && dataIndex < (NumberOfCells - 1)) cellSize += spacing;
+ }
+
+ // calculate the position based on the size of the cell and the offset within that cell
+ cellOffsetPosition = cellSize * cellOffset;
+ }
+
+ var newScrollPosition = 0f;
+
+ // cache the offset for quicker calculation
+ var offset = -(scrollerOffset * ScrollRectSize) + cellOffsetPosition;
+
+ if (loop)
+ {
+ // if looping, then we need to determine the closest jump position.
+ // we do that by checking all three sets of data locations, and returning the closest one
+
+ // get the scroll positions for each data set.
+ // Note: we are calculating the position based on the cell view index, not the data index here
+ var set1Position = GetScrollPositionForCellViewIndex(dataIndex, CellViewPositionEnum.Before) + offset;
+ var set2Position = GetScrollPositionForCellViewIndex(dataIndex + NumberOfCells, CellViewPositionEnum.Before) + offset;
+ var set3Position = GetScrollPositionForCellViewIndex(dataIndex + (NumberOfCells * 2), CellViewPositionEnum.Before) + offset;
+
+ // get the offsets of each scroll position from the current scroll position
+ var set1Diff = (Mathf.Abs(_scrollPosition - set1Position));
+ var set2Diff = (Mathf.Abs(_scrollPosition - set2Position));
+ var set3Diff = (Mathf.Abs(_scrollPosition - set3Position));
+
+ // choose the smallest offset from the current position (the closest position)
+ if (set1Diff < set2Diff)
+ {
+ if (set1Diff < set3Diff)
+ {
+ newScrollPosition = set1Position;
+ }
+ else
+ {
+ newScrollPosition = set3Position;
+ }
+ }
+ else
+ {
+ if (set2Diff < set3Diff)
+ {
+ newScrollPosition = set2Position;
+ }
+ else
+ {
+ newScrollPosition = set3Position;
+ }
+ }
+ }
+ else
+ {
+ // not looping, so just get the scroll position from the dataIndex
+ newScrollPosition = GetScrollPositionForDataIndex(dataIndex, CellViewPositionEnum.Before) + offset;
+ }
+
+ // clamp the scroll position to a valid location
+ newScrollPosition = Mathf.Clamp(newScrollPosition, 0, GetScrollPositionForCellViewIndex(_cellViewSizeArray.Count - 1, CellViewPositionEnum.Before));
+
+ // if spacing is used, adjust the final position
+ if (useSpacing)
+ {
+ // move back by the spacing if necessary
+ newScrollPosition = Mathf.Clamp(newScrollPosition - spacing, 0, GetScrollPositionForCellViewIndex(_cellViewSizeArray.Count - 1, CellViewPositionEnum.Before));
+ }
+
+ // start tweening
+ if (tweenType == TweenType.immediate || tweenTime == 0)
+ {
+ // if the easing is immediate or the time is zero, just jump to the end position
+ ScrollPosition = newScrollPosition;
+ return;
+ }
+ StartCoroutine(TweenPosition(tweenType, tweenTime, ScrollPosition, newScrollPosition, jumpComplete));
+ }
+
+ public void Tween(TweenType tweenType, float tweenTime, float newPosition, Action jumpComplete = null)
+ {
+ StartCoroutine(TweenPosition(tweenType, tweenTime, ScrollPosition, newPosition, jumpComplete));
+ }
+
+ /// <summary>
+ /// Jump to a position in the scroller based on a dataIndex.
+ /// </summary>
+ /// <param name="dataIndex">The data index to jump to</param>
+ /// <param name="position">Whether you should jump before or after the cell view</param>
+ [System.Obsolete("This is an obsolete method, please use the version of this function with a cell offset.")]
+ //杩囨椂鐨勬柟娉曪紝鍙互閫夋嫨瀹氫綅鍒板厓绱犱笂鏂规垨涓嬫柟锛堝乏鍙冲悓鐞�)锛屽彲浠ラ�氳繃涓婇潰鐨勬柟娉曡皟鏁村亸绉昏揪鍒板悓鏍风殑鏁堟灉
+ public void JumpToDataIndex(int dataIndex,
+ CellViewPositionEnum position = CellViewPositionEnum.Before,
+ bool useSpacing = true)
+ {
+ // if looping is on, we need to jump to the middle set of data, otherwise just use the dataIndex for the cellIndex
+ ScrollPosition = GetScrollPositionForDataIndex(dataIndex, position);
+
+ // if spacing is used, adjust the final position
+ if (useSpacing)
+ {
+ if (position == CellViewPositionEnum.Before)
+ ScrollPosition = _scrollPosition - spacing;
+ else
+ ScrollPosition = _scrollPosition + spacing;
+ }
+ }
+
+ /// <summary>
+ /// Snaps the scroller on command. This is called internally when snapping is set to true and the velocity
+ /// has dropped below the threshold. You can use this to manually snap whenever you like.
+ /// </summary>
+ /// 褰撳紑鍚攣瀹氫綅缃姛鑳芥椂锛屽湪婊戝姩鏉℃粦鍔ㄥ悗鍏冪礌浼氳繘琛岀浉搴旂殑瀹氫綅锛堝畾浣嶇殑绾︽潫鍦ㄩ潰鏉夸腑鍙互杩涜璁剧疆锛�
+ public void Snap()
+ {
+ if (NumberOfCells == 0) return;
+
+ // set snap jumping to true so other events won't process while tweening
+ _snapJumping = true;
+
+ // stop the scroller
+ LinearVelocity = 0;
+
+ // cache the current inertia state and turn off inertia
+ _snapInertia = scrollRect.inertia;
+ scrollRect.inertia = false;
+
+ // calculate the snap position
+ var snapPosition = ScrollPosition + (ScrollRectSize * Mathf.Clamp01(snapWatchOffset));
+
+ // get the cell view index of cell at the watch location
+ _snapCellViewIndex = GetCellViewIndexAtPosition(snapPosition);
+
+ // get the data index of the cell at the watch location
+ _snapDataIndex = _snapCellViewIndex % NumberOfCells;
+
+ // jump the snapped cell to the jump offset location and center it on the cell offset
+ JumpToDataIndex(_snapDataIndex, snapJumpToOffset, snapCellCenterOffset, snapUseCellSpacing, snapTweenType, snapTweenTime, SnapJumpComplete);
+ }
+
+ /// <summary>
+ /// Gets the scroll position in pixels from the start of the scroller based on the cellViewIndex
+ /// </summary>
+ /// <param name="cellViewIndex">The cell index to look for. This is used instead of dataIndex in case of looping</param>
+ /// <param name="insertPosition">Do we want the start or end of the cell view's position</param>
+ /// <returns></returns>
+ public float GetScrollPositionForCellViewIndex(int cellViewIndex, CellViewPositionEnum insertPosition)//鏍规嵁鐩稿叧鐨勭储寮曚粠_cellViewOffsetArray閲屽彇瀵瑰簲鐨刾osition
+ {
+ /*杩欎釜鏂规硶鐨勪富瑕佷綔鐢ㄦ槸閫氳繃涓�涓储寮曟潵杩斿洖position锛岃�岃繖涓猵osition瀹為檯涓婂彲浠ヨ涓烘槸鍙粦鍔ㄧ殑content鍚戜笂鎴栧悜宸︽粦鍔ㄤ簡澶氬皯
+ * 鍥犱负涔嬪墠閫氳繃_cellViewOffsetArray鏉ュ瓨鍌ㄤ簡姣忎釜cellView涓嬫柟鐩稿浜庡乏涓婄殑鍋忕Щ(TextAnchor.UpperLeft)鎵�浠ラ�氳繃绱㈠紩瀹為檯涓婂氨鑳藉彇鍑鸿繖涓亸绉婚噺
+ * 鍐嶉�氳繃Before(鍙栦笂鎴栧乏) After(鍙栦笅鎴栧彸)鏉ュ垽鏂渶缁坧osition鐨勫��
+ * -----scrollRect鐨凬ormallizedPosition瀹為檯涓婃槸鍙粦鍔ㄥ尯鍩熺殑澶у皬鍚戝彟涓�鏂规粦鍔ㄤ腑鍋忕Щ閲忕殑姣斾緥--------------
+ * 鎵�浠ュ彲浠ラ�氳繃postion鍜屽彲婊戝姩鍖哄煙澶у皬鐨勬瘮鍊兼潵瀹氫箟婊戝姩鏉℃粦鍔ㄥ埌浜嗗摢涓綅缃�
+ */
+
+ if (NumberOfCells == 0 || _cellViewOffsetArray.Count == 0) return 0;//濡傛灉scroll娌℃湁瀛愮墿浣撶洿鎺ヨ繑鍥�
+
+ if (cellViewIndex <= 0 && insertPosition == CellViewPositionEnum.Before)
+ {
+ return 0;//濡傛灉鏄涓�涓瓙鐗╀綋涓旇寰楀埌瀹冪殑涓婃柟浣嶇疆锛岀洿鎺ヨ繑鍥�0
+ }
+ else
+ {
+ if (cellViewIndex < _cellViewOffsetArray.Count)
+ {
+ // the index is in the range of cell view offsets
+
+ if (insertPosition == CellViewPositionEnum.Before)
+ {
+ // return the previous cell view's offset + the spacing between cell views
+ return _cellViewOffsetArray[cellViewIndex - 1] + spacing + (scrollDirection == ScrollDirectionEnum.Vertical ? padding.top : padding.left);
+ //杩斿洖褰撳墠绱㈠紩涓婃柟鐨勫��
+ //杩欓噷瑕佹敞鎰忎竴鐐瑰氨鏄竴鑸潵璇磋皟鐢ㄨ繖涓柟娉曠殑鏃跺�欏氨鏄鍦╨oop妯″紡涔嬩笅锛岃繖閲岀殑_cellViewOffsetArray鏄粡杩囧鍒跺悗鐨勯泦鍚�
+ }
+ else
+ {
+ // return the offset of the cell view (offset is after the cell)
+ return _cellViewOffsetArray[cellViewIndex] + (scrollDirection == ScrollDirectionEnum.Vertical ? padding.top : padding.left);
+ //杩斿洖褰撳墠绱㈠紩涓嬫柟鐨勫��
+ }
+ }
+ else
+ {
+ // get the start position of the last cell (the offset of the second to last cell)
+ return _cellViewOffsetArray[_cellViewOffsetArray.Count - 2];
+ //杩斿洖鏈�鍚庝竴涓储寮曠殑涓婃柟鍊�
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets the scroll position in pixels from the start of the scroller based on the dataIndex
+ /// </summary>
+ /// <param name="dataIndex">The data index to look for</param>
+ /// <param name="insertPosition">Do we want the start or end of the cell view's position</param>
+ /// <returns></returns>
+ public float GetScrollPositionForDataIndex(int dataIndex, CellViewPositionEnum insertPosition)
+ {
+ return GetScrollPositionForCellViewIndex(loop ? _delegate.GetNumberOfCells(this) + dataIndex : dataIndex, insertPosition);
+ //閫氳繃dataIndex鏉ョ‘瀹歋crollPosition锛岃娉ㄦ剰鐨勬槸GetScrollPositionForCellViewIndex闇�瑕佺殑鏄痗ellIndex鑰屼笉鏄痙ataIndex
+ //鎵�浠ュ湪寰幆妯″紡涓嬶紝dataIndex瑕佸姞涓婃墍鏈夊厓绱犵殑鏁伴噺锛堝洜涓哄湪寰幆妯″紡涓嬶紝dataIndex瀵瑰簲鐨勫厓绱犳案杩滈兘鏄湪闆嗗悎涓殑绗簩缁勶級
+ }
+
+ /// <summary>
+ /// Gets the index of a cell view at a given position
+ /// </summary>
+ /// <param name="position">The pixel offset from the start of the scroller</param>
+ /// <returns></returns>
+ public int GetCellViewIndexAtPosition(float position)
+ {
+ // call the overrloaded method on the entire range of the list
+ return _GetCellIndexAtPosition(position, 0, _cellViewOffsetArray.Count - 1);
+ }
+
+ #endregion
+
+ #region Private
+
+ /// <summary>
+ /// Cached reference to the scrollRect
+ /// </summary>
+ private ScrollRect m_ScrollRect;
+ public ScrollRect scrollRect {
+ get {
+ if (m_ScrollRect == null) {
+ m_ScrollRect = this.GetComponent<ScrollRect>();
+ }
+ return m_ScrollRect;
+ }
+ }
+
+ /// <summary>
+ /// Cached reference to the scrollRect's transform
+ /// </summary>
+ private RectTransform _scrollRectTransform;
+
+ /// <summary>
+ /// Cached reference to the scrollbar if it exists
+ /// </summary>
+ private Scrollbar _scrollbar;
+
+ /// <summary>
+ /// Cached reference to the active cell view container
+ /// </summary>
+ private RectTransform _container;
+
+ /// <summary>
+ /// Cached reference to the layout group that handles view positioning
+ /// </summary>
+ private HorizontalOrVerticalLayoutGroup _layoutGroup;
+ public HorizontalOrVerticalLayoutGroup LayoutGroup
+ {
+ get
+ {
+ return _layoutGroup;
+ }
+ }
+ /// <summary>
+ /// Reference to the delegate that will tell this scroller information
+ /// about the underlying data
+ /// </summary>
+ private IEnhancedScrollerDelegate _delegate;
+
+ /// <summary>
+ /// Flag to tell the scroller to reload the data
+ /// </summary>
+ private bool _reloadData;
+
+ /// <summary>
+ /// Flag to tell the scroller to refresh the active list of cell views
+ /// </summary>
+ private bool _refreshActive;
+
+ /// <summary>
+ /// List of views that have been recycled
+ /// </summary>
+ private SmallList<EnhancedScrollerCellView> _recycledCellViews = new SmallList<EnhancedScrollerCellView>();
+
+ /// <summary>
+ /// Cached reference to the element used to offset the first visible cell view
+ /// </summary>
+ private LayoutElement _firstPadder;
+
+ /// <summary>
+ /// Cached reference to the element used to keep the cell views at the correct size
+ /// </summary>
+ private LayoutElement _lastPadder;
+
+ /// <summary>
+ /// Cached reference to the container that holds the recycled cell views
+ /// </summary>
+ private RectTransform _recycledCellViewContainer;
+
+ /// <summary>
+ /// Internal list of cell view sizes. This is created when the data is reloaded
+ /// to speed up processing.
+ /// </summary>
+ private SmallList<float> _cellViewSizeArray = new SmallList<float>();
+
+ /// <summary>
+ /// Internal list of cell view offsets. Each cell view offset is an accumulation
+ /// of the offsets previous to it.
+ /// This is created when the data is reloaded to speed up processing.
+ /// </summary>
+ private SmallList<float> _cellViewOffsetArray = new SmallList<float>();
+
+ /// <summary>
+ /// The scrollers position
+ /// </summary>
+ private float _scrollPosition;
+
+ /// <summary>
+ /// The list of cell views that are currently being displayed
+ /// </summary>
+ private SmallList<EnhancedScrollerCellView> _activeCellViews = new SmallList<EnhancedScrollerCellView>();
+
+ /// <summary>
+ /// The index of the first cell view that is being displayed
+ /// </summary>
+ private int _activeCellViewsStartIndex;
+
+ /// <summary>
+ /// The index of the last cell view that is being displayed
+ /// </summary>
+ private int _activeCellViewsEndIndex;
+
+ /// <summary>
+ /// The index of the first element of the middle section of cell view sizes.
+ /// Used only when looping
+ /// </summary>
+ private int _loopFirstCellIndex;
+
+ /// <summary>
+ /// The index of the last element of the middle seciton of cell view sizes.
+ /// used only when looping
+ /// </summary>
+ private int _loopLastCellIndex;
+
+ /// <summary>
+ /// The scroll position of the first element of the middle seciotn of cell views.
+ /// Used only when looping
+ /// </summary>
+ private float _loopFirstScrollPosition;
+
+ /// <summary>
+ /// The scroll position of the last element of the middle section of cell views.
+ /// Used only when looping
+ /// </summary>
+ private float _loopLastScrollPosition;
+
+ /// <summary>
+ /// The position that triggers the scroller to jump to the end of the middle section
+ /// of cell views. This keeps the scroller in the middle section as much as possible.
+ /// </summary>
+ private float _loopFirstJumpTrigger;
+
+ /// <summary>
+ /// The position that triggers the scroller to jump to the start of the middle section
+ /// of cell views. This keeps the scroller in the middle section as much as possible.
+ /// </summary>
+ private float _loopLastJumpTrigger;
+
+ /// <summary>
+ /// The cached value of the last scroll rect size. This is checked every frame to see
+ /// if the scroll rect has resized. If so, it will refresh.
+ /// </summary>
+ private float _lastScrollRectSize;
+
+ /// <summary>
+ /// The cached value of the last loop setting. This is checked every frame to see
+ /// if looping was toggled. If so, it will refresh.
+ /// </summary>
+ private bool _lastLoop;
+
+ /// <summary>
+ /// The cell view index we are snapping to
+ /// </summary>
+ private int _snapCellViewIndex;
+
+ /// <summary>
+ /// The data index we are snapping to
+ /// </summary>
+ private int _snapDataIndex;
+
+ /// <summary>
+ /// Whether we are currently jumping due to a snap
+ /// </summary>
+ private bool _snapJumping;
+
+ /// <summary>
+ /// What the previous inertia setting was before the snap jump.
+ /// We cache it here because we need to turn off inertia while
+ /// manually tweeing.
+ /// </summary>
+ private bool _snapInertia;
+
+ /// <summary>
+ /// The cached value of the last scrollbar visibility setting. This is checked every
+ /// frame to see if the scrollbar visibility needs to be changed.
+ /// </summary>
+ private ScrollbarVisibilityEnum _lastScrollbarVisibility;
+
+ /// <summary>
+ /// Where in the list we are
+ /// </summary>
+ private enum ListPositionEnum
+ {
+ First,
+ Last
+ }
+
+ /// <summary>
+ /// The size of the active cell view container minus the visibile portion
+ /// of the scroller
+ /// </summary>
+ public float _ScrollSize//杩欓噷骞朵笉鏄寚scrllrect鐨勫ぇ灏忥紝鑰屾槸鎸囩湡姝e湪婊戝姩鐨勫尯鍩熺殑澶у皬
+ /*scrollrect鐨刵ormallizePosition瀹為檯涓婂氨鏄繖涓湡姝h兘婊戝姩鐨勫尯鍩熺殑澶у皬
+ * 鍦ㄦ粦鍔ㄨ繃绋嬩腑褰掍竴鍖栫殑鍊硷紝鑰岃繖涓ぇ灏忓氨鏄墍鏈夊瓙鐗╀綋鐨勫ぇ灏忎笌鍙鍖栧尯鍩熺殑宸�
+ * 褰揷ontent鐨勫ぇ灏忕瓑浜庢墍鏈夊瓙鐗╀綋鐨勫ぇ灏忔椂锛屽氨鍙互绠�鍖栨搷浣滅洿鎺ョ敤content鐨勫ぇ灏忔潵浠f浛
+ */
+ {
+ get
+ {
+ if (scrollDirection == ScrollDirectionEnum.Vertical)
+ {
+ if (_container != null && _scrollRectTransform != null)
+ return _container.rect.height - _scrollRectTransform.rect.height;
+ else
+ return 0;
+
+ }
+
+ else
+ {
+ if (_container != null && _scrollRectTransform != null)
+ return _container.rect.width - _scrollRectTransform.rect.width;
+ else
+ return 0;
+ }
+
+ }
+ }
+
+ /// <summary>
+ /// This function will create an internal list of sizes and offsets to be used in all calculations.
+ /// It also sets up the loop triggers and positions and initializes the cell views.
+ /// </summary>
+ /// <param name="keepPosition">If true, then the scroller will try to go back to the position it was at before the resize</param>
+ private void _Resize(bool keepPosition)
+ {
+ // cache the original position
+ var originalScrollPosition = _scrollPosition;
+
+ // clear out the list of cell view sizes and create a new list
+ _cellViewSizeArray.Clear();
+ var offset = _AddCellViewSizes();//姣忔娓呯┖鍚庨噸鏂版坊鍔犱竴娆★紝骞惰繑鍥炶繖涓泦鍚堢殑鍊肩殑鍜�
+
+ // if looping, we need to create three sets of size data
+ if (loop)
+ {
+ // if the cells don't entirely fill up the scroll area,
+ // make some more size entries to fill it up
+ if (offset < ScrollRectSize)//鎵�鏈夊瓙鐗╀綋鐩稿姞娌℃湁杩欏潡鍙鍖哄煙澶�
+ {
+ int additionalRounds = Mathf.CeilToInt(ScrollRectSize / offset);
+ _DuplicateCellViewSizes(additionalRounds, _cellViewSizeArray.Count);//濡傛灉瀛愮墿浣撶殑涓暟涓嶈冻浠ュ~鍏呭彲瑙嗗尯鍩燂紝瑕佽繘琛屽鍒�
+ }
+
+ // set up the loop indices
+ _loopFirstCellIndex = _cellViewSizeArray.Count;
+ _loopLastCellIndex = _loopFirstCellIndex + _cellViewSizeArray.Count - 1;
+ //杩欓噷鐨勪袱涓�兼槸鍦ㄩ泦鍚堟病鏈夎繘琛屼换浣曞鍒舵椂璧嬪�肩殑锛宊loopFirstCellIndex鏄浜屾寰幆鐨勭涓�涓厓绱犵储寮曪紝_loopLastCellIndex鏄浜屾寰幆鐨勬渶鍚庝竴涓储寮�
+
+ // create two more copies of the cell sizes
+ _DuplicateCellViewSizes(2, _cellViewSizeArray.Count);
+ /*褰撲娇鐢ㄥ惊鐜ā寮忕殑鏃跺�欙紝濡傛灉瀛愮墿浣撲笉瓒充互濉厖鍙鍖哄氨杩涜涓�娆″鍒讹紝浣垮厓绱犺兘澶熸粦鍔�
+ *褰撳厓绱犺冻澶熷锛岃兘澶熷湪鍙鍖烘粦鍔ㄧ殑鏃跺�欙紝鍐嶈繘琛屼袱娆″鍒讹紙鏈�缁堢粨鏋滄槸涓変釜寰幆锛�
+ * firstCellIndex涓虹涓�涓惊鐜殑绗竴涓墿浣撶储寮曪紝姣斿10涓厓绱狅紝绗竴涓惊鐜殑绗竴涓储寮曞氨鏄�10锛屽洜涓烘槸浠庯紙0~9锛�
+ * lastCellIndex涓虹涓�涓惊鐜殑鏈�鍚庝竴涓墿浣撶储寮曪紝姣斿10鍏冪礌锛�0~9锛�+ 10 = 19
+ * 瑕佹敞鎰忥細 涓婇潰璇寸殑澶嶅埗鍦ㄨ繖閲屽苟娌℃湁澶嶅埗娓告垙瀵硅薄锛屽彧鏄闆嗗悎杩涜浜嗕竴浜涙墿鍏咃紝杩欏彧鏄负浜嗘柟渚跨悊瑙�
+ */
+ }
+
+ // calculate the offsets of each cell view
+ _CalculateCellViewOffsets();//璁$畻浜嗙涓�涓厓绱犱笅鏂圭浉瀵瑰師鐐圭殑鍋忕Щ锛堝叾涓篃鍖呮嫭浜嗛棿璺濓級
+
+ // set the size of the active cell view container based on the number of cell views there are and each of their sizes
+ if (scrollDirection == ScrollDirectionEnum.Vertical)
+ _container.sizeDelta = new Vector2(_container.sizeDelta.x, _cellViewOffsetArray.Last() + padding.top + padding.bottom);
+ else
+ _container.sizeDelta = new Vector2(_cellViewOffsetArray.Last() + padding.left + padding.right, _container.sizeDelta.y);
+ //璁剧疆content鐨勫ぇ灏忥紝鏍规嵁_cellViewOffsetArray鐨勬渶鍚庝竴涓�煎氨鍙互寰楀埌鎵�鏈夊厓绱犲拰瀹冧滑鐨勯棿璺濈殑鎬诲拰锛屽啀鍔犱笂padding鐨勫�煎氨鍙互璁ヽontent鍜屾墍鏈夊瓙鐗╀綋瀹岀編鍖归厤
+ //涓斿洜涓轰箣鍓嶈缃簡pivot鐨勫師鍥狅紝鐩存帴璁剧疆content鐨勫ぇ灏忓苟涓嶄細璁╁畠寰�涓よ竟缂╂斁锛岃�屾槸椤虹潃鎴戜滑闇�瑕佺殑鏂瑰悜杩涜缂╂斁
+ // if looping, set up the loop positions and triggers
+ if (loop)
+ {
+ _loopFirstScrollPosition = GetScrollPositionForCellViewIndex(_loopFirstCellIndex, CellViewPositionEnum.Before) + (spacing * 0.5f);
+ _loopLastScrollPosition = GetScrollPositionForCellViewIndex(_loopLastCellIndex, CellViewPositionEnum.After) - ScrollRectSize + (spacing * 0.5f);
+
+
+ _loopFirstJumpTrigger = _loopFirstScrollPosition - ScrollRectSize;
+ _loopLastJumpTrigger = _loopLastScrollPosition + ScrollRectSize;
+ //firstJumpTrigger鏄涓�涓惊鐜殑鏈�鍚庝竴涓储寮曠殑涓嬫柟 - 鍙鍖哄ぇ灏忥紝lastJumpTrigger鏄浜屾寰幆鐨勬渶鍚庝竴涓储寮曠殑涓嬫柟
+ }
+
+ // create the visibile cells
+ _ResetVisibleCellViews();//鏍规嵁鍙鍖轰袱绔储寮曪紙閫氳繃_scrollPosition鏉ヨ绠楃储寮�)鏉ラ噸寤哄彲瑙嗗尯鍩熷唴鐨勫瓙鐗╀綋
+ if (this.Delegate != null)
+ {
+ this.Delegate.OnRebuildComplete();
+ }
+ // if we need to maintain our original position
+ if (keepPosition)//濡傛灉涓簍rue鍒欎繚鎸佽皟鐢ㄨ繖涓柟娉曟椂瀵瑰簲鐨勪綅缃�
+ {
+ ScrollPosition = originalScrollPosition;
+ }
+ else
+ {
+ if (loop)
+ {
+ ScrollPosition = _loopFirstScrollPosition;//寰幆妯″紡鏃跺畾涔夌殑鏄浜屾寰幆鐨勮捣濮嬬偣锛堢浉褰撲簬涓よ竟閮藉瓨鍦ㄤ竴涓惊鐜紝瀹氫綅鍦ㄤ腑闂撮偅涓惊鐜殑璧峰鐐癸級
+ }
+ else
+ {
+ ScrollPosition = 0;
+ }
+ }
+
+ // set up the visibility of the scrollbar
+ ScrollbarVisibility = scrollbarVisibility;
+
+ if (!m_IsLoadAll)
+ {
+ m_IsLoadAll = true;
+ if (OnFirstLoadAllEvent != null)
+ {
+ OnFirstLoadAllEvent();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Creates a list of cell view sizes for faster access
+ /// </summary>
+ /// <returns></returns>
+ private float _AddCellViewSizes()//鍒涘缓涓�涓敤浜庡瓨鏀炬墍鏈夊瓙鐗╀綋鐨勫ぇ灏忕殑闆嗗悎锛屽苟杩斿洖鎵�鏈夊瓙鐗╀綋鐩稿姞鍚庣殑鎬诲昂瀵�
+ {
+ var offset = 0f;
+ // add a size for each row in our data based on how many the delegate tells us to create
+ for (var i = 0; i < NumberOfCells; i++)
+ {
+ // add the size of this cell based on what the delegate tells us to use. Also add spacing if this cell isn't the first one
+ _cellViewSizeArray.Add(_delegate.GetCellViewSize(this, i) + (i == 0 ? 0 : _layoutGroup.spacing));
+ offset += _cellViewSizeArray[_cellViewSizeArray.Count - 1];
+ }
+
+ return offset;
+ }
+
+ /// <summary>
+ /// Create a copy of the cell view sizes. This is only used in looping
+ /// </summary>
+ /// <param name="numberOfTimes">How many times the copy should be made</param>
+ /// <param name="cellCount">How many cells to copy</param>
+ private void _DuplicateCellViewSizes(int numberOfTimes, int cellCount)//褰撲娇鐢ㄥ惊鐜ā寮忔椂锛屽鏋滃瓙鐗╀綋涓嶈冻浠ュ~鍏呭彲瑙嗗尯鍩燂紝灏辫繘琛屽鍒�
+ {
+ for (var i = 0; i < numberOfTimes; i++) //娉ㄦ剰姝ゅ鐨勫鍒跺苟涓嶆槸澶嶅埗娓告垙瀵硅薄锛岃�屽彧鏄泦鍚堢殑鎵╁厖
+ {
+ for (var j = 0; j < cellCount; j++)
+ {
+ _cellViewSizeArray.Add(_cellViewSizeArray[j] + (j == 0 ? _layoutGroup.spacing : 0));//瀛樺偍瀛愮墿浣搒ize鐨勯泦鍚堜篃瑕佽窡鐫�鍙�
+ /*j == 0 ? _layoutGroup.spacing : 0 娉ㄦ剰杩欎釜涓夊厓琛ㄨ揪寮忥紝鍦ㄨ繘琛屽鍒舵椂锛屽鏋滄槸澶嶅埗闆嗗悎鐨勭涓�涓厓绱犺澶氬姞涓�涓猻pacing
+ * 鍥犱负婊戝姩鏉′腑鍙湁绗竴涓厓绱犲墠鏂规垨宸︽柟鏄病鏈塻pacing鐨勶紝鎵�浠ュ綋澶嶅埗n浠芥椂锛屽氨瑕佸鍔爊涓猻pacing
+ */
+ }
+ }
+ }
+
+ /// <summary>
+ /// Calculates the offset of each cell, accumulating the values from previous cells
+ /// </summary>
+ private void _CalculateCellViewOffsets()//姝ゅ鐨勫亸绉婚泦鍚堝瓨鍌ㄧ殑鏄綋鍓嶇储寮曚笅鐨勭墿浣撲笅鏂圭浉瀵瑰師鐐圭殑鍋忕Щ閲忥紝涔熷氨鏄鏈�鍚庝竴涓厓绱犵殑澶у皬灏辨槸鎵�鏈夊瓙鐗╀綋澶у皬鍔犻棿璺濈殑鎬诲拰
+ {
+ _cellViewOffsetArray.Clear();
+ var offset = 0f;
+ for (var i = 0; i < _cellViewSizeArray.Count; i++)
+ {
+ offset += _cellViewSizeArray[i];
+ _cellViewOffsetArray.Add(offset);
+ }
+ }
+
+ /// <summary>
+ /// Get a recycled cell with a given identifier if available
+ /// </summary>
+ /// <param name="cellPrefab">The prefab to check for</param>
+ /// <returns></returns>
+ private EnhancedScrollerCellView _GetRecycledCellView(EnhancedScrollerCellView cellPrefab)//浠庣紦瀛樻睜涓彇涓�涓猚ellPrefab
+ {
+ for (var i = 0; i < _recycledCellViews.Count; i++)
+ {
+ if (_recycledCellViews[i].cellIdentifier == cellPrefab.cellIdentifier)
+ {
+ // the cell view was found, so we use this recycled one.
+ // we also remove it from the recycled list
+ var cellView = _recycledCellViews.RemoveAt(i);
+ return cellView;
+ }
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// This sets up the visible cells, adding and recycling as necessary
+ /// </summary>
+ private void _ResetVisibleCellViews()//閫氳繃鏌愪釜_scrollPosition鏉ュ垽鏂彲瑙嗗尯涓ょ鑳界湅鍒扮殑绱㈠紩锛屽啀閫氳繃杩欎袱涓储寮曟潵閲嶅缓鍙鍖哄唴鐨勫瓙鐗╀綋锛屽苟鏇存柊鐩稿簲鐨勯泦鍚�
+ {
+ int startIndex;
+ int endIndex;
+
+ // calculate the range of the visible cells
+ _CalculateCurrentActiveCellRange(out startIndex, out endIndex);//杩欎釜鏂规硶杩斿洖褰撳墠_scrollPosition瀵瑰簲鐨勫彲瑙嗗尯涓ょ鑳界湅鍒扮殑瀛愮墿浣撶储寮曪紙骞朵笉涓�瀹氳瀹屽叏鍦ㄥ彲瑙嗗尯鍐咃級
+ // go through each previous active cell and recycle it if it no longer falls in the range
+ var i = 0;
+ SmallList<int> remainingCellIndices = new SmallList<int>();
+ while (i < _activeCellViews.Count)
+ {
+ if (_activeCellViews[i].cellIndex < startIndex || _activeCellViews[i].cellIndex > endIndex)
+ {
+ _RecycleCell(_activeCellViews[i]);//濡傛灉鍘熸湰鍙鐨勫厓绱犱笉鍦ㄥ彲瑙嗗尯鍩熷唴灏嗗叾绉诲姩鍒癬RecycleCell鑺傜偣涓�
+ }
+ else
+ {
+ // this cell index falls in the new range, so we add its
+ // index to the reusable list
+ remainingCellIndices.Add(_activeCellViews[i].cellIndex);
+ //鍓╀笅鐨勮偗瀹氭槸鍙鍏冪礌锛屾斁鍏emainingCellIndices闆嗗悎涓紝杩欓噷瑕佹敞鎰忕殑鏄紝杩欎竴闆嗗悎骞朵笉涓�瀹氳兘澶熷~鍏呮暣涓彲瑙嗗尯鍩燂紝
+ //startIndex鍜宔ndIndex鍐呯殑閮ㄥ垎绱㈠紩鍙兘骞舵病鏈夊搴旂殑鍙瀛愮墿浣�
+ i++;
+ }
+ }
+
+ if (remainingCellIndices.Count == 0)//鍦ㄨ烦杞嚦杈冭繙浣嶇疆鏃讹紝浼氬鑷村師鏉ュ彲瑙佸厓绱犲叏閮ㄩ兘涓嶅彲瑙佷簡锛屽張鎴栬�呮缁勪欢鍒氳繘琛屽垵濮嬪寲鏃讹紝骞舵病鏈変换浣曞彲瑙佸厓绱�
+ {
+ // there were no previous active cells remaining,
+ // this list is either brand new, or we jumped to
+ // an entirely different part of the list.
+ // just add all the new cell views
+
+ for (i = startIndex; i <= endIndex; i++)
+ {
+ _AddCellView(i, ListPositionEnum.Last);
+ /*姝e簭娣诲姞锛屽綋remainingCellIndices闆嗗悎娌℃湁鍏冪礌鏃讹紝鐩存帴鎸夐『搴忔坊鍔犲氨鍙互浜嗭紝鍏堟坊鍔犵殑鍦ㄥ墠闈紝鍚庢坊鍔犵殑鍦ㄥ悗闈�
+ * 鍦ㄥ綋鍓峗scrollPosition涓嬭兘鐪嬪埌鐨勫氨鍙湁浠巗tartIndex鍒癳ndIndex杩欏嚑涓厓绱狅紝鍙渶瑕佸疄渚嬪寲锛堜粠缂撳啿姹犲彇锛夎繖鍑犱釜鍏冪礌灏辫浜�*/
+ }
+ }
+ else
+ {
+ // we are able to reuse some of the previous
+ // cell views
+
+ // first add the views that come before the
+ // previous list, going backward so that the
+ // new views get added to the front
+ for (i = endIndex; i >= startIndex; i--)
+ {
+ if (i < remainingCellIndices.First())
+ {
+ _AddCellView(i, ListPositionEnum.First);//鍊掑簭娣诲姞锛屽嵆褰撳墠娣诲姞鐨勫厓绱犱竴瀹氬湪绗竴涓紝瀹屾垚寰幆鍚庣涓�涓娣诲姞鐨勫厓绱犲氨鏀惧埌浜嗘渶鍚庝竴涓�
+ }
+ /*褰搑emainingCellIndices闆嗗悎涓瓨鍦ㄥ厓绱犳椂锛岃鏄庨泦鍚堜腑鐨勫厓绱犳槸鍙鐨勶紝浣嗘槸涓嶄竴瀹氳兘澶熷畬鍏ㄥ~鍏呭彲瑙嗗尯锛屾墍浠ヨ繕闇�瑕佹牴鎹儏鍐垫潵娣诲姞鏂扮殑鍙鍏冪礌
+ * 濡傛灉姝ら泦鍚堢殑鏈�灏忓厓绱犵储寮曞ぇ浜巗tartIndex鍜宔ndIndex涔嬪唴鐨勬煇涓�绱㈠紩锛岃鏄庤繖涓�绱㈠紩瀵瑰簲鐨勫瓙鐗╀綋瑕佽繘琛屽疄渚嬪寲锛堜粠缂撳啿姹犲彇锛夛紝涓斾竴瀹氭帓鍦ㄨ繖涓泦鍚堢殑绗竴涓厓绱犱箣鍓�
+ * 杩欓噷瑕佹敞鎰忕殑鏄惊鐜腑i鏄�掑噺鐨勶紝褰撶储寮昳姣旈泦鍚堜腑鏈�灏忕殑鍏冪礌绱㈠紩閮借灏忔椂璇存槑浜唅绱㈠紩姝ゆ椂骞舵病鏈夊彲瀵瑰簲鐨勫彲瑙佸瓙鐗╀綋锛屽疄渚嬪寲瀛愮墿浣撴椂瑕�
+ * 灏嗗畠璁剧疆鍦ㄦ渶鍓嶉潰锛屼互姝ょ被鎺紝寰幆瀹屾垚鍚庯紝鍚庢坊鍔犵殑浼氭瘮鍏堟坊鍔犵殑鎺掑湪鍓嶉潰
+ */
+ }
+
+ // next add teh views that come after the
+ // previous list, going forward and adding
+ // at the end of the list
+ for (i = startIndex; i <= endIndex; i++)
+ {
+ if (i > remainingCellIndices.Last())
+ {
+ _AddCellView(i, ListPositionEnum.Last);
+ }
+ /*褰撴闆嗗悎鏈�澶х殑鍏冪礌绱㈠紩灏忎簬startIndex鍒癳ndIndex涓煇涓�绱㈠紩鏃讹紝璇存槑杩欎竴绱㈠紩涓�鏍锋病鏈夊搴旂殑鍙瀛愮墿浣擄紝
+ * 鍙堝洜涓烘寰幆鏄�掑鐨勶紝鎵�浠ュ厛杩涜瀹炰緥鍖栵紙缂撳啿姹犲彇锛夌殑瀛愮墿浣撲竴瀹氭槸瑕佹瘮鍚庢坊鍔犵殑瀛愮墿浣撴帓鍦ㄥ墠闈�
+ */
+ }
+ }
+
+ // update the start and end indices
+ _activeCellViewsStartIndex = startIndex;
+ _activeCellViewsEndIndex = endIndex;
+
+ // adjust the padding elements to offset the cell views correctly
+ _SetPadders();//褰撳彲瑙佸尯鍩熻濉厖婊″悗锛屽氨鍙互灏嗗叾瀹冨尯鍩熻缃负padding
+ }
+
+ /// <summary>
+ /// Recycles all the active cells
+ /// </summary>
+ private void _RecycleAllCells()//绉婚櫎鍏ㄩ儴鍙鍏冪礌鍒扮紦鍐叉睜
+ {
+ while (_activeCellViews.Count > 0) _RecycleCell(_activeCellViews[0]);
+ _activeCellViewsStartIndex = 0;
+ _activeCellViewsEndIndex = 0;
+ }
+
+ /// <summary>
+ /// Recycles one cell view
+ /// </summary>
+ /// <param name="cellView"></param>
+ public void _RecycleCell(EnhancedScrollerCellView cellView)//浠巁activeCellVeiws闆嗗悎涓Щ闄ゅ厓绱犲埌_RecycleCell闆嗗悎涓�
+ {
+ // remove the cell view from the active list
+ _activeCellViews.Remove(cellView);
+
+ // add the cell view to the recycled list
+ _recycledCellViews.Add(cellView);
+
+ // move the GameObject to the recycled container
+ cellView.transform.SetParent(_recycledCellViewContainer);
+
+ // reset the cellView's properties
+ cellView.dataIndex = 0;
+ cellView.cellIndex = 0;
+ cellView.active = false;
+
+ if (cellViewVisibilityChanged != null) cellViewVisibilityChanged(cellView);
+ }
+
+ /// <summary>
+ /// Creates a cell view, or recycles if it can
+ /// </summary>
+ /// <param name="cellIndex">The index of the cell view</param>
+ /// <param name="listPosition">Whether to add the cell to the beginning or the end</param>
+ private void _AddCellView(int cellIndex, ListPositionEnum listPosition)
+ {
+ //閫氳繃鏌愪釜绱㈠紩娣诲姞锛堜粠缂撳啿姹犱腑鍙栵級瀛愮墿浣撳埌_activeCellViews闆嗗悎涓紝骞惰Е鍙戠浉鍏充簨浠�
+ //杩欎釜鏂规硶鏈韩涔熶細鏍规嵁浼犺繃鏉ョ殑绱㈠紩鏉ュ垵濮嬪寲CellView
+
+ if (NumberOfCells == 0) return;
+
+ // get the dataIndex. Modulus is used in case of looping so that the first set of cells are ignored
+ var dataIndex = cellIndex % NumberOfCells;
+ // request a cell view from the delegate
+ var cellView = _delegate.GetCellView(this, dataIndex, cellIndex);
+
+ // set the cell's properties
+ cellView.cellIndex = cellIndex;
+ cellView.dataIndex = dataIndex;
+ cellView.active = true;
+
+ // add the cell view to the active container
+ cellView.transform.SetParent(_container, false);
+ cellView.transform.localScale = Vector3.one;
+
+ // add a layout element to the cellView
+ LayoutElement layoutElement = cellView.GetComponent<LayoutElement>();
+ if (layoutElement == null) layoutElement = cellView.gameObject.AddComponent<LayoutElement>();
+
+ // set the size of the layout element
+ if (scrollDirection == ScrollDirectionEnum.Vertical)
+ layoutElement.minHeight = _cellViewSizeArray[cellIndex] - (cellIndex > 0 ? _layoutGroup.spacing : 0);
+ else
+ layoutElement.minWidth = _cellViewSizeArray[cellIndex] - (cellIndex > 0 ? _layoutGroup.spacing : 0);
+
+ // add the cell to the active list
+ if (listPosition == ListPositionEnum.First)
+ _activeCellViews.AddStart(cellView);
+ else
+ _activeCellViews.Add(cellView);
+
+ // set the hierarchy position of the cell view in the container
+ if (listPosition == ListPositionEnum.Last)
+ cellView.transform.SetSiblingIndex(_container.childCount - 2);//杩欓噷鐨勬坊鍔犳柟寮忓喅瀹氫簡涓や釜padder鐨勪綅缃槸澶圭潃鎵�鏈夌殑cellView鐨�
+ else if (listPosition == ListPositionEnum.First)
+ cellView.transform.SetSiblingIndex(1);
+
+ // call the visibility change delegate if available
+ if (cellViewVisibilityChanged != null) cellViewVisibilityChanged(cellView);
+ }
+
+ /// <summary>
+ /// This function adjusts the two padders that control the first cell view's
+ /// offset and the overall size of each cell.
+ /// </summary>
+ private void _SetPadders()//褰撳鐞嗗畬鍙鍖哄煙鍚庯紝Padder灏卞彲浠ヨ绠楀嚭鏉ワ紝padder鐨勪綔鐢ㄥ氨鏄敤鏉ユ敮鎾戞暣涓猻croll鍐呯殑鍏冪礌锛屼繚璇佸畠浠殑浣嶇疆
+ {
+ if (NumberOfCells == 0) return;
+
+ // calculate the size of each padder
+ var firstSize = _cellViewOffsetArray[_activeCellViewsStartIndex] - _cellViewSizeArray[_activeCellViewsStartIndex];
+ var lastSize = _cellViewOffsetArray.Last() - _cellViewOffsetArray[_activeCellViewsEndIndex];
+
+ if (scrollDirection == ScrollDirectionEnum.Vertical)
+ {
+ // set the first padder and toggle its visibility
+ _firstPadder.minHeight = firstSize;
+ _firstPadder.SetActive(_firstPadder.minHeight > 0);
+
+ // set the last padder and toggle its visibility
+ _lastPadder.minHeight = lastSize;
+ _lastPadder.SetActive(_lastPadder.minHeight > 0);
+ }
+ else
+ {
+ // set the first padder and toggle its visibility
+ _firstPadder.minWidth = firstSize;
+ _firstPadder.SetActive(_firstPadder.minWidth > 0);
+
+ // set the last padder and toggle its visibility
+ _lastPadder.minWidth = lastSize;
+ _lastPadder.SetActive(_lastPadder.minWidth > 0);
+ }
+ }
+
+ /// <summary>
+ /// This function is called if the scroller is scrolled, updating the active list of cells
+ /// </summary>
+ private void _RefreshActive()
+ {
+ _refreshActive = false;
+
+ int startIndex;
+ int endIndex;
+ var velocity = Vector2.zero;
+
+ // if looping, check to see if we scrolled past a trigger
+ if (loop)
+ {
+ if (_scrollPosition < _loopFirstJumpTrigger)
+ {
+ velocity = scrollRect.velocity;
+ ScrollPosition = _loopLastScrollPosition - (_loopFirstJumpTrigger - _scrollPosition);
+ scrollRect.velocity = velocity;
+ }
+ else if (_scrollPosition > _loopLastJumpTrigger)
+ {
+ velocity = scrollRect.velocity;
+ ScrollPosition = _loopFirstScrollPosition + (_scrollPosition - _loopLastJumpTrigger);
+ scrollRect.velocity = velocity;
+ }
+ //寰幆妯″紡涓嬭灏哠crollPosition闄愬埗鍦ㄧ浜屼釜寰幆鍐咃紝杩欓噷鐨勫嚑涓彉閲忛兘鏄敤浜庢帶鍒惰繖涓�灞炴�х殑
+ /*娉ㄦ剰杩欓噷鐨凷crollPosition鐨勮祴鍊兼搷浣滐紝鍙湁褰撳湪寰幆妯″紡涓嬶紝涓旀粦鍔ㄧ殑鍋忕Щ宸茬粡杈惧埌浜嗚Е鍙慱loopJumpTrigger鐨勬椂鍊�
+ * 瀹冩墠浼氬彂鐢熻祴鍊兼搷浣滐紝褰撳畠琚祴鍊间互鍚庯紝鍗虫鏃剁殑content鐨勪綅缃彂鐢熶簡鏀瑰彉锛岀劧鍚庝細鍐嶆璋冪敤姝ゆ柟娉曞埛鏂板彲瑙嗗尯锛岀洿鍒板啀娆¤Е鍙憀oopJumpTirgger
+ * 涔嬪墠锛孲crollPosition閮戒笉浼氬啀娆¤璧嬪�间簡
+ */
+ }
+
+ // get the range of visibile cells
+ _CalculateCurrentActiveCellRange(out startIndex, out endIndex);
+
+ // if the index hasn't changed, ignore and return
+ if (startIndex == _activeCellViewsStartIndex && endIndex == _activeCellViewsEndIndex) return;
+
+ // recreate the visibile cells
+ _ResetVisibleCellViews();
+
+ if (this.Delegate != null)
+ {
+ this.Delegate.OnRebuildComplete();
+ }
+ }
+
+ /// <summary>
+ /// Determines which cells can be seen
+ /// </summary>
+ /// <param name="startIndex">The index of the first cell visible</param>
+ /// <param name="endIndex">The index of the last cell visible</param>
+ private void _CalculateCurrentActiveCellRange(out int startIndex, out int endIndex)//杩欎釜鏂规硶杩斿洖鐨勬槸鍩轰簬_scrollPosition寰楀埌鐨勫彲瑙嗗尯鍩熶袱绔储寮�
+ {
+ startIndex = 0;
+ endIndex = 0;
+
+ // get the positions of the scroller
+ var startPosition = _scrollPosition;
+ var endPosition = _scrollPosition + (scrollDirection == ScrollDirectionEnum.Vertical ? _scrollRectTransform.rect.height : _scrollRectTransform.rect.width);
+
+ // calculate each index based on the positions
+ startIndex = GetCellViewIndexAtPosition(startPosition);
+ endIndex = GetCellViewIndexAtPosition(endPosition);
+ }
+
+ /// <summary>
+ /// Gets the index of a cell at a given position based on a subset range.
+ /// This function uses a recursive binary sort to find the index faster.
+ /// </summary>
+ /// <param name="position">The pixel offset from the start of the scroller</param>
+ /// <param name="startIndex">The first index of the range</param>
+ /// <param name="endIndex">The last index of the rnage</param>
+ /// <returns></returns>
+ private int _GetCellIndexAtPosition(float position, int startIndex, int endIndex)//杩欎釜鏂规硶鐨剆tartIndex涓�0 锛宔ndIndex涓篲cellViewOffsetArray鐨勫厓绱犳暟閲�(浣嗕細鏍规嵁璁$畻鐨勫�艰繘琛岃皟鏁达級
+ {
+ // if the range is invalid, then we found our index, return the start index
+ if (startIndex >= endIndex) return startIndex;
+ // determine the middle point of our binary search
+ var middleIndex = (startIndex + endIndex) / 2;
+ // if the middle index is greater than the position, then search the last
+ // half of the binary tree, else search the first half
+ if ((_cellViewOffsetArray[middleIndex] + (scrollDirection == ScrollDirectionEnum.Vertical ? padding.top : padding.left)) >= position)
+ return _GetCellIndexAtPosition(position, startIndex, middleIndex);
+ else
+ return _GetCellIndexAtPosition(position, middleIndex + 1, endIndex);
+ }
+
+ /// <summary>
+ /// Caches and initializes the scroller
+ /// </summary>
+ void Awake()
+ {
+ GameObject go;
+
+ // cache some components
+ //_scrollRect = this.GetComponent<ScrollRect>();
+ _scrollRectTransform = scrollRect.GetComponent<RectTransform>();
+
+ // destroy any content objects if they exist. Likely there will be
+ // one at design time because Unity gives errors if it can't find one.
+ if (scrollRect.content != null)
+ {
+ DestroyImmediate(scrollRect.content.gameObject);//濡傛灉瀛樺湪content鍒欓攢姣�
+ }
+
+ // Create a new active cell view container with a layout group
+ go = new GameObject("Container", typeof(RectTransform));
+ go.transform.SetParent(_scrollRectTransform);
+ if (scrollDirection == ScrollDirectionEnum.Vertical)
+ go.AddComponent<VerticalLayoutGroup>();
+ else
+ go.AddComponent<HorizontalLayoutGroup>();
+ _container = go.GetComponent<RectTransform>();
+ // set the containers anchor and pivot
+ if (scrollDirection == ScrollDirectionEnum.Vertical)
+ {
+ _container.anchorMin = new Vector2(0, 1);
+ _container.anchorMax = Vector2.one;
+ _container.pivot = new Vector2(0.5f, 1f);
+ //璁剧疆浜哻ontent鐨勯敋鐐瑰拰杞村績锛屼富瑕佷綔鐢ㄦ槸渚夸簬璁$畻,浠ュ畠涓婃柟涓績鐨勭偣鍒皊croll涓婃柟鐨勮窛绂讳负瀹冪殑y杞村�硷紝瀹冪殑闀垮害鍗充负瀹冪殑Height灞炴��
+ //褰撹缃畠鐨勯珮鐨勬椂鍊欏氨鏄缃簡浠栫殑澶у皬
+ }
+ else
+ {
+ _container.anchorMin = Vector2.zero;
+ _container.anchorMax = new Vector2(0, 1f);
+ _container.pivot = new Vector2(0, 0.5f);//鍚屼笂
+ }
+ _container.offsetMax = Vector2.zero;
+ _container.offsetMin = Vector2.zero;
+ _container.localScale = Vector3.one;
+ Vector3 pos = _container.transform.localPosition;
+ pos.z = 0;
+ _container.transform.localPosition = pos;
+ //灏嗗畠鐨勪綅缃浐瀹氬湪scrol涓婃柟鎴栧乏鏂癸紝閫氳繃杩欎釜浣嶇疆鍜屼笂闈㈣缃殑閿氱偣鏉ヤ繚璇佽缃ぇ灏忕殑鏃跺�欎笉浼氳窇鍋�
+ scrollRect.content = _container;
+
+ // cache the scrollbar if it exists
+ if (scrollDirection == ScrollDirectionEnum.Vertical)
+ {
+ _scrollbar = scrollRect.verticalScrollbar;
+ }
+ else
+ {
+ _scrollbar = scrollRect.horizontalScrollbar;
+ }
+
+ // cache the layout group and set up its spacing and padding
+ _layoutGroup = _container.GetComponent<HorizontalOrVerticalLayoutGroup>();
+ _layoutGroup.spacing = spacing;
+ _layoutGroup.padding = padding;
+ _layoutGroup.childAlignment = TextAnchor.UpperLeft;//娣诲姞閿氱偣
+ _layoutGroup.childForceExpandHeight = true;
+ _layoutGroup.childForceExpandWidth = true;
+
+ // force the scroller to scroll in the direction we want
+ //_scrollRect.horizontal = scrollDirection == ScrollDirectionEnum.Horizontal;
+ //_scrollRect.vertical = scrollDirection == ScrollDirectionEnum.Vertical;
+
+ // create the padder objects
+
+ go = new GameObject("First Padder", typeof(RectTransform), typeof(LayoutElement));
+ go.transform.SetParent(_container, false);
+ _firstPadder = go.GetComponent<LayoutElement>();
+
+ go = new GameObject("Last Padder", typeof(RectTransform), typeof(LayoutElement));
+ go.transform.SetParent(_container, false);
+ _lastPadder = go.GetComponent<LayoutElement>();
+
+ // create the recycled cell view container
+ go = new GameObject("Recycled Cells", typeof(RectTransform));
+ go.transform.SetParent(scrollRect.transform, false);
+ _recycledCellViewContainer = go.GetComponent<RectTransform>();
+ _recycledCellViewContainer.SetActive(false);
+ //瀹炰緥鍖栦簡涓や釜padder鍜屼竴涓紦鍐叉睜
+ // set up the last values for updates
+ _lastScrollRectSize = ScrollRectSize;
+ _lastLoop = loop;
+ _lastScrollbarVisibility = scrollbarVisibility;
+ //涓�浜涘彉閲忚繘琛屼簡鍒濆鍖�
+
+ if(OnCompLoad!=null) OnCompLoad();
+ inited = true;
+ }
+
+ void Update()
+ {
+ if (_reloadData)//褰撳閮ㄨ剼鏈缃瓺elegate鐨勬椂鍊欏氨浼氬皢_reloadData缃负true
+ {
+ // if the reload flag is true, then reload the data
+ ReloadData();//鐞嗚涓婁笉鐢ㄥ湪澶栭儴璋冪敤ReloadData()鍥犱负褰撴垚鍔熻祴鍊糄elegate鍚庤繖涓柟娉曞氨浼氭墽琛屼竴娆�
+ //浣嗗鏋滄兂鍦╱pdate涔嬪墠鎵ц灏变富鍔ㄨ皟鐢≧eloadData()
+ }
+
+ // if the scroll rect size has changed and looping is on,
+ // or the loop setting has changed, then we need to resize
+ if (
+ (loop && _lastScrollRectSize != ScrollRectSize)//褰揝croll鐨勫ぇ灏忓彂鐢熸敼鍙樺苟涓斿紑鍚惊鐜椂
+ ||
+ (loop != _lastLoop)//褰撳惊鐜紑鍏冲彂鐢熶簡鏀瑰彉
+ )
+ {
+ _Resize(true);
+ _lastScrollRectSize = ScrollRectSize;
+
+ _lastLoop = loop;
+ }
+
+ // update the scroll bar visibility if it has changed
+ if (_lastScrollbarVisibility != scrollbarVisibility)//濡傛灉婊戝姩鏉$殑鍙鎬у彂鐢熸敼鍙樹篃闇�瑕佹洿鏂颁竴涓嬬浉鍏冲彉閲�
+ {
+ ScrollbarVisibility = scrollbarVisibility;
+ _lastScrollbarVisibility = scrollbarVisibility;
+ }
+
+ // determine if the scroller has started or stopped scrolling
+ // and call the delegate if so.
+ if (LinearVelocity != 0 && !IsScrolling)//褰揝croll.velocity涓嶄负0鏃惰鏄庡湪婊戝姩锛屾鏃跺鏋淚sScrolling涓篺alse(鏍囪涓烘病鏈夋粦鍔�)
+ { //瑙﹀彂褰撴粦鍔ㄥ紑濮嬫椂鐨勪簨浠�
+ IsScrolling = true;
+ if (scrollerScrollingChanged != null) scrollerScrollingChanged(this, true);
+ }
+ else if (LinearVelocity == 0 && IsScrolling)//鍚岀悊瑙﹀彂褰撴粦鍔ㄧ粨鏉熸椂鐨勪簨浠讹紝杩欓噷鐨勪袱涓簨浠堕兘鍙細鍦ㄤ竴涓粦鍔ㄥ懆鏈熸椂鍚勬墽琛屼竴娆�
+ {
+ IsScrolling = false;
+ if (scrollerScrollingChanged != null) scrollerScrollingChanged(this, false);
+ }
+ }
+
+ void LateUpdate()
+ {
+ if (_refreshActive)//褰撹缃甋crollPosition鏃跺氨浼氬皢_refreshActive缃负true,姝ゆ椂灏变細璋冪敤_RefreshActive()鏂规硶
+ {
+ // if the refresh toggle is on, then
+ // refresh the list
+ _RefreshActive();
+ }
+ }
+
+ void OnEnable()
+ {
+ // when the scroller is enabled, add a listener to the onValueChanged handler
+ scrollRect.onValueChanged.AddListener(_ScrollRect_OnValueChanged);//褰撴樉绀烘椂娉ㄥ唽
+ }
+
+ void OnDisable()
+ {
+ // when the scroller is disabled, remove the listener
+ scrollRect.onValueChanged.RemoveListener(_ScrollRect_OnValueChanged);//褰撻殣钘忔椂绉婚櫎娉ㄥ唽
+ }
+
+ /// <summary>
+ /// Handler for when the scroller changes value
+ /// </summary>
+ /// <param name="val">The scroll rect's value</param>
+ private void _ScrollRect_OnValueChanged(Vector2 val)
+ {
+ // set the internal scroll position
+ if (scrollDirection == ScrollDirectionEnum.Vertical)
+ {
+ _scrollPosition = (1f - val.y) * _ScrollSize;//娉ㄦ剰杩欓噷鍙槸缁欑鏈夊瓧娈佃祴鍊硷紝骞朵笉浼氳皟鐢ㄧ浉鍏冲睘鎬х殑Set鏂规硶锛堝鏋滆皟鐢ㄤ簡Set鏂规硶浼氬鑷存棤闄愬惊鐜紝Set鏂规硶浼氳Е鍙憊aluechange锛寁aluechange鍙堣Е鍙慡et)
+ }
+ else
+ {
+ _scrollPosition = val.x * _ScrollSize;
+ }
+ _refreshActive = true;//鏍囪瑕佽繘琛屽埛鏂�
+
+ // call the handler if it exists
+ if (scrollerScrolled != null) scrollerScrolled(this, val, _scrollPosition);//婊戝姩杩囩▼涓Е鍙戠殑鐩稿叧浜嬩欢
+
+ // if the snapping is turned on, handle it
+ if (snapping && !_snapJumping)//濡傛灉寮�鍚攣瀹氫綅缃紝浣嗘鏃舵病鏈夊畾浣�
+ {
+ // if the speed has dropped below the threshhold velocity
+ if (Mathf.Abs(LinearVelocity) <= snapVelocityThreshold)
+ {
+ // Call the snap function
+ Snap();//杩涜瀹氫綅
+ }
+ }
+
+ _RefreshActive();//鍒锋柊
+ /*鍦ㄦ粦鍔ㄧ殑杩囩▼涓紝閫氳繃NormalizePosition鏉ユ眰寰梍scrollPosition
+ * 濡傛灉婊¤冻瀹氫綅鏉′欢灏辫繘琛屽畾浣�
+ * 浠ヤ笂浠g爜鎵ц瀹屾垚鍚庡氨浼氬幓鍒锋柊鏁翠釜Scroll
+ */
+
+ }
+
+ /// <summary>
+ /// This is fired by the tweener when the snap tween is completed
+ /// </summary>
+ private void SnapJumpComplete()//褰撳畾浣嶅畬鎴愭椂
+ {
+ // reset the snap jump to false and restore the inertia state
+ _snapJumping = false;
+ scrollRect.inertia = _snapInertia;
+
+ // fire the scroller snapped delegate
+ if (scrollerSnapped != null) scrollerSnapped(this, _snapCellViewIndex, _snapDataIndex);
+ }
+
+ #endregion
+
+ #region Tweening
+
+ /// <summary>
+ /// The easing type
+ /// </summary>
+ public enum TweenType
+ {
+ immediate,
+ linear,
+ spring,
+ easeInQuad,
+ easeOutQuad,
+ easeInOutQuad,
+ easeInCubic,
+ easeOutCubic,
+ easeInOutCubic,
+ easeInQuart,
+ easeOutQuart,
+ easeInOutQuart,
+ easeInQuint,
+ easeOutQuint,
+ easeInOutQuint,
+ easeInSine,
+ easeOutSine,
+ easeInOutSine,
+ easeInExpo,
+ easeOutExpo,
+ easeInOutExpo,
+ easeInCirc,
+ easeOutCirc,
+ easeInOutCirc,
+ easeInBounce,
+ easeOutBounce,
+ easeInOutBounce,
+ easeInBack,
+ easeOutBack,
+ easeInOutBack,
+ easeInElastic,
+ easeOutElastic,
+ easeInOutElastic
+ }
+
+ private float _tweenTimeLeft;
+ public bool inited;
+
+ /// <summary>
+ /// Moves the scroll position over time between two points given an easing function. When the
+ /// tween is complete it will fire the jumpComplete delegate.
+ /// </summary>
+ /// <param name="tweenType">The type of easing to use</param>
+ /// <param name="time">The amount of time to interpolate</param>
+ /// <param name="start">The starting scroll position</param>
+ /// <param name="end">The ending scroll position</param>
+ /// <param name="jumpComplete">The action to fire when the tween is complete</param>
+ /// <returns></returns>
+ IEnumerator TweenPosition(TweenType tweenType, float time, float start, float end, Action tweenComplete)
+ {
+ if (tweenType == TweenType.immediate || time == 0)
+ {
+ // if the easing is immediate or the time is zero, just jump to the end position
+ ScrollPosition = end;
+ }
+ else
+ {
+ // zero out the velocity
+ scrollRect.velocity = Vector2.zero;
+
+ // fire the delegate for the tween start
+ IsTweening = true;
+ if (scrollerTweeningChanged != null) scrollerTweeningChanged(this, true);
+
+ _tweenTimeLeft = 0;
+ var newPosition = 0f;
+
+ // while the tween has time left, use an easing function
+ while (_tweenTimeLeft < time)
+ {
+ switch (tweenType)
+ {
+ case TweenType.linear: newPosition = linear(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.spring: newPosition = spring(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeInQuad: newPosition = easeInQuad(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeOutQuad: newPosition = easeOutQuad(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeInOutQuad: newPosition = easeInOutQuad(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeInCubic: newPosition = easeInCubic(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeOutCubic: newPosition = easeOutCubic(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeInOutCubic: newPosition = easeInOutCubic(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeInQuart: newPosition = easeInQuart(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeOutQuart: newPosition = easeOutQuart(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeInOutQuart: newPosition = easeInOutQuart(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeInQuint: newPosition = easeInQuint(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeOutQuint: newPosition = easeOutQuint(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeInOutQuint: newPosition = easeInOutQuint(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeInSine: newPosition = easeInSine(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeOutSine: newPosition = easeOutSine(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeInOutSine: newPosition = easeInOutSine(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeInExpo: newPosition = easeInExpo(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeOutExpo: newPosition = easeOutExpo(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeInOutExpo: newPosition = easeInOutExpo(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeInCirc: newPosition = easeInCirc(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeOutCirc: newPosition = easeOutCirc(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeInOutCirc: newPosition = easeInOutCirc(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeInBounce: newPosition = easeInBounce(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeOutBounce: newPosition = easeOutBounce(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeInOutBounce: newPosition = easeInOutBounce(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeInBack: newPosition = easeInBack(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeOutBack: newPosition = easeOutBack(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeInOutBack: newPosition = easeInOutBack(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeInElastic: newPosition = easeInElastic(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeOutElastic: newPosition = easeOutElastic(start, end, (_tweenTimeLeft / time)); break;
+ case TweenType.easeInOutElastic: newPosition = easeInOutElastic(start, end, (_tweenTimeLeft / time)); break;
+ }
+
+ if (loop)
+ {
+ // if we are looping, we need to make sure the new position isn't past the jump trigger.
+ // if it is we need to reset back to the jump position on the other side of the area.
+
+ if (end > start && newPosition > _loopLastJumpTrigger)
+ {
+ //DesignDebug.Log("name: " + name + " went past the last jump trigger, looping back around");
+ newPosition = _loopFirstScrollPosition + (newPosition - _loopLastJumpTrigger);
+ }
+ else if (start > end && newPosition < _loopFirstJumpTrigger)
+ {
+ //DesignDebug.Log("name: " + name + " went past the first jump trigger, looping back around");
+ newPosition = _loopLastScrollPosition - (_loopFirstJumpTrigger - newPosition);
+ }
+ }
+
+ // set the scroll position to the tweened position
+ ScrollPosition = newPosition;
+
+ // increase the time elapsed
+ _tweenTimeLeft += Time.unscaledDeltaTime;
+
+ yield return null;
+ }
+
+ // the time has expired, so we make sure the final scroll position
+ // is the actual end position.
+ ScrollPosition = end;
+ }
+
+ // the tween jump is complete, so we fire the delegate
+ if (tweenComplete != null) tweenComplete();
+
+ // fire the delegate for the tween ending
+ IsTweening = false;
+ if (scrollerTweeningChanged != null) scrollerTweeningChanged(this, false);
+ }
+
+ private float linear(float start, float end, float val)
+ {
+ return Mathf.Lerp(start, end, val);
+ }
+
+ private static float spring(float start, float end, float val)
+ {
+ val = Mathf.Clamp01(val);
+ val = (Mathf.Sin(val * Mathf.PI * (0.2f + 2.5f * val * val * val)) * Mathf.Pow(1f - val, 2.2f) + val) * (1f + (1.2f * (1f - val)));
+ return start + (end - start) * val;
+ }
+
+ private static float easeInQuad(float start, float end, float val)
+ {
+ end -= start;
+ return end * val * val + start;
+ }
+
+ private static float easeOutQuad(float start, float end, float val)
+ {
+ end -= start;
+ return -end * val * (val - 2) + start;
+ }
+
+ private static float easeInOutQuad(float start, float end, float val)
+ {
+ val /= .5f;
+ end -= start;
+ if (val < 1) return end / 2 * val * val + start;
+ val--;
+ return -end / 2 * (val * (val - 2) - 1) + start;
+ }
+
+ private static float easeInCubic(float start, float end, float val)
+ {
+ end -= start;
+ return end * val * val * val + start;
+ }
+
+ private static float easeOutCubic(float start, float end, float val)
+ {
+ val--;
+ end -= start;
+ return end * (val * val * val + 1) + start;
+ }
+
+ private static float easeInOutCubic(float start, float end, float val)
+ {
+ val /= .5f;
+ end -= start;
+ if (val < 1) return end / 2 * val * val * val + start;
+ val -= 2;
+ return end / 2 * (val * val * val + 2) + start;
+ }
+
+ private static float easeInQuart(float start, float end, float val)
+ {
+ end -= start;
+ return end * val * val * val * val + start;
+ }
+
+ private static float easeOutQuart(float start, float end, float val)
+ {
+ val--;
+ end -= start;
+ return -end * (val * val * val * val - 1) + start;
+ }
+
+ private static float easeInOutQuart(float start, float end, float val)
+ {
+ val /= .5f;
+ end -= start;
+ if (val < 1) return end / 2 * val * val * val * val + start;
+ val -= 2;
+ return -end / 2 * (val * val * val * val - 2) + start;
+ }
+
+ private static float easeInQuint(float start, float end, float val)
+ {
+ end -= start;
+ return end * val * val * val * val * val + start;
+ }
+
+ private static float easeOutQuint(float start, float end, float val)
+ {
+ val--;
+ end -= start;
+ return end * (val * val * val * val * val + 1) + start;
+ }
+
+ private static float easeInOutQuint(float start, float end, float val)
+ {
+ val /= .5f;
+ end -= start;
+ if (val < 1) return end / 2 * val * val * val * val * val + start;
+ val -= 2;
+ return end / 2 * (val * val * val * val * val + 2) + start;
+ }
+
+ private static float easeInSine(float start, float end, float val)
+ {
+ end -= start;
+ return -end * Mathf.Cos(val / 1 * (Mathf.PI / 2)) + end + start;
+ }
+
+ private static float easeOutSine(float start, float end, float val)
+ {
+ end -= start;
+ return end * Mathf.Sin(val / 1 * (Mathf.PI / 2)) + start;
+ }
+
+ private static float easeInOutSine(float start, float end, float val)
+ {
+ end -= start;
+ return -end / 2 * (Mathf.Cos(Mathf.PI * val / 1) - 1) + start;
+ }
+
+ private static float easeInExpo(float start, float end, float val)
+ {
+ end -= start;
+ return end * Mathf.Pow(2, 10 * (val / 1 - 1)) + start;
+ }
+
+ private static float easeOutExpo(float start, float end, float val)
+ {
+ end -= start;
+ return end * (-Mathf.Pow(2, -10 * val / 1) + 1) + start;
+ }
+
+ private static float easeInOutExpo(float start, float end, float val)
+ {
+ val /= .5f;
+ end -= start;
+ if (val < 1) return end / 2 * Mathf.Pow(2, 10 * (val - 1)) + start;
+ val--;
+ return end / 2 * (-Mathf.Pow(2, -10 * val) + 2) + start;
+ }
+
+ private static float easeInCirc(float start, float end, float val)
+ {
+ end -= start;
+ return -end * (Mathf.Sqrt(1 - val * val) - 1) + start;
+ }
+
+ private static float easeOutCirc(float start, float end, float val)
+ {
+ val--;
+ end -= start;
+ return end * Mathf.Sqrt(1 - val * val) + start;
+ }
+
+ private static float easeInOutCirc(float start, float end, float val)
+ {
+ val /= .5f;
+ end -= start;
+ if (val < 1) return -end / 2 * (Mathf.Sqrt(1 - val * val) - 1) + start;
+ val -= 2;
+ return end / 2 * (Mathf.Sqrt(1 - val * val) + 1) + start;
+ }
+
+ private static float easeInBounce(float start, float end, float val)
+ {
+ end -= start;
+ float d = 1f;
+ return end - easeOutBounce(0, end, d - val) + start;
+ }
+
+ private static float easeOutBounce(float start, float end, float val)
+ {
+ val /= 1f;
+ end -= start;
+ if (val < (1 / 2.75f))
+ {
+ return end * (7.5625f * val * val) + start;
+ }
+ else if (val < (2 / 2.75f))
+ {
+ val -= (1.5f / 2.75f);
+ return end * (7.5625f * (val) * val + .75f) + start;
+ }
+ else if (val < (2.5 / 2.75))
+ {
+ val -= (2.25f / 2.75f);
+ return end * (7.5625f * (val) * val + .9375f) + start;
+ }
+ else
+ {
+ val -= (2.625f / 2.75f);
+ return end * (7.5625f * (val) * val + .984375f) + start;
+ }
+ }
+
+ private static float easeInOutBounce(float start, float end, float val)
+ {
+ end -= start;
+ float d = 1f;
+ if (val < d / 2) return easeInBounce(0, end, val * 2) * 0.5f + start;
+ else return easeOutBounce(0, end, val * 2 - d) * 0.5f + end * 0.5f + start;
+ }
+
+ private static float easeInBack(float start, float end, float val)
+ {
+ end -= start;
+ val /= 1;
+ float s = 1.70158f;
+ return end * (val) * val * ((s + 1) * val - s) + start;
+ }
+
+ private static float easeOutBack(float start, float end, float val)
+ {
+ float s = 1.70158f;
+ end -= start;
+ val = (val / 1) - 1;
+ return end * ((val) * val * ((s + 1) * val + s) + 1) + start;
+ }
+
+ private static float easeInOutBack(float start, float end, float val)
+ {
+ float s = 1.70158f;
+ end -= start;
+ val /= .5f;
+ if ((val) < 1)
+ {
+ s *= (1.525f);
+ return end / 2 * (val * val * (((s) + 1) * val - s)) + start;
+ }
+ val -= 2;
+ s *= (1.525f);
+ return end / 2 * ((val) * val * (((s) + 1) * val + s) + 2) + start;
+ }
+
+ private static float easeInElastic(float start, float end, float val)
+ {
+ end -= start;
+
+ float d = 1f;
+ float p = d * .3f;
+ float s = 0;
+ float a = 0;
+
+ if (val == 0) return start;
+ val = val / d;
+ if (val == 1) return start + end;
+
+ if (a == 0f || a < Mathf.Abs(end))
+ {
+ a = end;
+ s = p / 4;
+ }
+ else
+ {
+ s = p / (2 * Mathf.PI) * Mathf.Asin(end / a);
+ }
+ val = val - 1;
+ return -(a * Mathf.Pow(2, 10 * val) * Mathf.Sin((val * d - s) * (2 * Mathf.PI) / p)) + start;
+ }
+
+ private static float easeOutElastic(float start, float end, float val)
+ {
+ end -= start;
+
+ float d = 1f;
+ float p = d * .3f;
+ float s = 0;
+ float a = 0;
+
+ if (val == 0) return start;
+
+ val = val / d;
+ if (val == 1) return start + end;
+
+ if (a == 0f || a < Mathf.Abs(end))
+ {
+ a = end;
+ s = p / 4;
+ }
+ else
+ {
+ s = p / (2 * Mathf.PI) * Mathf.Asin(end / a);
+ }
+
+ return (a * Mathf.Pow(2, -10 * val) * Mathf.Sin((val * d - s) * (2 * Mathf.PI) / p) + end + start);
+ }
+
+ private static float easeInOutElastic(float start, float end, float val)
+ {
+ end -= start;
+
+ float d = 1f;
+ float p = d * .3f;
+ float s = 0;
+ float a = 0;
+
+ if (val == 0) return start;
+
+ val = val / (d / 2);
+ if (val == 2) return start + end;
+
+ if (a == 0f || a < Mathf.Abs(end))
+ {
+ a = end;
+ s = p / 4;
+ }
+ else
+ {
+ s = p / (2 * Mathf.PI) * Mathf.Asin(end / a);
+ }
+
+ if (val < 1)
+ {
+ val = val - 1;
+ return -0.5f * (a * Mathf.Pow(2, 10 * val) * Mathf.Sin((val * d - s) * (2 * Mathf.PI) / p)) + start;
+ }
+ val = val - 1;
+ return a * Mathf.Pow(2, -10 * val) * Mathf.Sin((val * d - s) * (2 * Mathf.PI) / p) * 0.5f + end + start;
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Main/Component/UI/EnhancedScroller/EnhancedScroller.cs.meta b/Main/Component/UI/EnhancedScroller/EnhancedScroller.cs.meta
new file mode 100644
index 0000000..f0884b6
--- /dev/null
+++ b/Main/Component/UI/EnhancedScroller/EnhancedScroller.cs.meta
@@ -0,0 +1,25 @@
+fileFormatVersion: 2
+guid: 9c1b74f910281224a8cae6d8e4fc1f43
+labels:
+- Data
+- Inventory
+- Cells
+- Cell
+- Reuse
+- UI
+- ScrollRect
+- Scroller
+- Virtualize
+- Recycle
+- Scroll
+- List
+timeCreated: 1435585470
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Main/Component/UI/EnhancedScroller/EnhancedScrollerCellView.cs b/Main/Component/UI/EnhancedScroller/EnhancedScrollerCellView.cs
new file mode 100644
index 0000000..2e99af9
--- /dev/null
+++ b/Main/Component/UI/EnhancedScroller/EnhancedScrollerCellView.cs
@@ -0,0 +1,53 @@
+锘縰sing UnityEngine;
+using System;
+using System.Collections;
+
+namespace EnhancedUI.EnhancedScroller
+{
+ /// <summary>
+ /// This is the base class that all cell views should derive from
+ /// </summary>
+ public class EnhancedScrollerCellView : WidgetBehavior
+ {
+ /// <summary>
+ /// The cellIdentifier is a unique string that allows the scroller
+ /// to handle different types of cells in a single list. Each type
+ /// of cell should have its own identifier
+ /// </summary>
+ public string cellIdentifier; //褰撳瓨鍦ㄤ笉鍚宲refab鐨勬椂鍊欙紝灏卞彲浠ョ敤杩欎釜identifier鏉ュ尯鍒�
+
+ /// <summary>
+ /// The cell index of the cell view
+ /// This will differ from the dataIndex if the list is looping
+ /// </summary>
+ [NonSerialized]
+ public int cellIndex;//_activeCellViews涓殑绱㈠紩
+
+ [NonSerialized]
+ public int index = -1;//_activeCellViews涓殑绱㈠紩
+
+ /// <summary>
+ /// The data index of the cell view
+ /// </summary>
+ [NonSerialized]
+ public int dataIndex;//闈炲惊鐜ā寮忎笅鍜宑ellIndex鐩稿悓锛屽惊鐜ā寮忎笅涓哄綋鍓嶅惊鐜殑瀛愮墿浣撶殑绱㈠紩
+
+ /// <summary>
+ /// Whether the cell is active or recycled
+ /// </summary>
+ [NonSerialized]
+ public bool active;
+
+ /// <summary>
+ /// This method is called by the scroller when the RefreshActiveCellViews is called on the scroller
+ /// You can override it to update your cell's view UID
+ /// </summary>
+ public virtual void RefreshCellView() { }//褰撲富鍔ㄨ皟鐢‥nhancedScrller绫讳腑RefreshActiveCellViews()鏂规硶鏃讹紝浼氶亶鍘嗗綋鍓嶅浜嶢ctive鐘舵�佺殑CellVeiw锛屽苟璋冪敤瀹冧滑閲嶅啓鐨勮繖涓柟娉�
+ //杩欎釜鏂规硶鍙互鐢ㄤ簬涓诲姩鍒锋柊褰撳墠澶勪簬Active鐘舵�佺殑CellVeiw
+
+ protected virtual void Awake()
+ {
+ InitWidgts();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Main/Component/UI/EnhancedScroller/EnhancedScrollerCellView.cs.meta b/Main/Component/UI/EnhancedScroller/EnhancedScrollerCellView.cs.meta
new file mode 100644
index 0000000..323996a
--- /dev/null
+++ b/Main/Component/UI/EnhancedScroller/EnhancedScrollerCellView.cs.meta
@@ -0,0 +1,25 @@
+fileFormatVersion: 2
+guid: 1f75717e94199704f82f26fcf6953e84
+labels:
+- Data
+- Inventory
+- Cells
+- Cell
+- Reuse
+- UI
+- ScrollRect
+- Scroller
+- Virtualize
+- Recycle
+- Scroll
+- List
+timeCreated: 1435585579
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Main/Component/UI/EnhancedScroller/IEnhancedScrollerDelegate.cs b/Main/Component/UI/EnhancedScroller/IEnhancedScrollerDelegate.cs
new file mode 100644
index 0000000..b82ac3f
--- /dev/null
+++ b/Main/Component/UI/EnhancedScroller/IEnhancedScrollerDelegate.cs
@@ -0,0 +1,53 @@
+锘縰sing UnityEngine;
+using System.Collections;
+
+namespace EnhancedUI.EnhancedScroller
+{
+ /// <summary>
+ /// All scripts that handle the scroller's callbacks should inherit from this interface
+ /// </summary>
+ public interface IEnhancedScrollerDelegate
+ {
+ /// <summary>
+ /// Gets the number of cells in a list of data
+ /// </summary>
+ /// <param name="scroller"></param>
+ /// <returns></returns>
+ int GetNumberOfCells(EnhancedScroller scroller);//寰楀埌Scroll閲岄潰CellVeiw鐨勬�绘暟鐩�
+
+ /// <summary>
+ /// Gets the size of a cell view given the index of the data set.
+ /// This allows you to have different sized cells
+ /// </summary>
+ /// <param name="scroller"></param>
+ /// <param name="dataIndex"></param>
+ /// <returns></returns>
+ float GetCellViewSize(EnhancedScroller scroller, int dataIndex);//寰楀埌鏌愪釜dataIndex鐨剆ize锛堝洜涓烘湁鍙兘浼氬瓨鍦ㄤ笉鍚岀殑CellVeiw锛�
+
+ /// <summary>
+ /// Gets the cell view that should be used for the data index. Your implementation
+ /// of this function should request a new cell from the scroller so that it can
+ /// properly recycle old cells.
+ /// </summary>
+ /// <param name="scroller"></param>
+ /// <param name="dataIndex"></param>
+ /// <param name="cellIndex"></param>
+ /// <returns></returns>
+ EnhancedScrollerCellView GetCellView(EnhancedScroller scroller, int dataIndex, int cellIndex);
+ /*
+ * 鐢ㄤ簬寰楀埌锛堟垨浠庡惊鐜泦鍚堜腑鍙栵紝鎴栧疄渚嬪寲锛変竴涓狢ellView骞跺彇鍏禖ellView瀵硅薄
+ 娉ㄦ剰杩欓噷杩斿洖鐨勬槸CellView鐨勭埗绫诲瀷锛孋ellVeiw鏄鑷繁鏉ュ啓鐨�,杩欐牱灏卞彲浠ラ�氳繃閲嶅啓鐖剁被鐨勮櫄鏂规硶瀹炵幇澶氭��
+ */
+
+
+ /*瑕佹兂浣跨敤杩欎釜鎻掍欢锛岄渶瑕佹垜浠坊鍔犱袱涓被锛�
+ * 1锛変竴涓被缁ф壙鑷狤nHancedScrollerCellView锛岀敤浜庝繚瀛樺崟涓狢ellView鐨勭浉鍏充俊鎭�
+ * 2锛夊彟涓�涓被瀹炵幇杩欎釜鎺ュ彛锛岀敤浜庢帶鍒舵暣涓猄croll锛屽苟鎻愪緵缁欏鐣屼竴浜涚浉鍏充俊鎭紙鎬荤殑CellView鏁扮洰锛屾瘡涓狢ellView鐨剆ize绛夛級
+ * 鍏朵腑锛孏etCellView()鏂规硶鍦ㄥ疄鐜扮殑鏃跺�欑洿鎺ヨ皟鐢� EnhancedScroller绫讳腑鐨凣etCellView锛堬級鏂规硶鏉ヨ繘琛屽疄鐜板氨鍙互浜�
+ * 杩欎袱涓被涔熷彲鏍规嵁鑷繁鐨勯渶瑕佽繘琛屾墿灞�
+ */
+
+
+ void OnRebuildComplete();
+ }
+}
\ No newline at end of file
diff --git a/Main/Component/UI/EnhancedScroller/IEnhancedScrollerDelegate.cs.meta b/Main/Component/UI/EnhancedScroller/IEnhancedScrollerDelegate.cs.meta
new file mode 100644
index 0000000..d8b3d83
--- /dev/null
+++ b/Main/Component/UI/EnhancedScroller/IEnhancedScrollerDelegate.cs.meta
@@ -0,0 +1,25 @@
+fileFormatVersion: 2
+guid: 7701b31137fe72d47b256054738fd57d
+labels:
+- Data
+- Inventory
+- Cells
+- Cell
+- Reuse
+- UI
+- ScrollRect
+- Scroller
+- Virtualize
+- Recycle
+- Scroll
+- List
+timeCreated: 1435585741
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Main/Component/UI/EnhancedScroller/SmallList.cs b/Main/Component/UI/EnhancedScroller/SmallList.cs
new file mode 100644
index 0000000..b681c5b
--- /dev/null
+++ b/Main/Component/UI/EnhancedScroller/SmallList.cs
@@ -0,0 +1,219 @@
+锘縰sing UnityEngine;
+using System.Collections.Generic;
+
+namespace EnhancedUI
+{
+ /// <summary>
+ /// This is a super light implementation of an array that
+ /// behaves like a list, automatically allocating new memory
+ /// when needed, but not releasing it to garbage collection.
+ /// </summary>
+ /// <typeparam name="T">The type of the list</typeparam>
+ public class SmallList<T>
+ {
+ /// <summary>
+ /// internal storage of list data
+ /// </summary>
+ public T[] data;
+
+ /// <summary>
+ /// The number of elements in the list
+ /// </summary>
+ public int Count = 0;
+
+ /// <summary>
+ /// Indexed access to the list items
+ /// </summary>
+ /// <param name="i"></param>
+ /// <returns></returns>
+ public T this[int i]
+ {
+ get { return data[i]; }
+ set { data[i] = value; }
+ }
+
+ /// <summary>
+ /// Resizes the array when more memory is needed.
+ /// </summary>
+ private void ResizeArray()
+ {
+ T[] newData;
+
+ if (data != null)
+ newData = new T[Mathf.Max(data.Length << 1, 64)];
+ else
+ newData = new T[64];
+
+ if (data != null && Count > 0)
+ data.CopyTo(newData, 0);
+
+ data = newData;
+ }
+
+ /// <summary>
+ /// Instead of releasing the memory to garbage collection,
+ /// the list size is set back to zero
+ /// </summary>
+ public void Clear()
+ {
+ Count = 0;
+ }
+
+ /// <summary>
+ /// Returns the first element of the list
+ /// </summary>
+ /// <returns></returns>
+ public T First()
+ {
+ if (data == null || Count == 0) return default(T);
+ return data[0];
+ }
+
+ /// <summary>
+ /// Returns the last element of the list
+ /// </summary>
+ /// <returns></returns>
+ public T Last()
+ {
+ if (data == null || Count == 0) return default(T);
+ return data[Count - 1];
+ }
+
+ /// <summary>
+ /// Adds a new element to the array, creating more
+ /// memory if necessary
+ /// </summary>
+ /// <param name="item"></param>
+ public void Add(T item)
+ {
+ if (data == null || Count == data.Length)
+ ResizeArray();
+
+ data[Count] = item;
+ Count++;
+ }
+
+ /// <summary>
+ /// Adds a new element to the start of the array, creating more
+ /// memory if necessary
+ /// </summary>
+ /// <param name="item"></param>
+ public void AddStart(T item)
+ {
+ Insert(item, 0);
+ }
+
+ /// <summary>
+ /// Inserts a new element to the array at the index specified, creating more
+ /// memory if necessary
+ /// </summary>
+ /// <param name="item"></param>
+ public void Insert(T item, int index)
+ {
+ if (data == null || Count == data.Length)
+ ResizeArray();
+
+ for (var i = Count; i > index; i--)
+ {
+ data[i] = data[i - 1];
+ }
+
+ data[index] = item;
+ Count++;
+ }
+
+ /// <summary>
+ /// Removes an item from the start of the data
+ /// </summary>
+ /// <returns></returns>
+ public T RemoveStart()
+ {
+ return RemoveAt(0);
+ }
+
+ /// <summary>
+ /// Removes an item from the index of the data
+ /// </summary>
+ /// <returns></returns>
+ public T RemoveAt(int index)
+ {
+ if (data != null && Count != 0)
+ {
+ T val = data[index];
+
+ for (var i = index; i < Count - 1; i++)
+ {
+ data[i] = data[i + 1];
+ }
+
+ Count--;
+ data[Count] = default(T);
+ return val;
+ }
+ else
+ {
+ return default(T);
+ }
+ }
+
+ /// <summary>
+ /// Removes an item from the data
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public T Remove(T item)
+ {
+ if (data != null && Count != 0)
+ {
+ for (var i = 0; i < Count; i++)
+ {
+ if (data[i].Equals(item))
+ {
+ return RemoveAt(i);
+ }
+ }
+ }
+
+ return default(T);
+ }
+
+ /// <summary>
+ /// Removes an item from the end of the data
+ /// </summary>
+ /// <returns></returns>
+ public T RemoveEnd()
+ {
+ if (data != null && Count != 0)
+ {
+ Count--;
+ T val = data[Count];
+ data[Count] = default(T);
+
+ return val;
+ }
+ else
+ {
+ return default(T);
+ }
+ }
+
+ /// <summary>
+ /// Determines if the data contains the item
+ /// </summary>
+ /// <param name="item">The item to compare</param>
+ /// <returns>True if the item exists in teh data</returns>
+ public bool Contains(T item)
+ {
+ if (data == null)
+ return false;
+
+ for (var i = 0; i < Count; i++)
+ {
+ if (data[i].Equals(item))
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Main/Component/UI/EnhancedScroller/SmallList.cs.meta b/Main/Component/UI/EnhancedScroller/SmallList.cs.meta
new file mode 100644
index 0000000..05a4a0f
--- /dev/null
+++ b/Main/Component/UI/EnhancedScroller/SmallList.cs.meta
@@ -0,0 +1,25 @@
+fileFormatVersion: 2
+guid: aab29d68fb4a95d49bca25f359d8f076
+labels:
+- Data
+- Inventory
+- Cells
+- Cell
+- Reuse
+- UI
+- ScrollRect
+- Scroller
+- Virtualize
+- Recycle
+- Scroll
+- List
+timeCreated: 1435585634
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Main/System/Skill.meta b/Main/System/Skill.meta
new file mode 100644
index 0000000..3d56c61
--- /dev/null
+++ b/Main/System/Skill.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: c1ae185223108c54388b2570cb6b4758
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Main/System/Skill/CellView.cs b/Main/System/Skill/CellView.cs
new file mode 100644
index 0000000..1e28ea4
--- /dev/null
+++ b/Main/System/Skill/CellView.cs
@@ -0,0 +1,106 @@
+锘縰sing System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using EnhancedUI.EnhancedScroller;
+using UnityEngine.UI;
+using System;
+
+public class CellView : EnhancedScrollerCellView
+{
+ Button m_btn;
+
+ public Action<CellView> OnClick;
+
+ public ScrollerDataType type;
+
+ public float height = 100;
+
+ public CellInfo? info;
+
+ public ScrollerController controller { get; private set; }
+
+ private ScrollerUI scrollerUI;
+
+ public ScrollerUI diplayCell
+ {
+ get
+ {
+ if (scrollerUI == null)
+ {
+ scrollerUI = GetComponent<ScrollerUI>();
+ }
+ return scrollerUI;
+ }
+ }
+
+
+ private void Start()
+ {
+ m_btn = GetComponent<Button>();
+ if (m_btn != null)
+ {
+ m_btn.onClick.AddListener(OnBtnClick);
+ }
+ }
+
+ public void SetData(ScrollerData data, ScrollerDataType type, ScrollerController controller)
+ {
+ index = data.index;
+ this.type = type;
+ this.controller = controller;
+ }
+
+ void OnBtnClick()
+ {
+ if (OnClick != null)
+ {
+ OnClick(this);
+ }
+ }
+
+ public override void RefreshCellView()
+ {
+ if (controller != null)
+ {
+ controller.OnRefreshCellActive(this);
+ }
+ RefreshUI();
+ }
+
+ public void RefreshUI()
+ {
+ if (diplayCell != null)
+ {
+ diplayCell.Refresh(this);
+ }
+ }
+}
+
+public struct CellInfo
+{
+ public int infoInt1;
+ public int infoInt2;
+ public int infoInt3;
+ public string infoStr1;
+
+ public CellInfo(int infoInt1, int infoInt2, string infoStr1)
+ {
+ this.infoInt1 = infoInt1;
+ this.infoInt2 = infoInt2;
+ this.infoStr1 = infoStr1;
+ this.infoInt3 = 0;
+ }
+
+ public void SetInfo(int _val)
+ {
+ infoInt3 = _val;
+ }
+
+ public static CellInfo Default
+ {
+ get
+ {
+ return new CellInfo(0, 0, string.Empty);
+ }
+ }
+}
diff --git a/Main/System/Skill/CellView.cs.meta b/Main/System/Skill/CellView.cs.meta
new file mode 100644
index 0000000..2965484
--- /dev/null
+++ b/Main/System/Skill/CellView.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: b1a0224d44a749a47ae59084c72f4ddc
+timeCreated: 1501126153
+licenseType: Free
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Main/System/Skill/ScrollerController.cs b/Main/System/Skill/ScrollerController.cs
new file mode 100644
index 0000000..e5f466c
--- /dev/null
+++ b/Main/System/Skill/ScrollerController.cs
@@ -0,0 +1,622 @@
+锘縰sing System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using EnhancedUI.EnhancedScroller;
+using System;
+using UnityEngine.UI;
+
+public enum EnhanceLockType
+{
+ None,
+ LockHorizonRight,
+ LockHorizonLeft,
+ LockVerticalTop,
+ LockVerticalBottom,
+ KeepHorizon,
+ KeepVertical,
+ KeepVertical2,
+}
+public class ScrollerController : MonoBehaviour, IEnhancedScrollerDelegate {
+
+ private List<ScrollerData> _data = new List<ScrollerData>();
+ public delegate void OnRefreshCellDelegate(ScrollerDataType type, CellView cell);
+ public event OnRefreshCellDelegate OnRefreshCell;
+
+ public delegate bool OnDynamicCell(ScrollerDataType type,int index,out float height);
+ public event OnDynamicCell OnGetDynamicSize;
+
+ public event Action OnRefreshCompleteEvent;
+
+ public event Action<Vector2> onValueChange;
+
+
+ public EnhancedScrollerCellView GetCellView(EnhancedScroller scroller, int dataIndex, int cellIndex)
+ {
+ CellView cell = GetCellView(scroller, dataIndex);
+ if (!cell.gameObject.activeSelf) cell.SetActive(true);
+ cell.SetData(_data[dataIndex], _data[dataIndex].m_ScrollerType,this);
+ if (_data[dataIndex].OnClick != null) {
+ cell.OnClick = _data[dataIndex].OnClick;
+ }
+ cell.info = _data[dataIndex].info;
+ if (OnRefreshCell != null) {
+ OnRefreshCell(_data[dataIndex].m_ScrollerType, cell);
+ }
+ cell.RefreshUI();
+ return cell;
+ }
+
+ private CellView GetCellView(EnhancedScroller scroller, int dataIndex)
+ {
+ CellView cell = null;
+ switch (_data[dataIndex].m_ScrollerType) {
+ case ScrollerDataType.Header:
+ cell = scroller.GetCellView(m_CellHeaderPrefab) as CellView;
+ break;
+ case ScrollerDataType.Normal:
+ cell = scroller.GetCellView(m_CellNomalPrefab) as CellView;
+ break;
+ case ScrollerDataType.Tail:
+ cell = scroller.GetCellView(m_CellTailPrefab) as CellView;
+ break;
+ case ScrollerDataType.Extra1:
+ cell = scroller.GetCellView(m_CellExtraPrefab1) as CellView;
+ break;
+ case ScrollerDataType.Extra2:
+ cell = scroller.GetCellView(m_CellExtraPrefab2) as CellView;
+ break;
+ case ScrollerDataType.Extra3:
+ cell = scroller.GetCellView(m_CellExtraPrefab3) as CellView;
+ break;
+ }
+ return cell;
+ }
+
+ public float GetCellViewSize(EnhancedScroller scroller, int dataIndex)
+ {
+ if (OnGetDynamicSize != null) {
+ float height = 0;
+ if (OnGetDynamicSize(_data[dataIndex].m_ScrollerType, _data[dataIndex].index,out height)) {
+ return height;
+ }
+ }
+ switch (_data[dataIndex].m_ScrollerType) {
+ case ScrollerDataType.Header:
+ return m_CellHeaderPrefab.height;
+ case ScrollerDataType.Normal:
+ return m_CellNomalPrefab.height;
+ case ScrollerDataType.Tail:
+ return m_CellTailPrefab.height;
+ case ScrollerDataType.Extra1:
+ return m_CellExtraPrefab1.height;
+ case ScrollerDataType.Extra2:
+ return m_CellExtraPrefab2.height;
+ case ScrollerDataType.Extra3:
+ return m_CellExtraPrefab3.height;
+ }
+ return 80;
+ }
+
+ public void OnRefreshCellActive(CellView cell)
+ {
+ if (OnRefreshCell != null) {
+ OnRefreshCell(cell.type, cell);
+ }
+ }
+
+ public int GetNumberOfCells(EnhancedScroller scroller)
+ {
+ return _data.Count;
+ }
+
+ public EnhancedScroller m_Scorller;
+ private ScrollRect m_ScrollRect;
+ public ScrollRect mScrollRect {
+ get {
+ if (m_ScrollRect == null)
+ m_ScrollRect = m_Scorller.GetComponent<ScrollRect>();
+ return m_ScrollRect;
+ }
+ }
+ public CellView m_CellHeaderPrefab;
+ public CellView m_CellNomalPrefab;
+ public CellView m_CellTailPrefab;
+ public CellView m_CellExtraPrefab1;
+ public CellView m_CellExtraPrefab2;
+ public CellView m_CellExtraPrefab3;
+ public int maxCellCnt = 0;
+ public bool fakeMiddleCenter = false; //鏄惁闇�瑕佸亣灞呬腑, 灞呬腑鏃跺綋cell涓暟灏� 灏哄灏忎簬鏈�澶у昂瀵告椂 涓嶅彲婊戝姩; 鍙湁header绫诲瀷鏃舵墠鍑嗙‘
+ int jiaMiddleWithMaxSize = 0; //鍋囧眳涓殑鏈�澶у昂瀵革紝鑷姩璁句负棰勫埗浣撻噷鐨勫垵濮嬪昂瀵�
+
+ public bool horizontal = false;
+ public bool vertical = false;
+ private bool inited = false;
+ private int cacheJump = -1;
+ private void Awake()
+ {
+ m_Scorller.Delegate = this;
+ horizontal = mScrollRect.horizontal;
+ vertical = mScrollRect.vertical;
+
+ mScrollRect.onValueChanged.AddListener(OnValueChangle);
+
+ inited = m_Scorller.inited;
+ m_Scorller.OnFirstLoadAllEvent += OnFirstLoadAllEvent;
+ if (m_Scorller.OnCompLoad == null && !m_Scorller.inited)
+ {
+ m_Scorller.OnCompLoad = OnCompLoad;
+ }
+ HideDefaultCell();
+ }
+
+ private void OnValueChangle(Vector2 delta)
+ {
+ if (onValueChange != null)
+ {
+ onValueChange(delta);
+ }
+ }
+
+ private void OnFirstLoadAllEvent()
+ {
+ if (cacheJump != -1)
+ {
+ JumpIndex(cacheJump);
+ }
+ }
+
+ private void HideDefaultCell()
+ {
+ HideDefaultCell(m_CellHeaderPrefab);
+ HideDefaultCell(m_CellNomalPrefab);
+ HideDefaultCell(m_CellTailPrefab);
+ HideDefaultCell(m_CellExtraPrefab1);
+ HideDefaultCell(m_CellExtraPrefab2);
+ HideDefaultCell(m_CellExtraPrefab3);
+ }
+
+ private void HideDefaultCell(CellView _cell)
+ {
+ if (_cell != null)
+ {
+ _cell.SetActive(false);
+ }
+ }
+
+ List<CellView> list = new List<CellView>();
+
+ private void OnCompLoad()
+ {
+ inited = true;
+ if (_data.Count > 0)
+ {
+ Restart();
+ }
+ }
+
+ public void Refresh()
+ {
+ inited = m_Scorller.inited;
+ if (m_Scorller.OnCompLoad == null && !m_Scorller.inited)
+ {
+ m_Scorller.OnCompLoad = OnCompLoad;
+ }
+ _data.Clear();
+
+ if (!inited)
+ {
+ return;
+ }
+
+ //鍋囧眳涓仮澶嶅昂瀵�
+ if (fakeMiddleCenter && jiaMiddleWithMaxSize != 0)
+ {
+ var rect = (transform as RectTransform);
+ if (horizontal)
+ {
+ rect.sizeDelta = rect.sizeDelta.SetX(jiaMiddleWithMaxSize);
+ }
+ else if (vertical)
+ {
+ rect.sizeDelta = rect.sizeDelta.SetY(jiaMiddleWithMaxSize);
+ }
+ }
+
+
+ if (m_Scorller.LayoutGroup != null)
+ {
+ m_Scorller.LayoutGroup.spacing = m_Scorller.spacing;
+ }
+
+ lastScrollPos = horizontal ? mScrollRect.horizontalNormalizedPosition : mScrollRect.verticalNormalizedPosition;
+ lastContentSize = m_Scorller._ScrollSize;
+
+ mScrollRect.verticalNormalizedPosition = 1;
+ mScrollRect.horizontalNormalizedPosition = 0;
+
+ lastScrollPos = Mathf.Clamp01(lastScrollPos);
+
+ }
+
+ public CellView GetActiveCellView(int _index)
+ {
+ if (m_Scorller == null)
+ {
+ return null;
+ }
+ var _cellView = m_Scorller.GetActiveCellView(_index);
+ if (_cellView != null)
+ {
+ return _cellView as CellView;
+ }
+ return null;
+ }
+
+ public CellView GetActiveCellView(int _index, ScrollerDataType type)
+ {
+ if (m_Scorller == null)
+ {
+ return null;
+ }
+ var views = m_Scorller.GetActiveCellViews();
+ for (int i = 0; i < views.Count; i++)
+ {
+ var _cellView = views[i] as CellView;
+ if (views[i].index == _index && _cellView.type == type)
+ {
+ return _cellView;
+ }
+ }
+ return null;
+ }
+
+ public List<CellView> GetActiveCellViews()
+ {
+ if (m_Scorller == null)
+ {
+ return null;
+ }
+ var views = m_Scorller.GetActiveCellViews();
+ List<CellView> list = new List<CellView>();
+ for (int i = 0; i < views.Count; i++)
+ {
+ var _cellView = views[i] as CellView;
+ list.Add(_cellView);
+ }
+ return list;
+ }
+
+ public void AddCell(ScrollerDataType type, int index, Action<CellView> action = null, CellInfo? info = null)
+ {
+ ScrollerData data = null;
+ switch (type) {
+ case ScrollerDataType.Header:
+ data = new ScrollerHeaderData(index, action);
+ break;
+ case ScrollerDataType.Normal:
+ data = new ScrollerNormalData(index, action);
+ break;
+ case ScrollerDataType.Tail:
+ data = new ScrollerTailData(index, action);
+ break;
+ case ScrollerDataType.Extra1:
+ case ScrollerDataType.Extra2:
+ case ScrollerDataType.Extra3:
+ data = new ScrollerExtraData(index, type, action);
+ break;
+ }
+ if (data != null) {
+ data.info = info;
+ _data.Add(data);
+ }
+ }
+
+ public void AddCell(ScrollerDataType type, int index, CellInfo info)
+ {
+ ScrollerData data = null;
+ switch (type) {
+ case ScrollerDataType.Header:
+ data = new ScrollerHeaderData(index);
+ break;
+ case ScrollerDataType.Normal:
+ data = new ScrollerNormalData(index);
+ break;
+ case ScrollerDataType.Tail:
+ data = new ScrollerTailData(index);
+ break;
+ case ScrollerDataType.Extra1:
+ case ScrollerDataType.Extra2:
+ case ScrollerDataType.Extra3:
+ data = new ScrollerExtraData(index, type);
+ break;
+ }
+ if (data != null) {
+ data.info = info;
+ _data.Add(data);
+ }
+ }
+
+ public void OnRefreshAdd()
+ {
+ Restart();
+ }
+
+ public void Restart()
+ {
+ if (!inited) return;
+
+
+ m_Scorller.ReloadData();
+
+ if (fakeMiddleCenter && _data.Count <= maxCellCnt)
+ {
+ //鍙湁璁剧疆header鏃讹紝杩涜鍋囧眳涓鐞嗘墠鑳借揪鍒版晥鏋�
+ if (jiaMiddleWithMaxSize == 0)
+ {
+ jiaMiddleWithMaxSize = (int)m_Scorller.ScrollRectSize;
+ }
+
+
+ var rect = (transform as RectTransform);
+ if (horizontal)
+ {
+
+ rect.sizeDelta = rect.sizeDelta.SetX(Math.Min(jiaMiddleWithMaxSize, (m_CellHeaderPrefab.height + m_Scorller.spacing) * _data.Count - m_Scorller.spacing));
+ }
+ else if (vertical)
+ {
+ rect.sizeDelta = rect.sizeDelta.SetY(Math.Min(jiaMiddleWithMaxSize, (m_CellHeaderPrefab.height + m_Scorller.spacing) * _data.Count - m_Scorller.spacing));
+ }
+ if (rect.sizeDelta.x < jiaMiddleWithMaxSize)
+ {
+ mScrollRect.horizontal = false;
+ mScrollRect.vertical = false;
+ }
+ else
+ {
+ mScrollRect.horizontal = horizontal;
+ mScrollRect.vertical = vertical;
+ }
+ }
+ else if (maxCellCnt != 0 && _data.Count <= maxCellCnt)
+ {
+ mScrollRect.horizontal = false;
+ mScrollRect.vertical = false;
+ }
+ else
+ {
+ mScrollRect.horizontal = horizontal;
+ mScrollRect.vertical = vertical;
+ }
+
+ ResetScrollPos();
+
+ lastDataCnt = _data.Count;
+ }
+
+ public void JumpIndex(int index)
+ {
+ if (!inited)
+ {
+ cacheJump = index;
+ return;
+ }
+ if ((index < 0 || index >= _data.Count) && !m_Scorller.Loop)
+ {
+ return;
+ }
+ var _size = m_Scorller.GetScrollPositionForDataIndex(index, EnhancedScroller.CellViewPositionEnum.Before);
+ var _contentSize = vertical ? m_Scorller.scrollRect.content.rect.size.y : m_Scorller.scrollRect.content.rect.size.x;
+ if (_contentSize - _size < m_Scorller.ScrollRectSize)
+ {
+ _size = _contentSize - m_Scorller.ScrollRectSize;
+ }
+ m_Scorller.ScrollPosition = _size;
+ }
+
+ public void JumpIndex(int index,ref float offset)
+ {
+ if (!inited)
+ {
+ cacheJump = index;
+ return;
+ }
+ if ((index < 0 || index >= _data.Count) && !m_Scorller.Loop)
+ {
+ return;
+ }
+ var _size = m_Scorller.GetScrollPositionForDataIndex(index, EnhancedScroller.CellViewPositionEnum.Before);
+ var _contentSize = vertical ? m_Scorller.scrollRect.content.rect.size.y : m_Scorller.scrollRect.content.rect.size.x;
+ offset = 0f;
+ if (_contentSize - _size < m_Scorller.ScrollRectSize)
+ {
+ offset = _size - (_contentSize - m_Scorller.ScrollRectSize);
+ _size = _size - offset;
+ }
+ m_Scorller.ScrollPosition = _size;
+ }
+
+ public float GetCellSize(int _dataIndex)
+ {
+ if (!inited)
+ {
+ return 0;
+ }
+ return m_Scorller.GetCellSize(_dataIndex);
+ }
+
+ //婊戝姩杩囧幓
+ public void MoveToIndex(int index, float _time, EnhancedScroller.TweenType _tweenType)
+ {
+ if (!inited)
+ {
+ cacheJump = index;
+ return;
+ }
+ if ((index < 0 || index >= _data.Count) && !m_Scorller.Loop)
+ {
+ return;
+ }
+ var _size = m_Scorller.GetScrollPositionForDataIndex(index, EnhancedScroller.CellViewPositionEnum.Before);
+
+ m_Scorller.Tween(_tweenType, _time, _size);
+ }
+
+
+ public void JumpIndex(float _delta, float _time, EnhancedScroller.TweenType _tweenType)
+ {
+ if (!inited)
+ {
+ return;
+ }
+ m_Scorller.Tween(_tweenType, _time, m_Scorller.ScrollPosition + _delta);
+ }
+
+ public float GetPreScrollSize(int index)
+ {
+ float _size = 0;
+ for (int i = 0; i < _data.Count; i++) {
+ _size += GetCellViewSize(m_Scorller, i);
+ if (i >= index) break;
+ }
+ return _size;
+ }
+
+ public void RefreshSingleCellView(int _index)
+ {
+ CellView _cell;
+ if (IsDisplay(_index, out _cell))
+ {
+ _cell.RefreshCellView();
+ }
+ }
+
+ public bool IsDisplay(int index, out CellView _cell)
+ {
+ _cell = null;
+ if (m_Scorller == null)
+ {
+ return false;
+ }
+ var _base = m_Scorller.GetActiveCellView(index);
+ if (_base != null)
+ {
+ _cell = _base as CellView;
+ return true;
+ }
+ return false;
+ }
+
+ public bool IsDisplay(int index)
+ {
+ if (m_Scorller == null)
+ {
+ return false;
+ }
+ return m_Scorller.GetActiveCellView(index) != null;
+ }
+
+ public bool OutOfStartView(int index)
+ {
+ float value=m_Scorller.GetScrollPositionForCellViewIndex(index, EnhancedScroller.CellViewPositionEnum.Before);
+ if (value < m_Scorller.ScrollPosition) {
+ return true;
+ }
+ return false;
+ }
+
+ private void OnDestroy()
+ {
+ if (m_Scorller != null)
+ {
+ m_Scorller.OnFirstLoadAllEvent -= OnFirstLoadAllEvent;
+ }
+ }
+
+ public void OnRebuildComplete()
+ {
+ if (OnRefreshCompleteEvent != null)
+ {
+ OnRefreshCompleteEvent();
+ }
+ }
+
+ #region 婊氬姩瀹氫綅
+
+ private EnhanceLockType m_lockType = EnhanceLockType.None;
+
+ public EnhanceLockType lockType {
+ get { return m_lockType; }
+ set {
+ m_lockType = value;
+ }
+ }
+
+ private float lastContentSize = 0;
+
+ private int lastDataCnt = 0;
+
+ private float lastScrollPos = 0;
+
+ public void ResetScrollPos()
+ {
+ if (_data.Count == 0 || !inited)
+ {
+ return;
+ }
+ switch (lockType) {
+ case EnhanceLockType.LockHorizonRight: {
+ mScrollRect.horizontalNormalizedPosition = 1;
+ }
+ break;
+ case EnhanceLockType.LockHorizonLeft: {
+ mScrollRect.horizontalNormalizedPosition = 0;
+ }
+ break;
+ case EnhanceLockType.LockVerticalTop: {
+ mScrollRect.verticalNormalizedPosition = 1;
+ }
+ break;
+ case EnhanceLockType.LockVerticalBottom: {
+ mScrollRect.verticalNormalizedPosition = 0;
+ m_Scorller.ScrollPosition = m_Scorller._ScrollSize;
+ }
+ break;
+ case EnhanceLockType.KeepHorizon: {
+ mScrollRect.horizontalNormalizedPosition = Mathf.Clamp01(lastContentSize * lastScrollPos / m_Scorller._ScrollSize);
+ }
+ break;
+ case EnhanceLockType.KeepVertical2: {
+ if(lastContentSize == m_Scorller._ScrollSize) {
+ mScrollRect.verticalNormalizedPosition = lastScrollPos;
+ m_Scorller.ScrollPosition = (1 - mScrollRect.verticalNormalizedPosition) * m_Scorller._ScrollSize;
+ return;
+ }
+ if (lastScrollPos == 1) {
+ mScrollRect.verticalNormalizedPosition = 1;
+ }
+ mScrollRect.verticalNormalizedPosition = Mathf.Clamp01(lastContentSize * lastScrollPos / m_Scorller._ScrollSize);
+ m_Scorller.ScrollPosition = (1 - mScrollRect.verticalNormalizedPosition) * m_Scorller._ScrollSize;
+ }
+ break;
+ case EnhanceLockType.KeepVertical:
+ {
+ if (lastContentSize == m_Scorller._ScrollSize)
+ {
+ mScrollRect.verticalNormalizedPosition = lastScrollPos;
+ m_Scorller.ScrollPosition = (1 - mScrollRect.verticalNormalizedPosition) * m_Scorller._ScrollSize;
+ return;
+ }
+ if (lastScrollPos == 1)
+ {
+ mScrollRect.verticalNormalizedPosition = 1;
+ }
+ mScrollRect.verticalNormalizedPosition = Mathf.Clamp01(1 - lastContentSize * (1 - lastScrollPos) / m_Scorller._ScrollSize);
+ m_Scorller.ScrollPosition = (1 - mScrollRect.verticalNormalizedPosition) * m_Scorller._ScrollSize;
+ }
+ break;
+ }
+ }
+
+ #endregion
+}
diff --git a/Main/System/Skill/ScrollerController.cs.meta b/Main/System/Skill/ScrollerController.cs.meta
new file mode 100644
index 0000000..bd75633
--- /dev/null
+++ b/Main/System/Skill/ScrollerController.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: db8a0c384b7dd034fa327df389b01390
+timeCreated: 1501125931
+licenseType: Free
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Main/System/Skill/ScrollerData.cs b/Main/System/Skill/ScrollerData.cs
new file mode 100644
index 0000000..f3e4a0e
--- /dev/null
+++ b/Main/System/Skill/ScrollerData.cs
@@ -0,0 +1,59 @@
+锘縰sing System;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+public class ScrollerData {
+ public int index;
+ public ScrollerDataType m_ScrollerType = ScrollerDataType.Normal;
+ public ScrollerData(int index, Action<CellView> action)
+ {
+ this.index = index;
+ OnClick = action;
+ }
+
+ public CellInfo? info;
+
+ public Action<CellView> OnClick;
+}
+
+public class ScrollerHeaderData : ScrollerData
+{
+ public ScrollerHeaderData(int index, Action<CellView> action = null) :base(index, action)
+ {
+ m_ScrollerType = ScrollerDataType.Header;
+ }
+}
+
+public class ScrollerTailData : ScrollerData
+{
+ public ScrollerTailData(int index, Action<CellView> action = null) : base(index, action)
+ {
+ m_ScrollerType = ScrollerDataType.Tail;
+ }
+}
+
+public class ScrollerNormalData : ScrollerData
+{
+ public ScrollerNormalData(int index, Action<CellView> action = null) : base(index, action)
+ {
+ m_ScrollerType = ScrollerDataType.Normal;
+ }
+}
+public class ScrollerExtraData : ScrollerData
+{
+ public ScrollerExtraData(int index, ScrollerDataType type, Action<CellView> action = null) : base(index, action)
+ {
+ m_ScrollerType = type;
+ }
+}
+
+public enum ScrollerDataType
+{
+ Header,
+ Normal,
+ Tail,
+ Extra1,
+ Extra2,
+ Extra3,
+}
diff --git a/Main/System/Skill/ScrollerData.cs.meta b/Main/System/Skill/ScrollerData.cs.meta
new file mode 100644
index 0000000..57a9f9f
--- /dev/null
+++ b/Main/System/Skill/ScrollerData.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 11cfc3c4873e25c4db2a54cd2d565464
+timeCreated: 1501126064
+licenseType: Free
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Main/System/Skill/ScrollerUI.cs b/Main/System/Skill/ScrollerUI.cs
new file mode 100644
index 0000000..d561f5b
--- /dev/null
+++ b/Main/System/Skill/ScrollerUI.cs
@@ -0,0 +1,11 @@
+锘縰sing UnityEngine;
+namespace EnhancedUI.EnhancedScroller
+{
+ public abstract class ScrollerUI : MonoBehaviour
+ {
+ public ScrollerDataType type=ScrollerDataType.Header;
+
+ public abstract void Refresh(CellView cell);
+ }
+}
+
diff --git a/Main/System/Skill/ScrollerUI.cs.meta b/Main/System/Skill/ScrollerUI.cs.meta
new file mode 100644
index 0000000..f2c7a55
--- /dev/null
+++ b/Main/System/Skill/ScrollerUI.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 20a2854509a5a624ebcb26b536632821
+timeCreated: 1508552655
+licenseType: Free
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Main/System/WindowBase.meta b/Main/System/WindowBase.meta
new file mode 100644
index 0000000..ceaecae
--- /dev/null
+++ b/Main/System/WindowBase.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: ba02f3312cb5175499b8702894548057
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Main/System/WindowBase/WidgetBehavior.cs b/Main/System/WindowBase/WidgetBehavior.cs
new file mode 100644
index 0000000..35b4968
--- /dev/null
+++ b/Main/System/WindowBase/WidgetBehavior.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+
+[System.Serializable]
+public struct Widget
+{
+ public string name;
+ public GameObject gameObject;
+}
+
+
+public class WidgetBehavior : MonoBehaviour
+{
+ [HideInInspector]
+ public Widget[] widgets;
+ protected Dictionary<string, GameObject> dicWidgts;
+
+ private bool hasInitWidgets = false;
+
+ /// <summary>
+ /// 鍦ㄥ瓙绫诲悎閫傚湴鏂瑰垵濮嬪寲姝ゆ柟娉�
+ /// </summary>
+ protected void InitWidgts()
+ {
+ dicWidgts = new Dictionary<string, GameObject>();
+ foreach (var item in widgets)
+ {
+ if (dicWidgts.ContainsKey(item.name))
+ Debug.LogErrorFormat("鏈夐噸澶嶇殑鎺т欢鍚嶇О锛歿0}", item.name);
+ dicWidgts.Add(item.name, item.gameObject);
+ }
+ hasInitWidgets = true;
+ }
+
+ public T GetWidgt<T>(string name) where T: Component
+ {
+ if (!hasInitWidgets)
+ {
+ Debug.LogError("鎺т欢杩樻湭鍒濆鍖栵紒");
+ return default(T);
+ }
+ GameObject go;
+ if (dicWidgts.TryGetValue(name, out go))
+ {
+ return go.GetComponent<T>();
+ }
+ Debug.LogErrorFormat("鎵句笉鍒版帶浠讹細{0}", name);
+ return default(T);
+ }
+
+ public Component GetWidgt(string type, string name)
+ {
+ if (!hasInitWidgets)
+ {
+ Debug.LogError("鎺т欢杩樻湭鍒濆鍖栵紒");
+ return null;
+ }
+ GameObject go;
+ if (dicWidgts.TryGetValue(name, out go))
+ {
+ return go.GetComponent(type);
+ }
+ Debug.LogErrorFormat("鎵句笉鍒版帶浠讹細{0}", name);
+ return null;
+ }
+
+ public Component GetWidgt(Type type, string name)
+ {
+ if (!hasInitWidgets)
+ {
+ Debug.LogError("鎺т欢杩樻湭鍒濆鍖栵紒");
+ return null;
+ }
+ GameObject go;
+ if (dicWidgts.TryGetValue(name, out go))
+ {
+ return go.GetComponent(type);
+ }
+ Debug.LogErrorFormat("鎵句笉鍒版帶浠讹細{0}", name);
+ return null;
+ }
+
+}
\ No newline at end of file
diff --git a/Main/System/WindowBase/WidgetBehavior.cs.meta b/Main/System/WindowBase/WidgetBehavior.cs.meta
new file mode 100644
index 0000000..7fed834
--- /dev/null
+++ b/Main/System/WindowBase/WidgetBehavior.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4a829f199a150a544b7022271869a09c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
--
Gitblit v1.8.0