Files

1156 lines
39 KiB
C#
Raw Permalink Normal View History

2025-01-25 04:38:09 +08:00
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System;
namespace Thousandto.Plugins.Common
{
/// <summary>
/// ListView单列排版的滑动列表支持不等高度的自动排版
/// 示例可以参考UIServerListFormScript
/// </summary>
public class UIListView : MonoBehaviour
{
const float DURATION = 0.5f;
#region
public UIScrollView ScrollView = null;
public float LerpDuration = DURATION;
public bool Initialized = false;
public float Offset = 50f;
//默认缩放动画
public bool EnableEffect = true;
#endregion
#region
private UIPanel _panel = null;
//最初的偏移
private Vector4 _originalClipOffset = Vector4.zero;
//最初的位置
private Vector3 _originalPos = Vector3.zero;
//下方最终位置向上滑动时如果下方需要补新的item 坐标从_bottomPos开始算
private Vector3 _bottomPos = Vector3.zero;
//上方最终位置向下滑动时如果上方需要补新的item坐标从_topPos开始算
private Vector2 _topPos = Vector2.zero;
//需要移动的距离
//private Vector2 _moveAmount = Vector2.zero;
//跟节点的上一次变换后的位置
private Vector3 _lastRootPos = Vector3.zero;
private Vector2 _lastClipOffset = Vector2.zero;
//滑动窗口尺寸
private Vector2 _scrollViewSize = Vector2.zero;
private Vector2 _autoMoveDistance = Vector2.zero;
//添加新的item后transform需要移动到的目标位置
private Vector3 _rootMoveToPos = Vector3.zero;
//添加新的item后裁剪区域偏移量需要改变到的目标值
private Vector2 _rootEndClipOffset = Vector2.zero;
//边界模糊区域
private Vector2 _softClipOffset = Vector2.zero;
//ScrollView的边界
private Bounds _bounds;
private Transform _transform = null;
//在添加了新的item或者滑动区域后需要重新计算边界
private bool _calclateBounds = false;
//添加新item后自动滑动
private bool _enableSmoothMove = false;
//插值时长
private float _lerpTimer = 0;
//保存临时Item的节点
private Transform _cacheRootTrans = null;
//--------------下面几个变量用于调用Show方法刷新面板所用
//是否调用show方法显示列表
private bool _isCallShowFunc = false;
private bool _endShow = false;
//调用show时记录下沿Y坐标
private float _bottomClipPosOnShow = 0;
//显示的索引
private int _showIndex = 0;
//------------------------------------------------------
#endregion
#region
private List<ItemHolder> _showingList = new List<ItemHolder>();
private ItemHolder _itemHolder = null;
private ListItemAdapter _adapter;
//顶部的item
private ItemHolder _topItemHolder;
//底部的item
private ItemHolder _bottomItemHolder;
private int _lastIndex = 0;
//新需要展示消息
private int _newItemCount = 0;
//item间距
private float _spaceY = 10;
private int _curChannel = -1;
#endregion
#region
//当前窗口的边界
private Bounds mBounds
{
get
{
if (!_calclateBounds)
{
_calclateBounds = true;
_bounds = GetBounds(transform);
}
return _bounds;
}
}
public bool EnableSmoothMove
{
get
{
return _enableSmoothMove;
}
}
#endregion
#region Mono生命周期
void Awake()
{
_transform = transform;
ScrollView = GetComponent<UIScrollView>();
_panel = ScrollView.panel;
_scrollViewSize = ScrollView.panel.GetViewSize();
_originalClipOffset = _panel.clipOffset;
_originalPos = transform.localPosition;
if (ScrollView.panel.clipping == UIDrawCall.Clipping.SoftClip)
{
_softClipOffset.y = _panel.clipSoftness.y;
_softClipOffset.x = _panel.clipSoftness.x;
}
InitTopAndBottomPos();
//事件注册
ScrollView.onDragStarted = onDragStarted;
ScrollView.onDragFinished = onDragFinished;
ScrollView.onStoppedMoving = onStoppedMoving;
ScrollView.panel.onClipMove = onDragMove;
//自动创建保存Item的节点
GameObject cacheTempGo = new GameObject("[CacheScrollItem]");
_cacheRootTrans = cacheTempGo.transform;
_cacheRootTrans.parent = transform.parent;
Clear();
}
//void Update()
//{
//}
private void LateUpdate()
{
RefreshWhileNewItem();
if (_dragging)
{
//UnityEngine.Debug.LogError("点击了拖动直接返回不移动滑动列表!!!!!");
return;
}
//onDragMove(null);
if (!_enableSmoothMove)
{
//UnityEngine.Debug.LogError("滑动列表的SmoothMove状态是关闭的");
return;
}
_lerpTimer += Time.deltaTime / LerpDuration;
SmoothMove(_lerpTimer);
if (_lerpTimer > 1)
{
_lerpTimer = 0;
_enableSmoothMove = false;
}
}
#if UNITY_EDITOR
void OnDrawGizmos()
{
Vector4 clip = ScrollView.panel.finalClipRegion;
if (Input.mousePosition.y - _lastMousePos.y >= 0)
_dragMoveDown = false;
else
_dragMoveDown = true;
Bounds b = GetBounds(transform);
float hx = clip.z * 0.5f;
float hy = clip.w * 0.5f;
//裁剪区域的上沿Y坐标
var topClipPos = clip.y + hy;
//下沿Y坐标
var bottomClipPos = clip.y - hy;
var TopItemOutOfRegion = GetTopItemOutOfClipRegion(topClipPos);
var TopItemInView = GetTopItemInClipRegion();
var BottomItemOutOfRegion = GetBottomItemOutOfClipRegion(bottomClipPos);
var BottomItemInView = GetBottomItemInClipRegion();
Gizmos.color = Color.red;
if (TopItemOutOfRegion != null)
{
Gizmos.DrawLine(ScrollView.transform.TransformPoint(new Vector2(0, TopItemOutOfRegion.TopAndBottom.y)),
ScrollView.transform.TransformPoint((new Vector2(50 * 5, TopItemOutOfRegion.TopAndBottom.y))));
UnityEditor.Handles.Label(ScrollView.transform.TransformPoint((new Vector2(50 * 5 + 10, TopItemOutOfRegion.TopAndBottom.y))), "TopItemOutOfRegion-" + TopItemOutOfRegion.Object.name);
}
Gizmos.color = Color.green;
if (TopItemInView != null)
{
Gizmos.DrawLine(ScrollView.transform.TransformPoint(new Vector2(0, TopItemInView.TopAndBottom.x)),
ScrollView.transform.TransformPoint((new Vector2(50 * 5, TopItemInView.TopAndBottom.x))));
UnityEditor.Handles.Label(ScrollView.transform.TransformPoint((new Vector2(50 * 5 + 10, TopItemInView.TopAndBottom.x))), "TopItemInView-" + TopItemInView.Object.name);
}
Gizmos.color = Color.blue;
if (BottomItemInView != null)
{
Gizmos.DrawLine(ScrollView.transform.TransformPoint(new Vector2(0, BottomItemInView.TopAndBottom.y)),
ScrollView.transform.TransformPoint((new Vector2(50 * 5, BottomItemInView.TopAndBottom.y))));
UnityEditor.Handles.Label(ScrollView.transform.TransformPoint((new Vector2(50 * 5 + 10, BottomItemInView.TopAndBottom.y))), "BottomItemInView-" + BottomItemInView.Object.name);
}
Gizmos.color = Color.black;
if (BottomItemOutOfRegion != null)
{
Gizmos.DrawLine(ScrollView.transform.TransformPoint(new Vector2(0, BottomItemOutOfRegion.TopAndBottom.x)),
ScrollView.transform.TransformPoint((new Vector2(50 * 5, BottomItemOutOfRegion.TopAndBottom.x))));
UnityEditor.Handles.Label(ScrollView.transform.TransformPoint((new Vector2(50 * 5 + 10, BottomItemOutOfRegion.TopAndBottom.x))), "BottomItemOutOfRegion-" + BottomItemOutOfRegion.Object.name);
}
}
#endif
#endregion
#region
public List<ItemHolder> GetShowList()
{
return _showingList;
}
public void SetAdapter(ListItemAdapter adapter)
{
_adapter = adapter;
Initialized = true;
}
public void SetSpaceY(float space)
{
_spaceY = space;
}
public void SetChannel(int channel)
{
_curChannel = channel;
}
/// <summary>
/// 显示若干item直到超出可视窗
/// </summary>
/// <param name="reverse">采用倒序获取数据</param>
/// <param name="moveUp"></param>
public void Show(bool moveDown = false)
{
_isCallShowFunc = true;
_showIndex = 0;
var clip = ScrollView.panel.finalClipRegion;
float hy = clip.w * 0.5f;
//下沿Y坐标
_bottomClipPosOnShow = clip.y - hy;
//_panel.onClipMove = null;
//int dataCount = _adapter.GetCount();
//for(int i = 0; i < dataCount; ++i)
//{
// var view = _adapter.GetView(i, null);
// view.Index = i;
// if(i == 0)
// {
// _topItemHolder = view;
// }
// AddItem(view, false);
// _showingList.Add(view);
// if (_bottomClipPosOnShow - _bottomPos.y > view.Bounds.size.y + Offset)
// {
// _lastIndex = i;
// _bottomItemHolder = view;
// break;
// }
//}
if (!moveDown)
_enableSmoothMove = false;
}
public void ShowReverse(int channel = -1)
{
//这里要设置为0避免切换频道有滑动操作
ScrollView.currentMomentum = Vector2.zero;
_dragging = false;
var clipRegion = ScrollView.panel.finalClipRegion;
InitTopAndBottomPos(false);
if (channel == -1)
{
int dataCount = _adapter.GetCount();
for (int i = dataCount - 1; i >= 0; --i)
{
var view = _adapter.GetView(i, null);
view.Index = i;
if (i == dataCount - 1)
{
_bottomItemHolder = view;
}
AddItem(view, true);
_showingList.Insert(0, view);
_topItemHolder = view;
if (_topPos.y - _bottomPos.y > clipRegion.w + Offset)
{
_lastIndex = i;
break;
}
}
}
else
{
List<int> indexList = _adapter.GetIndexs(channel);
for (int i = indexList.Count -1; i >= 0; i--)
{
var view = _adapter.GetView(indexList[i], null);
view.Index = indexList[i];
if (i == indexList.Count - 1)
{
_bottomItemHolder = view;
}
AddItem(view, true);
_showingList.Insert(0, view);
_topItemHolder = view;
if (_topPos.y - _bottomPos.y > clipRegion.w + Offset)
{
_lastIndex = i;
break;
}
}
}
SmoothMove(1);
//这个脚本导致切换聊天时,如果有滑动操作,新频道内容位置显示异常
var sp = transform.GetComponent<SpringPanel>();
if (sp != null)
{
sp.target = Vector3.zero;
sp.enabled = false;
}
}
private float _addItemDeltaTime = 0;
//当有新item添加到数据源后触发需要手动调用
public bool OnAddItem()
{
if (_dragging)
return false;
//上下方如果有超出框的item存在则不添加新的item
if ((GetBottomItemOutOfClipRegion() != null/* && GetTopItemOutOfClipRegion() != null*/))
{
var topItem = GetTopItemInClipRegion();
if(topItem != null && topItem.Index != 0)
return false;
}
if(GetTopItemInClipRegion() == null)
{
ScrollView.ResetPosition();
}
//_newItemCount++;
ShowNewItem();
if (_addItemDeltaTime == 0)
_addItemDeltaTime = Time.realtimeSinceStartup;
else
{
var deltaTime = Time.realtimeSinceStartup - _addItemDeltaTime;
if (deltaTime < DURATION)
{
LerpDuration = deltaTime;
}
else
{
LerpDuration = DURATION;
}
_addItemDeltaTime = Time.realtimeSinceStartup;
}
return true;
}
public void ShowNewItem()
{
var holder = AddItemFromCacheParent(GetTopItemOutOfClipRegion(), false, GetBottomItemInClipRegion());
if (holder == null)
return;
//对新加入的item播放缩放动画
PlayScaleEffect(holder);
}
public bool RefreshWhileNewItem()
{
//每5帧刷新界面
//if (Time.frameCount % 5 != 0)
// return;
if(_isCallShowFunc)
{
if (Time.frameCount % 5 != 0)
{
return true;
}
if (_endShow)
{
_isCallShowFunc = false;
_endShow = false;
//_panel.onClipMove = onDragMove;
return true;
}
var view = _adapter.GetView(_showIndex, null);
if (view != null)
{
view.Index = _showIndex;
if (_showIndex == 0)
{
_topItemHolder = view;
}
AddItem(view, false);
_showingList.Add(view);
if (_bottomClipPosOnShow - _bottomPos.y > view.Bounds.size.y + Offset)
{
_lastIndex = _showIndex;
_bottomItemHolder = view;
_showIndex = 0;
_endShow = true;
}
else
_showIndex++;
//对新加入的item播放缩放动画
PlayScaleEffect(view);
}
else
_endShow = true;
}
else
{
if (_newItemCount > 0)
{
_newItemCount--;
ShowNewItem();
return true;
}
}
return false;
}
public ItemHolder RemoveAtIndex(int index, bool fromFirst = true, bool forceRemove = false)
{
if (_showingList.Count == 0)
return null;
ItemHolder ret = null;
if (forceRemove)
{
ret = fromFirst ? _showingList[0] : _showingList[_showingList.Count - 1];
_showingList.RemoveAt(fromFirst ? 0 : _showingList.Count - 1);
return ret;
}
if (fromFirst)
{
//从上到下、从前往后查找
for(int i = 0; i < _showingList.Count; ++i)
{
//找到指定item删除其后的item的index需要递减
if (_showingList[i].Index == index)
{
ret = _showingList[i];
_showingList.RemoveAt(i);
i--;
_topPos.y = ret.TopAndBottom.y;
}
else if (_showingList[i].Index > index)
{
_showingList[i].Index--;
}
}
if(ret != null)
{
//删除顶部item需要重新对齐
if (GetTopItemOutOfClipRegion() == null)
{
SetClipRegionMoveOffset(ret.TopAndBottom.y);
//AddItemFromCacheParent(ret, false, _showingList[_showingList.Count - 1]);
}
}
}
else
{
ret = _showingList[_showingList.Count - 1];
_showingList.RemoveAt(_showingList.Count - 1);
for(int i = _showingList.Count - 1; i >= 0; --i)
{
if(_showingList[i].Index == index)
{
ret = _showingList[i];
_showingList.RemoveAt(i);
_bottomPos.y = ret.TopAndBottom.x;
break;
}
else
_showingList[i].Index--;
}
}
return ret;
}
public void SetAfterItemPos(ItemHolder holder)
{
bool isAfter = false;
List<ItemHolder> tempList = new List<ItemHolder>();
for (int i = 0; i < _showingList.Count; i++)
{
var item = _showingList[i];
if (!isAfter)
{
if (_showingList[i] == holder)
{
isAfter = true;
}
}
else
{
tempList.Add(item);
}
}
float curSizeY = GetBounds(holder.Object).size.y;
float offsetY = curSizeY - holder.Param;
holder.Param = curSizeY;
for (int i = 0; i < tempList.Count; i++)
{
var item = tempList[i];
if (item != null)
{
item.Object.localPosition = new Vector3(item.Object.localPosition.x, item.Object.localPosition.y - offsetY, item.Object.localPosition.z);
var bounds = GetBounds(ScrollView.transform, item.Object);
item.TopAndBottom.x = bounds.max.y;
item.TopAndBottom.y = bounds.min.y;
item.Size = bounds.size;
}
}
//同步bottomPos的坐标
//_bottomPos.y
var bottomItem = _showingList[_showingList.Count - 1];
_bottomPos.y = bottomItem.TopAndBottom.y;
_bottomPos.y -= _spaceY;
}
public void Clear()
{
if (ScrollView == null) return;
_showingList.Clear();
InitTopAndBottomPos();
_enableSmoothMove = false;
_panel.clipOffset = _originalClipOffset;
transform.localPosition = _originalPos;
}
#endregion
#region
private Vector3 _lastMousePos = Vector3.zero;
private bool _dragMoveDown = true;
private bool _dragging = false;
private void onDragStarted()
{
_lastMousePos = Input.mousePosition;
_dragging = true;
//手动滑动,就关掉自动滑动
_enableSmoothMove = false;
}
private void onDragFinished()
{
}
private void onStoppedMoving()
{
_dragging = false;
}
private void onDragMove(UIPanel panel)
{
//if (!_dragging)
// return;
if (_isCallShowFunc)
return;
var mPanel = ScrollView.panel;
bool moveDown = true;
Vector4 clip = mPanel.finalClipRegion;
if (Input.mousePosition.y - _lastMousePos.y >= 0)
_dragMoveDown = false;
else
_dragMoveDown = true;
moveDown = _dragMoveDown;
Bounds b = GetBounds(transform);
float hx = clip.z * 0.5f;
float hy = clip.w * 0.5f;
//裁剪区域的上沿Y坐标
var topClipPos = clip.y + hy;
//下沿Y坐标
var bottomClipPos = clip.y - hy;
//上方在裁剪窗口内的item
var topDisplayItem = GetTopItemInClipRegion();
//下方在裁剪窗口内的item
var bottomDisplayItem = GetBottomItemInClipRegion();
//上方在裁剪窗口外的item
var topDisappearItem = GetTopItemOutOfClipRegion(topClipPos);
//下方在裁剪窗口外的item
var bottomDisappearItem = GetBottomItemOutOfClipRegion(bottomClipPos);
if(moveDown)
{
//往下滑需要补充上方的item。如果上方有滑出屏幕的item则不补充
if(topDisappearItem == null && topDisplayItem != null)
{
AddItemFromCacheParent(bottomDisappearItem, true, topDisplayItem);
}
}
else
{
//往上滑需要补充下方的item。如果下方有滑出屏幕的item则不补充
if(bottomDisappearItem == null && bottomDisplayItem != null)
{
AddItemFromCacheParent(topDisappearItem, false, bottomDisplayItem);
}
}
_lastMousePos = Input.mousePosition;
}
#endregion
#region
private void InitTopAndBottomPos(bool topLeft = true)
{
var clipRegion = ScrollView.panel.finalClipRegion;
if (topLeft)
{
//左上角
_bottomPos = new Vector2(-clipRegion.z * 0.5f, clipRegion.w * 0.5f);
}
else
{ //左下角
_bottomPos = new Vector2(-clipRegion.z * 0.5f, -clipRegion.w * 0.5f);
}
_topPos = _bottomPos;
_topPos.y += _softClipOffset.y + clipRegion.y;
//clipRegion.y = 0 的情况加上偏移7.7592f
_bottomPos.y -= _softClipOffset.y + clipRegion.y - 7.7592f;
}
private void AddItem(ItemHolder holder, bool addToTop = true)
{
//在这里设置holder非New
holder.UseNew = false;
Transform templateTrans = holder.Object;
if (templateTrans.parent != ScrollView.transform)
{
if(!templateTrans.gameObject.activeSelf)
templateTrans.gameObject.SetActive(true);
templateTrans.parent = ScrollView.transform;
Core.Base.UnityUtils.ResetTransform(templateTrans.gameObject);
}
templateTrans.name = "" + holder.Index;
//var itemTrans = templateTrans;
Bounds bounds = GetBounds(templateTrans);
//设置item的坐标
SetPosition(templateTrans, bounds, addToTop);
bounds = GetBounds(ScrollView.transform, templateTrans);
holder.TopAndBottom.x = bounds.max.y;
holder.TopAndBottom.y = bounds.min.y;
holder.Size = bounds.size;
//可重新计算ScrollView的bounds
_calclateBounds = false;
if(!_dragging && !_isCallShowFunc)
SetMoveAmount();
//if (_newItemCount > 5)
//{
// SmoothMove(1);
// RecordLastPosition();
//}
//if (!_dragging)
// SmoothMove(1);
TriggeOnItemShow(holder);
}
private Bounds GetBounds(Transform trans)
{
return NGUIMath.CalculateRelativeWidgetBounds(trans, trans);
}
private Bounds GetBounds(Transform parent, Transform trans)
{
return NGUIMath.CalculateRelativeWidgetBounds(parent, trans);
}
/// <summary>
/// 计算添加item后UIPanel的clipOffset的偏移
/// </summary>
/// <param name="toBottom">对齐到底部</param>
private void SetMoveAmount(bool toBottom = true)
{
RecordLastPosition();
var mPanel = ScrollView.panel;
Bounds b = mBounds;
if (b.min.x == b.max.x || b.min.y == b.max.y) return;
Vector4 clip = mPanel.finalClipRegion;
float hx = clip.z * 0.5f;
float hy = clip.w * 0.5f;
float left = b.min.x + hx;
float right = b.max.x - hx;
float bottom = b.min.y + hy;
float top = b.max.y - hy;
if (mPanel.clipping == UIDrawCall.Clipping.SoftClip)
{
left -= mPanel.clipSoftness.x;
right += mPanel.clipSoftness.x;
bottom -= mPanel.clipSoftness.y;
top += mPanel.clipSoftness.y;
}
Vector4 cr = mPanel.baseClipRegion;
float oy = bottom;
if (b.size.y < cr.w)
{
oy = top;
_lerpTimer = 1;
}
//对齐顶部主要是用在起始位置的item被删除后裁剪区域顶部需要和最上面的item对齐
if (!toBottom)
oy = top;
var pos = transform.localPosition;
if (ScrollView.canMoveHorizontally)
{
_rootMoveToPos.x = pos.x + clip.x - right;
_rootMoveToPos.y = pos.y;
_rootEndClipOffset.x = right - cr.x;
_rootEndClipOffset.y = clip.y - cr.y;
}
if (ScrollView.canMoveVertically)
{
_rootMoveToPos.x = pos.x;
_rootMoveToPos.y = pos.y + clip.y - oy;
_rootEndClipOffset.x = clip.x - cr.x;
_rootEndClipOffset.y = oy - cr.y;
}
}
/// <summary>
/// 手动设置裁剪区域需要移动的偏移
/// </summary>
/// <param name="offsetY"></param>
private void SetClipRegionMoveOffset(float offsetY)
{
//RecordLastPosition();
var pos = transform.localPosition;
Vector4 clip = ScrollView.panel.finalClipRegion;
Vector4 cr = ScrollView.panel.baseClipRegion;
var topPos = offsetY - cr.w * 0.5f;
//需要矫正边界坐标,中心点总是跟边界有其一半高度的偏移
//topPos = topPos - clip.w * 0.5f;
Vector3 _rootMoveToPos = pos;
Vector4 _rootEndClipOffset = clip;
_rootMoveToPos.x = pos.x;
_rootMoveToPos.y = pos.y + clip.y - topPos;
_rootEndClipOffset.x = clip.x;
_rootEndClipOffset.y = topPos - cr.y;
transform.localPosition = _rootMoveToPos;
ScrollView.panel.clipOffset = _rootEndClipOffset;
RecordLastPosition();
}
private void SmoothMove(float time)
{
_calclateBounds = false;
if (transform.localPosition == _rootMoveToPos)
return;
//transform.localPosition = Vector3.Lerp(_lastRootPos, _rootMoveToPos, time);
//ScrollView.panel.clipOffset = Vector2.Lerp(_lastClipOffset, _rootEndClipOffset, time);
transform.localPosition = _rootMoveToPos;
ScrollView.panel.clipOffset = _rootEndClipOffset;
//可重新计算ScrollView的bounds
}
private void TriggeOnItemShow(ItemHolder item)
{
if (item.OnItemShow != null)
item.OnItemShow(item);
}
//记录上次变换后的位置
private void RecordLastPosition()
{
_lastRootPos = transform.localPosition;
_lastClipOffset = ScrollView.panel.clipOffset;
_lerpTimer = 0;
if (!_dragging)
_enableSmoothMove = true;
}
private void SetPosition(Transform item, Bounds itemBounds, bool addToTop)
{
int offsetX = 10;
var pivot = GetPivot(item);
if (addToTop)
{
var pos = new Vector3(0, _topPos.y - itemBounds.size.y * 0.5f);
if (pivot == UIWidget.Pivot.TopLeft)
{
//pos.x = -itemBounds.size.x * 0.5f;
pos.x = -_scrollViewSize.x * 0.5f + offsetX;
pos.y = _topPos.y + itemBounds.size.y;
}
else if (pivot == UIWidget.Pivot.Left)
{
//pos.x = -itemBounds.size.x ;
pos.x = -_scrollViewSize.x * 0.5f + offsetX;
pos.y = _topPos.y + itemBounds.size.y * 0.5f;
}
else if (pivot == UIWidget.Pivot.TopRight)
{
//pos.x = itemBounds.size.x * 0.5f;
pos.x = _scrollViewSize.x * 0.5f - offsetX;
pos.y = _topPos.y + itemBounds.size.y;
}
else if (pivot == UIWidget.Pivot.Right)
{
//pos.x = itemBounds.size.x * 0.5f;
pos.x = _scrollViewSize.x * 0.5f - offsetX;
pos.y = _topPos.y + itemBounds.size.y * 0.5f;
}
//垂直方向x值是center的值
item.localPosition = pos;
//矫正坐标, 需要在设置偏移前调用
CorrectPosition(item, addToTop);
//仅在Y方向做偏移保存
_topPos.y = _topPos.y + itemBounds.size.y;
_topPos.y += _spaceY;
_topPos.x = pos.x;
}
else
{
var pos = new Vector3(0, _bottomPos.y - itemBounds.size.y * 0.5f);
if (pivot == UIWidget.Pivot.TopLeft)
{
pos.x = -_scrollViewSize.x * 0.5f + offsetX;
pos.y = _bottomPos.y - itemBounds.size.y;
}
else if (pivot == UIWidget.Pivot.Left)
{
pos.x = -_scrollViewSize.x + offsetX;
pos.y = _bottomPos.y - itemBounds.size.y * 0.5f;
}
else if (pivot == UIWidget.Pivot.TopRight)
{
pos.x = _scrollViewSize.x * 0.5f - offsetX;
pos.y = _bottomPos.y - itemBounds.size.y;
}
else if (pivot == UIWidget.Pivot.Right)
{
pos.x = _scrollViewSize.x * 0.5f - offsetX;
pos.y = _bottomPos.y - itemBounds.size.y * 0.5f;
}
//垂直方向x值是center的值
item.localPosition = pos;
//仅在Y方向做偏移保存
_bottomPos.y = _bottomPos.y - itemBounds.size.y;
_bottomPos.y -= _spaceY;
_bottomPos.x = pos.x;
//矫正坐标,需要在设置了偏移后调用
CorrectPosition(item, addToTop);
}
}
//矫正位置因Item设置坐标其中心点是最上层组件的中心点而不是整个Transform和子控件构成的大的
//控件的中心点,导致设置坐标时会有偏移,在这里对偏移做矫正
private void CorrectPosition(Transform trans, bool addToTop)
{
//重新计算设置了坐标后的bounds主要是得到中心点
var bounds = NGUIMath.CalculateRelativeWidgetBounds(_transform, trans);
if (addToTop)
trans.localPosition += (new Vector3(0, _topPos.y - bounds.min.y));
else
trans.localPosition += (new Vector3(0, _bottomPos.y - bounds.min.y));
}
private UIWidget.Pivot GetPivot(Transform trans)
{
var widget = trans.GetComponent<UIWidget>();
if (widget != null)
return widget.pivot;
return UIWidget.Pivot.Center;
}
private void MoveItemToCacheParent(ItemHolder item, bool disappearTop)
{
item.Object.gameObject.SetActive(false);
if(disappearTop)
{
_topPos.y -= item.Bounds.size.y;
}
else
{
_bottomPos.y += item.Bounds.size.y;
}
}
/// <summary>
/// 添加新的Item补充到上或者下方即将呈现的位置
/// </summary>
/// <param name="disappearItem">上方或者下方在裁剪区域外的item</param>
/// <param name="addToTop"></param>
/// <param name="displayItem">上方或者下方在裁剪区域内的item</param>
private ItemHolder AddItemFromCacheParent(ItemHolder disappearItem, bool addToTop, ItemHolder displayItem)
{
ItemHolder newItem = null;
if(addToTop)
{
var newIndex = displayItem == null ? 0 : _adapter.GetReverseNextIndex(displayItem.Index);
if (_curChannel != _adapter.GetChannelId(newIndex))
return null;
newItem = CreateHolder(newIndex, disappearItem);
if (newItem == null)
return newItem;
//有裁剪区域外的item才移除末尾的item
if (disappearItem != null && !newItem.UseNew)
{
_showingList.RemoveAt(_showingList.Count - 1);
if(_showingList.Count > 0)
{
var bottomItem = _showingList[_showingList.Count - 1];
_bottomPos.y = bottomItem.TopAndBottom.y;
_bottomPos.y -= _spaceY;
}
}
_showingList.Insert(0, newItem);
}
else
{
var newIndex = displayItem == null ? 0 : _adapter.GetNextIndex(displayItem.Index);
if (_curChannel != _adapter.GetChannelId(newIndex))
return null;
newItem = CreateHolder(newIndex, disappearItem);
if (newItem == null)
return newItem;
//有裁剪区域外的item才移除开头的item
if (disappearItem != null && !newItem.UseNew)
{
_showingList.RemoveAt(0);
if(_showingList.Count > 0)
{
_topPos.y = _showingList[0].TopAndBottom.x;
_topPos.y += _spaceY;
}
}
_showingList.Add(newItem);
}
AddItem(newItem, addToTop);
return newItem;
}
private ItemHolder CreateHolder(int index, ItemHolder temp)
{
if (index < 0 || index >= _adapter.GetCount())
return null;
var newItem = _adapter.GetView(index, temp);
if (newItem == null)
return null;
newItem.Index = index;
//newItem.Object.parent = _transform;
return newItem;
}
private void PlayScaleEffect(ItemHolder holder)
{
if (holder == null || !EnableEffect)
return;
//if (holder.AnimEffect == null)
//{
// holder.AnimEffect = holder.Object.gameObject.RequireComponent<ScaleEffect>();
// holder.AnimEffect.From = Vector3.one * 0.5f;
// holder.AnimEffect.To = Vector3.one;
// holder.AnimEffect.Duration = 0.5f;
//}
//holder.Object.localScale = holder.AnimEffect.From;
//holder.AnimEffect.Start();
}
//上方第一个在裁剪区域内的item
private ItemHolder GetTopItemInClipRegion()
{
if (_showingList.Count > 0)
return _showingList[0];
return null;
}
//下方最后一个在裁剪区域内的item
private ItemHolder GetBottomItemInClipRegion()
{
if (_showingList.Count > 0)
return _showingList[_showingList.Count - 1];
return null;
}
//上方第一个在裁剪区域外的Item
private ItemHolder GetTopItemOutOfClipRegion(float topClipPos)
{
if(_showingList.Count > 0)
{
var topItem = _showingList[0];
if (topItem.TopAndBottom.y > topClipPos + Offset)
return topItem;
}
return null;
}
private ItemHolder GetTopItemOutOfClipRegion()
{
Vector4 clip = ScrollView.panel.finalClipRegion;
float hy = clip.w * 0.5f;
//裁剪区域的上沿Y坐标
var topClipPos = clip.y + hy;
return GetTopItemOutOfClipRegion(topClipPos);
}
//下方最后一个在裁剪区域外的item
private ItemHolder GetBottomItemOutOfClipRegion(float bottomClipPos)
{
if(_showingList.Count > 0)
{
var bottomItem = _showingList[_showingList.Count - 1];
if (bottomItem.TopAndBottom.x < bottomClipPos - Offset)
return bottomItem;
}
return null;
}
//下方最后一个在裁剪区域外的item
private ItemHolder GetBottomItemOutOfClipRegion()
{
Vector4 clip = ScrollView.panel.finalClipRegion;
float hy = clip.w * 0.5f;
//下沿Y坐标
var bottomClipPos = clip.y - hy;
return GetBottomItemOutOfClipRegion(bottomClipPos);
}
#endregion
}
}