Unity3D UGUI制作滚动日期选择(无限滚动)
首先上效果图和层次结构
效果图 -层次结构 DatePickerGroup(日期选择组)
DatePicker(时间选择器)DatePickerGroup需要将所属的DatePicker添加到DatePickerList中,共同控制选择的时间。
Item示例DatePicker中Mask组件和Image组件起着遮罩的作用,
DatePicker组件需要选择DateType :_year, _month, _day,_hour, _minute, _second
DatePicker设置一下一列最多可显示数量
ItemObj和ItemParent添加对应引用
ContentItem示例,带有一个Text组件,注意:锚点和中心点位置注意都在中间。
Content注意RectTransform的锚点和位置信息。
包含ContentSizeFitter适应大小组件和VerticalLayoutGroup竖排列组件
注意VerticalLayoutGroup竖排列组件中红框的属性选择
下面贴代码:
using System;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
///
/// 当选择日期的委托
///
public delegate void OnDateUpdate();
public enum DateType {
_year, _month, _day,
_hour, _minute, _second
}
///
/// 日期选择器
/// 2019.4.10
/// wxw
///
public class DatePicker : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
///
/// 日期类型 (年月日时分秒)
///
public DateType _dateType;
///
/// 子节点数量(奇数)
///
public int _itemNum = 5;
[HideInInspector]
///
/// 更新选择的目标值
///
public float _updateLength;
///
/// 子节点预制体
///
public GameObject _itemObj;
///
/// 子节点容器对象
///
public Transform _itemParent;
///
/// 我属于的日期选择组
///
[HideInInspector]
public DatePickerGroup myGroup;
///
/// 当选择日期的委托事件
///
public event OnDateUpdate _onDateUpdate;
void Awake()
{
_itemObj.SetActive(false);
_updateLength = _itemObj.GetComponent().sizeDelta.y;
}
///
/// 初始化时间选择器
///
public void Init()
{
for (int i = 0; i < _itemNum; i++)
{
//计算真实位置
int real_i = -(_itemNum / 2) + i;
SpawnItem(real_i);
}
RefreshDateList();
}
///
/// 生成子对象
///
/// 对应日期
/// 真实位置
///
GameObject SpawnItem(float real_i) {
GameObject _item = Instantiate(_itemObj);
_item.SetActive(true);
_item.transform.SetParent(_itemParent);
_item.transform.localScale = Vector3.one;
_item.transform.localEulerAngles = Vector3.zero;
if (real_i != 0)
{
_item.GetComponent().color = new Color(1, 1, 1, 1 - 0.2f - (Mathf.Abs(real_i) / (_itemNum / 2 + 1)));
}
return _item;
}
Vector3 oldDragPos;
///
/// 当开始拖拽
///
///
public void OnBeginDrag(PointerEventData eventData)
{
oldDragPos = eventData.position;
}
public void OnDrag(PointerEventData eventData)
{
UpdateSelectDate(eventData);
}
public void OnEndDrag(PointerEventData eventData)
{
_itemParent.localPosition = Vector3.zero;
}
///
/// 更新选择的时间
///
///
void UpdateSelectDate(PointerEventData eventData)
{
//判断拖拽的长度是否大于目标值
if (Mathf.Abs(eventData.position.y - oldDragPos.y) >= _updateLength)
{
int num;
//判断加减
if (eventData.position.y > oldDragPos.y)
{
//+
num = 1;
}
else
{
//-
num = -1;
}
DateTime _data = new DateTime();
switch (_dateType)
{
case DateType._year:
_data = myGroup._selectDate.AddYears(num);
break;
case DateType._month:
_data = myGroup._selectDate.AddMonths(num);
break;
case DateType._day:
_data = myGroup._selectDate.AddDays(num);
break;
case DateType._hour:
_data = myGroup._selectDate.AddHours(num);
break;
case DateType._minute:
_data = myGroup._selectDate.AddMinutes(num);
break;
case DateType._second:
_data = myGroup._selectDate.AddSeconds(num);
break;
}
//判断是否属于时间段
if (IsInDate(_data, myGroup._minDate, myGroup._maxDate))
{
myGroup._selectDate = _data;
oldDragPos = eventData.position;
_onDateUpdate();
}
_itemParent.localPosition = Vector3.zero;
}
else
{
_itemParent.localPosition = new Vector3(0, (eventData.position.y - oldDragPos.y), 0);
}
}
///
/// 刷新时间列表
///
public void RefreshDateList() {
DateTime _data = new DateTime();
for (int i = 0; i < _itemNum; i++) {
//计算真实位置
int real_i = -(_itemNum / 2) + i;
switch (_dateType)
{
case DateType._year:
_data = myGroup._selectDate.AddYears(real_i);
break;
case DateType._month:
_data = myGroup._selectDate.AddMonths(real_i);
break;
case DateType._day:
_data = myGroup._selectDate.AddDays(real_i);
break;
case DateType._hour:
_data = myGroup._selectDate.AddHours(real_i);
break;
case DateType._minute:
_data = myGroup._selectDate.AddMinutes(real_i);
break;
case DateType._second:
_data = myGroup._selectDate.AddSeconds(real_i);
break;
}
string str = "";
if (IsInDate(_data, myGroup._minDate, myGroup._maxDate))
{
switch (_dateType)
{
case DateType._year:
str = _data.Year.ToString();
break;
case DateType._month:
str = _data.Month.ToString();
break;
case DateType._day:
str = _data.Day.ToString();
break;
case DateType._hour:
str = _data.Hour.ToString();
break;
case DateType._minute:
str = _data.Minute.ToString();
break;
case DateType._second:
str = _data.Second.ToString();
break;
}
}
_itemParent.GetChild(i).GetComponent().text = str;
}
}
///
/// 判断某个日期是否在某段日期范围内,返回布尔值
///
/// 要判断的日期
/// 开始日期
/// 结束日期
///
public bool IsInDate(DateTime dt, DateTime dt_min, DateTime dt_max)
{
return dt.CompareTo(dt_min) >= 0 && dt.CompareTo(dt_max) <= 0;
}
}
using System;
using System.Collections.Generic;
using UnityEngine;
///
/// 日期选择组
///
public class DatePickerGroup : MonoBehaviour {
///
/// 最小日期和最大日期
///
public DateTime _minDate, _maxDate;
///
/// 选择的日期(年月日时分秒)
///
public DateTime _selectDate;
///
/// 时间选择器列表
///
public List _datePickerList;
///
/// 当选择日期的委托事件
///
public event OnDateUpdate _OnDateUpdate;
void Awake() {
_minDate = new DateTime(2000, 1, 1, 0, 0, 0);
_maxDate = new DateTime(2020, 1, 1, 0, 0, 0);
}
public void Init(DateTime dt) {
_selectDate = dt;
for (int i = 0; i < _datePickerList.Count; i++)
{
_datePickerList[i].myGroup = this;
_datePickerList[i].Init();
_datePickerList[i]._onDateUpdate += onDateUpdate;
}
_OnDateUpdate();
}
public void Init()
{
_selectDate = DateTime.Now;
for (int i = 0; i < _datePickerList.Count; i++)
{
_datePickerList[i].myGroup = this;
_datePickerList[i].Init();
_datePickerList[i]._onDateUpdate += onDateUpdate;
}
_OnDateUpdate();
}
///
/// 当选择的日期更新
///
public void onDateUpdate()
{
Debug.Log("当前选择日期:" + _selectDate.ToString("yyyy/MM/dd HH : mm : ss"));
for (int i = 0; i < _datePickerList.Count; i++)
{
_datePickerList[i].RefreshDateList();
}
_OnDateUpdate();
}
}