首先,我们 想做一个滚动列表,这就像在 x轴 和Z 轴上的 一个循环的椭圆
##如果我们将卡牌平均分布在这个椭圆上。那么每个卡牌占这个 椭圆 整个圆周 角度一定的 比例。我们定这个比例 为 radio ,radio 的值 从 0 ~ 1 ,0和1 的点重合。
现在大家 清除 我们卡牌 是怎么 排布的了吧。
我们 需要做的点有四个:
1.将 卡牌 排布在这个椭圆上。
2. 根据 radio 去 设置 不同位置的卡牌的 缩放。
3. 为了看起来有层次感,我们需要设置 卡牌的 层级。
4. 最后就是 给卡牌添加 拖拽的监听。
那么现在第一步骤:
在 unity UI 上添加一个 节点,用来放置我们的卡牌。
在UI 上加个 空的 组件。作为父节点。
然后 添加 C# 脚本,添加到该组件上。
我这里 百度截图了 10张图,将就着用。
先初始化这 10张卡牌
private GameObject CreateTempate()
{
GameObject temp = new GameObject("Template");
temp.AddComponent<PageItem>();
temp.AddComponent<RectTransform>().sizeDelta = ItemSize;
temp.AddComponent<Image>();
return temp;
}
private void CreateItem()
{
GameObject temp = CreateTempate();
for (int i = 0; i < SpriteList.Count; i++)
{
PageItem item = Instantiate(temp).GetComponent<PageItem>();
item.Index = i;
item.SetImage(SpriteList[i]);
item.SetParent(transform);
item.AddEventlistenr(change);
ItemList.Add(item);
}
}
我们 在这个椭圆上 平均分布 这些卡牌,则 均分的 系数 是 radio = 1/10,十张卡牌均分;
private void CaculateData()
{
float length = (ItemSize.x + OffSetX) * 6;
float radio = 1.0f / SpriteList.Count;
float tempRadio = 0f;
for (int i = 0; i < SpriteList.Count; i++)
{
ItemPosData pos = new ItemPosData();
ItemIdData itemId = new ItemIdData();
itemId.Id = i;
pos.X = GetX(tempRadio, length);
pos.ScareTimes = GetScaraTimes(tempRadio, ScareMax, ScareMin);
tempRadio += radio;
pos.Order = i;
ItemPosList.Add(pos);
itemIdList.Add(itemId);
}
itemIdList = itemIdList.OrderBy(u => ItemPosList[u.Id].ScareTimes).ToList();
for (int i = 0; i < itemIdList.Count; i++) //根据缩放有小到大,排列了id列表
{
int id = itemIdList[i].Id;
ItemPosList[id].Order = i;
}
for (int i = 0; i < ItemPosList.Count; i++)
{
ItemList[i].SetPositon(ItemPosList[i]);
}
}
length 是我们自己定义 滚动列表的宽度,很重要的一点,Z 轴 左右两边 的 卡牌坐标是是对称的。
我们根据 radio 和宽度 计算出 卡牌的 X 坐标。
private float GetX(float radio, float length)
{
if (radio < 0 || radio > 1)
{
Debug.Log("系数错误");
return 0;
}
if (radio >= 0 && radio <= 0.25f)
{
return radio * length;
}
else if (radio > 0.25 && radio < 0.75f)
{
return (0.5f - radio) * length;
}
else
{
return (radio - 1f) * length;
}
}
同样的,卡牌的缩放,也是 左右对称的。
private float GetScaraTimes(float radio, float scareMax, float scareMin)
{
float scareSub = scareMax - scareMin;
if (radio < 0f || radio > 1f)
{
Debug.Log("系数错误");
return 0;
}
if (radio == 0 || radio == 1f)
{
return scareSub;
}
if (radio > 0 && radio <= 0.5f)
{
return (1 - radio) * scareSub;//0.5 ~ 1
}
else
{
return radio * scareSub;
}
}
这时候的 卡牌是没有层级的
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;
public class PageItem : MonoBehaviour,IDragHandler,IEndDragHandler
{
private float X;
private int index;
private float ScareTimes;
private float offX = 0;
private Action<float> MoveAction;
private Image myImage;
private Image MyImage
{
get {
if (myImage == null)
myImage = GetComponent<Image>();
return myImage;
}
}
private RectTransform myRect;
private RectTransform MyRect {
get {
if (myRect == null)
myRect = GetComponent<RectTransform>();
return myRect;
}
}
public int Index
{
get=> index; set => index = value;
}
void Start()
{
}
public void SetParent(Transform parent) {
transform.SetParent(parent);
}
public void SetPositon(ItemPosData posData) {
MyRect.DOAnchorPos(Vector2.right * posData.X, 1.0f);
MyRect.DOScale(Vector2.one * posData.ScareTimes, 1.0f);
StartCoroutine(wait(posData.Order));
}
IEnumerator wait(int order) {
yield return new WaitForSeconds(0.5f);
//transform.SetSiblingIndex(order);
}
public void SetImage(Sprite sprite) {
MyImage.sprite = sprite;
}
public void AddEventlistenr(Action<float> move) {
MoveAction = move;
}
public void OnDrag(PointerEventData eventData)
{
offX += eventData.delta.x;
//Debug.Log("offX=========" + offX);
}
public void OnEndDrag(PointerEventData eventData)
{
MoveAction(offX);
offX = 0;
}
}
item 中 我们 重点 就是 添加可 两个 拖拽接口:
IDragHandler,IEndDragHandler
这是我们能让 卡牌滚动的重点。
通过委托,我们将 offX 也就是拖拽的 值传递到 父节点的脚本中。
item.AddEventlistenr(change);
我们 通过 计算好的 位置 和缩放值 的列表。
去给 item 重新设置 位置 和 缩放,就产生了滚动的效果。
private void change(float offX) {
int symbol = 0;
symbol = offX > 0 ? 1 : -1;
rotateItem(symbol);
}
private void rotateItem(int symbol) {
int allNums = itemIdList.Count;
int lens = allNums - 1;
int maxValues = lens;
for (int i = 0; i < ItemPosList.Count; i++)
{
int index = ItemList[i].Index;
if (symbol < 0)
{
if (index == 0)
{
index = maxValues;
}
else
{
index = index + symbol;
}
}
else {
if (index == maxValues)
{
index = 0;
}
else
{
index = index + symbol;
}
}
ItemList[i].Index = index;
}
for (int i = 0; i < allNums; i++) {
int index = ItemList[i].Index;
ItemList[i].SetPositon(ItemPosList[index]);
}
}
这里主要 要理解 的还是位置的重置。
链接: https://pan.baidu.com/s/1dynUHQYCCevMUW8qFlRM-Q 提取码: r59t
demo 下载