Files
2025-01-25 04:38:09 +08:00

1156 lines
39 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}
}