最后的两个代码段为最终代码,可直接使用(需导入DoTween)
对数据的设置(参考):
,
先创建物体模板,再创建物体
设置图片的缩放系数和X轴位置,再对其位置信息进行计算:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class RotationDiagram2D : MonoBehaviour
{
public Vector2 ItemSize; //图片大小
public Sprite[] ItemSprites;
public float Offect; //图片间距
public float ScaleTimesMin; //最大缩放系数
public float ScaleTimesMax; //最小缩放系数
private List<RotationDiagramItem> RotationDiagramItemList;
private List<ItemPosData> PosDataList;
void Start()
{
PosDataList = new List<ItemPosData>();
RotationDiagramItemList = new List<RotationDiagramItem>();
CreateItem();
CalculateData();
SetItemPosData();
}
/// <summary>
/// 创建物体模板
/// </summary>
GameObject CreateTemplate()
{
GameObject template = new GameObject();
template.AddComponent<RectTransform>();
template.AddComponent<Image>();
template.AddComponent<RotationDiagramItem>();
return template;
}
//创建UI物体,设置图片和父物体 并 将其放入RotationDiagramItemList中
void CreateItem()
{
GameObject template = CreateTemplate();
RotationDiagramItem item = null;
foreach (Sprite sprite in ItemSprites)
{
item = Instantiate(template).GetComponent<RotationDiagramItem>();
item.SetSprite(sprite);
item.SetParent(transform);
RotationDiagramItemList.Add(item);
}
Destroy(template);
}
//计算位置的方法
private void CalculateData()
{
float length = (ItemSize.x + Offect) * RotationDiagramItemList.Count; // 长度为(图片长度 + 图片间间隔) * 图片数量
float radioOffect = 1 / (float)RotationDiagramItemList.Count; // 每个图片的等距间隔
float radio = 0;
for (int i = 0; i < RotationDiagramItemList.Count; i++)
{
ItemPosData data = new ItemPosData();
data.X = GetX(radio, length);
data.ScaleTimes = GetScaleTimes(radio, ScaleTimesMax, ScaleTimesMin);
radio += radioOffect;
PosDataList.Add(data);
}
}
/// <summary>
/// 设置图片的位置数据(将第i个位置信息赋予第i个子物体)
/// </summary>
private void SetItemPosData()
{
for (int i = 0; i < RotationDiagramItemList.Count; i++)
{
RotationDiagramItemList[i].SetPos(PosDataList[i]);
}
}
/// <summary>
/// 用于获取X轴的位置
/// </summary>
/// <param name="radio">图片所在位置比例,如有三张图片,长度为1,则位置为0,0.33,0.66.</param>
/// <param name="length">length为总长度,length = (图片长度 + 图片间间隔) * 图片数量</param>
/// <returns></returns>
private float GetX(float radio, float length)
{
if (radio < 0 || radio > 1)
{
Debug.LogWarning("当前比例必须为 0 - 1 的值");
return 0;
}
else if (radio >= 0 && radio < 0.25)
{
return radio * length;
}
else if (radio >= 0.25 && radio < 0.75)
{
return (0.5f - radio) * length;
}
else
{
return (radio - 1) * length;
}
}
//获取缩放系数
public float GetScaleTimes(float radio,float max ,float min)
{
if (radio < 0 || radio > 1)
{
Debug.LogWarning("当前比例必须为 0 - 1 的值");
return 0;
}
float scaleOffect = (max - min) / 0.5f;
if (radio < 0.5f)
return max - scaleOffect * radio;
else
return max - scaleOffect * (1-radio);
}
}
public classItemPosData
{
public float X;
public float ScaleTimes; // 缩放系数
}using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class RotationDiagramItem : MonoBehaviour
{
//不用Start的原因:防止初始化时,别的地方调用时,该项时还未进行初始化
private Image image;
public Image Image
{
get
{
if (image == null)
image = GetComponent<Image>();
return image;
}
}
private RectTransform rect;
public RectTransform Rect
{
get
{
if (rect == null)
rect = GetComponent<RectTransform>();
return rect;
}
}
//设置父物体
public void SetParent(Transform parent)
{
this.transform.SetParent(parent);
}
//设置图片
public void SetSprite(Sprite sprite)
{
Image.sprite = sprite;
}
//将位置数据赋予子物体
public void SetPos(ItemPosData data)
{
Rect.anchoredPosition = data.X * Vector2.right;
Rect.localScale = data.ScaleTimes * Vector3.one;
Debug.Log(gameObject.name + ":" + Rect.anchoredPosition + ":" + Rect.localScale);
}
}
我们会发现,后面的图片把前面的图片盖住了
所以我们需要对图片的层级进行排序
修改思路:
声明 结构体 ItemData ,用PosID来获取对应位置的数据,ItemPosData 中声明 order 来表示图片的层级
在CalculateData 方法中, 声明List集合管理ItemData并在第一次for循环中对ItemData的PosID初始化并添加入集合,再对itemDatas中的PosID进行升序排序,利用for循环对PosDataList的order赋值(i= 0 → order = 2 → PosDataList[2].order = 0),再到子类RotationDiagramItem的SetPos方法中设置子类图片的层级(通过transform.SetSiblingIndex方法)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Linq;
public class RotationDiagram2D : MonoBehaviour
{
public Vector2 ItemSize; //图片大小
public Sprite[] ItemSprites;
public float Offect; //图片间距
public float ScaleTimesMin; //最大缩放系数
public float ScaleTimesMax; //最小缩放系数
private List<RotationDiagramItem> RotationDiagramItemList;
private List<ItemPosData> PosDataList;
void Start()
{
PosDataList = new List<ItemPosData>();
RotationDiagramItemList = new List<RotationDiagramItem>();
CreateItem();
CalculateData();
SetItemPosData();
}
/// <summary>
/// 创建物体模板
/// </summary>
GameObject CreateTemplate()
{
GameObject template = new GameObject();
template.AddComponent<RectTransform>();
template.AddComponent<Image>();
template.AddComponent<RotationDiagramItem>();
return template;
}
//创建UI物体,设置图片和父物体 并 将其放入RotationDiagramItemList中
void CreateItem()
{
GameObject template = CreateTemplate();
RotationDiagramItem item = null;
foreach (Sprite sprite in ItemSprites)
{
item = Instantiate(template).GetComponent<RotationDiagramItem>();
item.SetSprite(sprite);
item.SetParent(transform);
RotationDiagramItemList.Add(item);
}
Destroy(template);
}
//计算位置的方法
private void CalculateData()
{
List<ItemData> itemDatas = new List<ItemData>();
float length = (ItemSize.x + Offect) * RotationDiagramItemList.Count; // 长度为(图片长度 + 图片间间隔) * 图片数量
float radioOffect = 1 / (float)RotationDiagramItemList.Count; // 每个图片的等距间隔
float radio = 0;
for (int i = 0; i < RotationDiagramItemList.Count; i++)
{
ItemData itemData = new ItemData();
itemData.PosID = i;
itemDatas.Add(itemData);
ItemPosData data = new ItemPosData();
data.X = GetX(radio, length);
data.ScaleTimes = GetScaleTimes(radio, ScaleTimesMax, ScaleTimesMin);
radio += radioOffect;
PosDataList.Add(data);
}
itemDatas = itemDatas.OrderBy(a => PosDataList[a.PosID].ScaleTimes).ToList(); //对itemDatas中的PosID进行升序排序
for (int i = 0; i < itemDatas.Count; i++)
{
// i= 0 → order = 2 → PosDataList[2].order = 0
// 在前面的图片不能被后面的挡住,所以层级要更大
PosDataList[itemDatas[i].PosID].order = i;
}
}
/// <summary>
/// 设置图片的位置数据(将第i个位置信息赋予第i个子物体)
/// </summary>
private void SetItemPosData()
{
for (int i = 0; i < RotationDiagramItemList.Count; i++)
{
RotationDiagramItemList[i].SetPos(PosDataList[i]);
}
}
/// <summary>
/// 用于获取X轴的位置
/// </summary>
/// <param name="radio">图片所在位置比例,如有三张图片,长度为1,则位置为0,0.33,0.66.</param>
/// <param name="length">length为总长度,length = (图片长度 + 图片间间隔) * 图片数量</param>
/// <returns></returns>
private float GetX(float radio, float length)
{
if (radio < 0 || radio > 1)
{
Debug.LogWarning("当前比例必须为 0 - 1 的值");
return 0;
}
else if (radio >= 0 && radio < 0.25)
{
return radio * length;
}
else if (radio >= 0.25 && radio < 0.75)
{
return (0.5f - radio) * length;
}
else
{
return (radio - 1) * length;
}
}
//获取缩放系数
public float GetScaleTimes(float radio,float max ,float min)
{
if (radio < 0 || radio > 1)
{
Debug.LogWarning("当前比例必须为 0 - 1 的值");
return 0;
}
float scaleOffect = (max - min) / 0.5f;
if (radio < 0.5f)
return max - scaleOffect * radio;
else
return max - scaleOffect * (1-radio);
}
}
public class ItemPosData
{
public float X;
public float ScaleTimes; // 缩放系数
public int order; //层级
}
public struct ItemData
{
public int PosID;
}using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class RotationDiagramItem : MonoBehaviour
{
public int PosID;
//不用Start的原因:防止初始化时,别的地方调用时,该项时还未进行初始化
private Image image;
public Image Image
{
get
{
if (image == null)
image = GetComponent<Image>();
return image;
}
}
private RectTransform rect;
public RectTransform Rect
{
get
{
if (rect == null)
rect = GetComponent<RectTransform>();
return rect;
}
}
//设置父物体
public void SetParent(Transform parent)
{
this.transform.SetParent(parent);
}
//设置图片
public void SetSprite(Sprite sprite)
{
Image.sprite = sprite;
}
//将位置数据赋予子物体
public void SetPos(ItemPosData data)
{
Rect.anchoredPosition = data.X * Vector2.right;
Rect.localScale = data.ScaleTimes * Vector3.one;
transform.SetSiblingIndex(data.order); //通过参数index决定物体在父类的第几个孩子
}
}
图片的拖动与切换以及补间动画效果(DoTween)
通过IDragHandler, IEndDragHandler实现图片拖动的效果:
通过委托传递X轴偏移量来改变图片的PosID,再更新其位置信息 SetPos()
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;
using DG.Tweening;
public class RotationDiagramItem : MonoBehaviour, IDragHandler, IEndDragHandler
{
public int PosID;
private float mOffsetX;
private Action<float> mMoveAction;
private float mAniTime = .5f;
//不用Start的原因:防止初始化时,别的地方调用时,该项时还未进行初始化
private Image image;
public Image Image
{
get
{
if (image == null)
image = GetComponent<Image>();
return image;
}
}
private RectTransform rect;
public RectTransform Rect
{
get
{
if (rect == null)
rect = GetComponent<RectTransform>();
return rect;
}
}
//设置父物体
public void SetParent(Transform parent)
{
this.transform.SetParent(parent);
}
//设置图片
public void SetSprite(Sprite sprite)
{
Image.sprite = sprite;
}
//将位置数据赋予子物体
public void SetPos(ItemPosData data)
{
Rect.DOAnchorPos(data.X * Vector2.right, mAniTime);
Rect.DOScale(data.ScaleTimes * Vector3.one, mAniTime);
transform.SetSiblingIndex(data.order); //通过参数index决定物体在父类的第几个孩子
}
public void OnDrag(PointerEventData eventData)
{
mOffsetX += eventData.delta.x;
}
public void OnEndDrag(PointerEventData eventData)
{
mMoveAction(mOffsetX);
mOffsetX = 0;
}
public void AddMoveListener(Action<float> action)
{
mMoveAction = action;
}
public void ChangeID(int symbol,int total)
{
int id = PosID;
id += symbol;
if (id < 0)
{
id += total;
}
PosID = id % total;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Linq;
public class RotationDiagram2D : MonoBehaviour
{
public Vector2 ItemSize; //图片大小
public Sprite[] ItemSprites;
public float Offect; //图片间距
public float ScaleTimesMin; //最大缩放系数
public float ScaleTimesMax; //最小缩放系数
private List<RotationDiagramItem> RotationDiagramItemList;
private List<ItemPosData> PosDataList;
void Start()
{
PosDataList = new List<ItemPosData>();
RotationDiagramItemList = new List<RotationDiagramItem>();
CreateItem();
CalculateData();
SetItemPosData();
}
/// <summary>
/// 创建物体模板
/// </summary>
GameObject CreateTemplate()
{
GameObject template = new GameObject();
template.AddComponent<RectTransform>();
template.AddComponent<Image>();
template.AddComponent<RotationDiagramItem>();
return template;
}
//创建UI物体,设置图片和父物体 并 将其放入RotationDiagramItemList中
void CreateItem()
{
GameObject template = CreateTemplate();
RotationDiagramItem item = null;
foreach (Sprite sprite in ItemSprites)
{
item = Instantiate(template).GetComponent<RotationDiagramItem>();
item.SetSprite(sprite);
item.SetParent(transform);
item.AddMoveListener(Change); //添加监听
RotationDiagramItemList.Add(item);
}
Destroy(template);
}
private void Change(float offsetX)
{
//判断符号是正还是负
int symbol = offsetX > 0 ? 1 : -1;
Change(symbol);
}
//改变图片的PosID
private void Change(int symbol)
{
//为每个子类切换自身ID
foreach (RotationDiagramItem item in RotationDiagramItemList)
{
item.ChangeID(symbol, RotationDiagramItemList.Count);
}
for (int i = 0; i < PosDataList.Count; i++)
{
RotationDiagramItemList[i].SetPos(PosDataList[RotationDiagramItemList[i].PosID]);
}
}
//计算位置的方法
private void CalculateData()
{
List<ItemData> itemDatas = new List<ItemData>();
float length = (ItemSize.x + Offect) * RotationDiagramItemList.Count; // 长度为(图片长度 + 图片间间隔) * 图片数量
float radioOffect = 1 / (float)RotationDiagramItemList.Count; // 每个图片的等距间隔
float radio = 0;
for (int i = 0; i < RotationDiagramItemList.Count; i++)
{
ItemData itemData = new ItemData();
itemData.PosID = i;
itemDatas.Add(itemData);
RotationDiagramItemList[i].PosID = i;
ItemPosData data = new ItemPosData();
data.X = GetX(radio, length);
data.ScaleTimes = GetScaleTimes(radio, ScaleTimesMax, ScaleTimesMin);
radio += radioOffect;
PosDataList.Add(data);
}
itemDatas = itemDatas.OrderBy(a => PosDataList[a.PosID].ScaleTimes).ToList(); //对itemDatas中的PosID进行升序排序
for (int i = 0; i < itemDatas.Count; i++)
{
// i= 0 → order = 2 → PosDataList[2].order = 0
// 在前面的图片不能被后面的挡住,所以层级要更大
PosDataList[itemDatas[i].PosID].order = i;
}
}
/// <summary>
/// 设置图片的位置数据(将第i个位置信息赋予第i个子物体)
/// </summary>
private void SetItemPosData()
{
for (int i = 0; i < RotationDiagramItemList.Count; i++)
{
RotationDiagramItemList[i].SetPos(PosDataList[i]);
}
}
/// <summary>
/// 用于获取X轴的位置
/// </summary>
/// <param name="radio">图片所在位置比例,如有三张图片,长度为1,则位置为0,0.33,0.66.</param>
/// <param name="length">length为总长度,length = (图片长度 + 图片间间隔) * 图片数量</param>
/// <returns></returns>
private float GetX(float radio, float length)
{
if (radio < 0 || radio > 1)
{
Debug.LogWarning("当前比例必须为 0 - 1 的值");
return 0;
}
else if (radio >= 0 && radio < 0.25)
{
return radio * length;
}
else if (radio >= 0.25 && radio < 0.75)
{
return (0.5f - radio) * length;
}
else
{
return (radio - 1) * length;
}
}
//获取缩放系数
public float GetScaleTimes(float radio, float max, float min)
{
if (radio < 0 || radio > 1)
{
Debug.LogWarning("当前比例必须为 0 - 1 的值");
return 0;
}
float scaleOffect = (max - min) / 0.5f;
if (radio < 0.5f)
return max - scaleOffect * radio;
else
return max - scaleOffect * (1 - radio);
}
}
public class ItemPosData
{
public float X;
public float ScaleTimes; // 缩放系数
public int order; //层级
}
public struct ItemData
{
public int PosID;
}
版权声明:本文为weixin_44003309原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。