效果预览:
此处利用Excel来读取数据来制作年份选择器,具体步骤如下。
如果只是制作年份选择器可以参考我这篇文章:构建简单实用的年份选择器(简单原理示范)
目录
一、 Excel准备与存放
1.1 Excel准备
打开Excel,填写内容,保存命名为“年份”。示例如下:
1.2 存放Excel
将命名为“年份”的excel文件存放在Assets根目录下
1.3 读取Excel准备
读取Excel的几种方式可以参考这篇文章:读取Excel的几种方式
此处使用DLL插件读取
将所需插件放入Plugins文件夹中
二、场景准备
场景包括显示年份的背景和字体等内容,具体可以参考这篇文章: 构建简单实用的年份选择器(简单原理示范)
三、编写脚本
此处编写了两个脚本,分别是ExcelTool和YearAdsorption,ExcelTool实现读取Excel内容并记录,YearAdsorption来实现生成年份。
using System.Data; // 引入System.Data命名空间,用于处理数据表
using System.IO; // 引入System.IO命名空间,用于文件操作
using Excel; // 引入Excel命名空间,用于读取Excel文件
using UnityEngine; // 引入UnityEngine命名空间,用于Unity相关功能
public class ExcelTool : MonoBehaviour
{
public static string[] YearsItemsStr;//用来存放Excel中的年份
public static int YearsItemsNum; //用来存放Excel中的年份数量
void Start()
{
ReadExcel("/年份.xlsx"); // 调用读取Excel方法,并传入文件路径
}
// 读取Excel文件
public void ReadExcel(string xmlName)
{
FileStream stream = File.Open(Application.dataPath + xmlName, FileMode.Open, FileAccess.Read, FileShare.Read); // 打开Excel文件流
//IExcelDataReader excelReader = ExcelReaderFactory.CreateBinaryReader(stream);//读取 Excel 1997-2003版本
IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream); // 使用OpenXml读取 Excel 2007及以后的版本
DataSet result = excelReader.AsDataSet(); // 将Excel数据读取到DataSet中
if (stream != null)
{
stream.Close(); // 关闭文件流
}
//DataSet可以包含多个数据表,索引从0开始,所以result.Tables[0]代表第一个表格。
int[] counts = GetCount(result.Tables[0]); // 获取Excel表格的行数和列数
int rows = counts[0]; // 行数
int columns = counts[1]; // 列数
YearsItemsNum = rows - 1;//记录年份数量
Debug.Log("Excel年份数YearsItemsNum:" + YearsItemsNum);
YearsItemsStr = new string[rows - 1];
Debug.Log("row:" + rows + "...col:" + columns); // 打印行数和列数信息
// 遍历Excel表格并打印内容
for (int i = 1; i < rows; i++)//将表头"年份"不包括在内于是i!=0
{
for (int j = 0; j < columns; j++)
{
Debug.Log(result.Tables[0].Rows[i][j].ToString()); // 打印单元格内容
YearsItemsStr[i-1] = result.Tables[0].Rows[i][j].ToString();
}
}
}
// 获取数据表的行数和列数
private int[] GetCount(DataTable dt)
{
int i = dt.Rows.Count; // 获取行数
for (int m = 0; m < dt.Rows.Count; m++)
{
if (string.IsNullOrEmpty(dt.Rows[m][0].ToString())) // 判断第一列是否为空
{
i = m; // 如果为空,记录有效行数
break;
}
}
int j = dt.Columns.Count; // 获取列数
for (int n = 0; n < dt.Columns.Count; n++)
{
if (string.IsNullOrEmpty(dt.Rows[0][n].ToString())) // 判断第一行是否为空
{
j = n; // 如果为空,记录有效列数
break;
}
}
return new int[] { i, j }; // 返回行数和列数的数组
}
}
using UnityEngine;
using UnityEngine.UI;
public class YearAdsorption : MonoBehaviour
{
public GameObject yearTextPrefab; // 预设的年份Text对象
public ScrollRect scrollRect;
public float scaleDifference = 0.5f; // 缩放差异
public RectTransform contentRectTrans; // Scroll Rect Content的RectTransform
private RectTransform[] items;//用来存放生成的年份
//int yearsCount = 40; // 年份总数
float viewPortSize;
float center;
int itemCount;
void Start()
{
// 获取ScrollView的视图大小300;
viewPortSize = scrollRect.viewport.rect.height;
Debug.Log("ScrollView的视图大小:" + viewPortSize);
// 计算ScrollView的中心位置
center = scrollRect.transform.position.y;// - viewPortSize / 2;
Debug.Log("ScrollView的中心位置:" + center);
Debug.Log("YearAdsorption的YearsItemsNum:" + ExcelTool.YearsItemsNum);
for (int i = 0; i < ExcelTool.YearsItemsNum; i++)//int i = 0; i < yearsCount; i++
{
GenerateYearText(ExcelTool.YearsItemsStr[i]);//1950+iint.Parse(ExcelTool.YearsItemsStr[i])
Debug.Log("YearAdsorption年份:" + ExcelTool.YearsItemsStr[i]);
}
//for (int i = 0; i < yearsCount; i++)//int i = 0; i < yearsCount; i++
//{
// GenerateYearText((1950 + i).ToString());//1950+iint.Parse(ExcelTool.YearsItemsStr[i])
//}
// 获取ScrollView中的所有子对象
itemCount = scrollRect.content.childCount;
items = new RectTransform[itemCount];
for (int i = 0; i < itemCount; i++)
{
items[i] = scrollRect.content.GetChild(i).GetComponent<RectTransform>();
//Debug.Log("items[i]: " + i);
}
}
void Update()
{
foreach (RectTransform item in items)
{
// 计算每个项目的中心位置
float itemCenter = item.transform.position.y;// - item.rect.height / 2;
//Debug.Log("每个项目的中心位置: " + itemCenter);
// 计算每个项目相对于ScrollView中心的偏移量
float distanceFromCenter = Mathf.Abs(center - itemCenter);
// 根据偏移量计算缩放比例
float scale = Mathf.Clamp(1 - distanceFromCenter * scaleDifference / viewPortSize, 0.5f, 1f);
//Debug.Log("根据偏移量计算缩放比例: " + scale);
// 应用缩放
item.localScale = new Vector3(scale, scale, 1f);
}
// 如果用户停止滑动,则吸附到最近的年份
if (scrollRect.velocity.magnitude <= 20.0f)
{
SnapToNearestYear();
Debug.Log("不移动了!");
}
}
private void GenerateYearText(string year)
{
GameObject yearText = Instantiate(yearTextPrefab, contentRectTrans);
yearText.transform.SetAsFirstSibling();
yearText.transform.GetComponent<Text>().text = year.ToString();
}
void SnapToNearestYear()
{
RectTransform closestItem = null;
foreach (RectTransform item in items)
{
float distance = Mathf.Abs(center - item.position.y);
if (distance < 35)// 根据需求调整阈值
{
closestItem = item;
Debug.Log("装入了一个Item");
}
}
// 将最近的年份吸附到ScrollView的中心
if (closestItem != null)
{
// 计算需要移动的距离
float distanceToMove = center - closestItem.position.y;
// 将ScrollView的内容向上或向下移动,使最近的年份对象出现在ScrollView的中心
scrollRect.content.anchoredPosition += new Vector2(0f, distanceToMove);
}
}
}
这里注意两个脚本的执行顺序,ExcelTool需要在YearAdsorption之前执行
修改执行顺序可以参考我这篇文章:如何设置Unity脚本的执行顺序?
将两个脚本挂载Canvas上,拖入相应物体并运行 。
四、总结
以上实现步骤具体内容可参考以下文章: