在项目开发中,列表滚动是很常用的功能,比如展示玩家排名,聊天信息等。
这里我们实现一个循环列表功能。
首先我们创建个ScrollRect,移除掉Content里面的布局组件。如下
然后在List_View上放上如下代码
LoopListViewer.cs
:
/*
* Created By Zhaotao On 2019-3-22
* Desc:循环列表
*/
using System;
using System.Collections;
using System.Collections.Generic;
using DigiskyUnity;
using LuaInterface;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SocialPlatforms;
using UnityEngine.UI;
public class LoopListViewer : MonoBehaviour
{
private enum LayoutDir
{
NEGATIVE = -1,
POSITIVE = 1,
}
//滚动区域组件
[SerializeField] private ScrollRect ScrollView;
//Item父对象
[SerializeField] private GameObject Content;
//list的Item 控件
[SerializeField] private GameObject ItemBase;
//上下的缓冲
[SerializeField] private float BufferDis = 20;
//排列器
[SerializeField] private LoopItemArranger Arranger;
//默认Item的个数
[SerializeField] private int DefaultCount = 10;
//是否是垂直滚动
[SerializeField] private bool IsVertical = true;
//滚动方向 1 为正滚动,-1为反方向滚动
[SerializeField] private LayoutDir Direction = LayoutDir.POSITIVE;
//Item 列表
private List<ILoopItem> _ItemList = new List<ILoopItem>();
private int _TopIndex = -1;
private int _EndIndex = -1;
//Item的个数
private int _TotalCount = 0;
//Content 的尺寸
private Vector2 _ContentSize = Vector2.zero;
//ViewPort的尺寸
private Vector2 _ViewPortSize = Vector2.zero;
private LoopListUpdateCallBack _ChangeCallBack = null;
private Vector2 _LastPos = Vector2.zero;
//滚动到的索引
private int _ScrollToIndex = 0;
//滚动速度
private float _ScrollSpeed = 0;
private void Awake()
{
if (Content != null)
{
_ContentSize = Content.GetComponent<RectTransform>().sizeDelta;
}
if (ScrollView != null)
{
_ViewPortSize = ScrollView.GetComponent<RectTransform>().sizeDelta;
ScrollView.onValueChanged.AddListener(ScrollCallBack);
}
Arranger.SetIsVertical(IsVertical);
Arranger.SetDir((int)Direction);
AdjustPovit();
}
private void Start()
{
AddCount(DefaultCount);
Content.GetComponent<RectTransform>().anchoredPosition = Vector2.zero;
}
private void Update()
{
if (_ScrollToIndex > 0 && _ScrollSpeed > 0)
{
var head = Arranger.GetHeadItem();
var tail = Arranger.GetTailItem();
if (_ScrollToIndex < head.GetIndex())
{
//项下滚动
if (IsVertical)
{
SpeedScroll(-_ScrollSpeed * (int)Direction);
}
else
{
SpeedScroll(_ScrollSpeed * (int)Direction);
}
}else if (_ScrollToIndex > tail.GetIndex())
{
//项上滚动
if (IsVertical)
{
SpeedScroll(_ScrollSpeed * (int)Direction);
}
else
{
SpeedScroll(-_ScrollSpeed * (int)Direction);
}
}
else
{
//在可见项之间
ILoopItemArrange itemArrange = Arranger.GetItemArrangeByIndex(_ScrollToIndex);
if (itemArrange != null)
{
if (IsVertical)
{
float conY = Content.GetComponent<RectTransform>().anchoredPosition.y;
float iY = itemArrange.GetCurrentItem().GetPosition().y * (int) Direction;
float offY = conY * (int) Direction + iY + Arranger.GetSpaceOff();
if (Math.Abs(offY) < _ScrollSpeed)
{
SpeedScroll(-offY * (int)Direction);
_ScrollToIndex = 0;
_ScrollSpeed = 0;
ScrollView.enabled = true;
}
else if(Math.Abs(offY) > _ScrollSpeed)
{
SpeedScroll(-offY/Math.Abs(offY) * _ScrollSpeed * (int)Direction);
}
else
{
_ScrollToIndex = 0;
_ScrollSpeed = 0;
ScrollView.enabled = true;
}
}
else
{
float conX = Content.GetComponent<RectTransform>().anchoredPosition.x;
float iX = itemArrange.GetCurrentItem().GetPosition().x * (int) Direction;
float offX = conX * (int) Direction + iX - Arranger.GetSpaceOff();
if (Math.Abs(offX) < _ScrollSpeed)
{
SpeedScroll(-offX * (int)Direction);
_ScrollToIndex = 0;
_ScrollSpeed = 0;
ScrollView.enabled = true;
}
else if(Math.Abs(offX) > _ScrollSpeed)
{
SpeedScroll(-offX/Math.Abs(offX) * _ScrollSpeed * (int)Direction);
}
else
{
_ScrollToIndex = 0;
_ScrollSpeed = 0;
ScrollView.enabled = true;
}
}
}
else
{
LogHelper.Warning("dont find "+_ScrollToIndex +" Item");
}
}
}
}
/// <summary>
/// 调整锚点方向
/// </summary>
private void AdjustPovit()
{
var Rt = Content.GetComponent<RectTransform>();
var Rtb = ItemBase.GetComponent<RectTransform>();
if (Direction == LayoutDir.POSITIVE && IsVertical)
{
Rt.anchorMin = new Vector2(0,1);
Rt.anchorMax = new Vector2(1,1);
Rt.pivot = new Vector2(0.5f,1);
Rt.anchoredPosition = Vector2.zero;
Rtb.pivot = new Vector2(0.5f,1);
Rtb.anchoredPosition = Vector2.zero;
}else if (Direction == LayoutDir.NEGATIVE && IsVertical)
{
Rt.anchorMin = new Vector2(0,0);
Rt.anchorMax = new Vector2(1,0);
Rt.pivot = new Vector2(0.5f,0);
Rt.anchoredPosition = Vector2.zero;
Rtb.pivot = new Vector2(0.5f,0);
Rtb.anchoredPosition = Vector2.zero;
}else if(Direction == LayoutDir.POSITIVE && !IsVertical)
{
Rt.anchorMin = new Vector2(0,0);
Rt.anchorMax = new Vector2(0,1);
Rt.pivot = new Vector2(0,0.5f);
Rt.anchoredPosition = Vector2.zero;
Rtb.pivot = new Vector2(0,0.5f);
Rtb.anchoredPosition = Vector2.zero;
}else if(Direction == LayoutDir.NEGATIVE && !IsVertical)
{
Rt.anchorMin = new Vector2(1,0);
Rt.anchorMax = new Vector2(1,1);
Rt.pivot = new Vector2(1,0.5f);
Rt.anchoredPosition = Vector2.zero;
Rtb.pivot = new Vector