前言

考虑到工业项目中可能会利用到类似日历的工具,就比如选取某个时间节点,所以我结合UGUI源码开发了日历工具和日期拾取器工具,简单易用,接口齐全,可中文显示,外观可自定义。只需要导入脚本,即可在Hierarchy面板直接创建组件,和使用自带组件一样方便。

主要内容:

1.日历工具(仿Winform平台的Calendar组件)
2.日期拾取器
3.如何使用日历组件和日期拾取器组件

实现效果:

Unity中如何自主定义类 unity自定义组件_ui

Unity中如何自主定义类 unity自定义组件_Unity中如何自主定义类_02

实现方法:

1.如何不依靠预制物创建组件

创建方法在博主之前的两篇博文中重点介绍过,所以这里我将直接给出简单的代码结构,具体内容可去Github或者博客资源进行下载。


1.1 创建日历

public class SpringGUIMenuOptions
{
    [MenuItem("GameObject/UI/Calendar")]
    public static void AddCalendar( MenuCommand menuCommand )
    {
        GameObject calendar = SpringGUIDefaultControls.CreateCalendar(GetStandardResources());
        PlaceUIElementRoot(calendar,menuCommand);
        calendar.transform.localPosition = Vector3.zero;
    }
}

有了以上这段代码我们就可以在Hierarchy窗口中右击,然后UI->Calendar 创建日历组件

Unity中如何自主定义类 unity自定义组件_unity_03

public static class SpringGUIDefaultControls
{
    public static GameObject CreateCalendar( Resources resources )
    {
        //创建日历组件的详细代码..在Github中下载获取
    }
}

相信看过之前两篇博客的同学已经可以自己利用这种方式来创建经常使用的UI组件了。

1.2 创建日期拾取器

public class SpringGUIMenuOptions
{
    [MenuItem("GameObject/UI/DatePicker")]
    public static void AddDatePicker( MenuCommand menuCommand )
    {
        GameObject datePicker = SpringGUIDefaultControls.CreateDatePicker(GetStandardResources());
        PlaceUIElementRoot(datePicker,menuCommand);
        datePicker.transform.localPosition = Vector3.zero;
    }
}

public static class SpringGUIDefaultControls
{
     public static GameObject CreateDatePicker( Resources resources )
     {
        //GameObject calendar = CreateCalendar(resources);
        //在日期拾取器中我们会利用到上面创建的日历工具,所以这里直接调用方法创建即可。详细请看Github源码。
     }
}

有了以上代码,我们同理可在Hierarchy面板中创建日期拾取器工具。

2.日历和日期拾取器的代码逻辑

利用上面的方法我们可以轻松创建出UI组件,但是UI组件运行需要脚本来进行控制,下面我们讲解一下主要的逻辑。

2.1日历的逻辑

日期的获取我们直接使用System.DateTime来获取,我们只需要计算好每一页需要显示的42天的DateTime值,每一页12个月的DateTime值和每一页12个年份的DateTime值。利用DateTime.Today和DateTime.AddDays和DateTime.Months和DateTime.Years通过计算获取。
需要注意的就是42天的DateTime的获取,我们需要根据当月第一天星期几和当月一共多少天来计算出上个月的几天和下个月的几天的DateTime值。

public class CalendarData
{
    //计算出需要显示的42天的DateTime值
    public List<DateTime> Days( DateTime month )
    {
        List<DateTime> days = new List<DateTime>();
        DateTime firstDay = new DateTime(month.Year , month.Month , 1);
        DayOfWeek week = firstDay.DayOfWeek;
        int lastMonthDays = (int)week;
        if ( lastMonthDays.Equals(0) )
            lastMonthDays = 7;
        for ( int i = lastMonthDays ; i > 0 ; i-- )
            days.Add(firstDay.AddDays(-i));
        for ( int i = 0 ; i < 42 - lastMonthDays ; i++ )
            days.Add(firstDay.AddDays(i));
        return days;
    }
    //计算出12个月的DateTime值
    public List<DateTime> Months( DateTime year )
    {
        List<DateTime> months = new List<DateTime>();
        DateTime firstMonth = new DateTime(year.Year , 1 , 1);
        months.Add(firstMonth);
        for ( int i = 1 ; i < 12 ; i++ )
            months.Add(firstMonth.AddMonths(i));
        return months;
    }
    //计算出12个年份的DateTime值
    public List<DateTime> Years( DateTime year )
    {
        List<DateTime> years = new List<DateTime>();
        //前五年
        for ( int i = 5 ; i > 0 ; i-- )
            years.Add(year.AddYears(-i));
        //后六年
        for ( int i = 0 ; i < 7 ; i++ )
            years.Add(year.AddYears(i));
        return years;
    }
}

在Calendar类中主要写Calendar组件的UI刷新,包括上一个月、下一个月、上一年和下一年的按钮操作,以及点击每一天、每个月、每个年分触发的事件等。

public class Calendar : UIBehaviour
{
    //按钮事件,带有一个DateTime类型的UntiyEvent,使用方式和Button一样使AddListener(UnityAction<DateTime>);
    public class DayClickEvent : UnityEvent<DateTime>{}
    public class MonthClickEvent : UnityEvent<DateTime> { }
    public class YearClickEvent : UnityEvent<DateTime> { }

    public enum E_DisplayType
    {
        Standard,
        Chinese
    }
    //这个枚举控制UI是否中文显示
    public E_DisplayType DisplayType = E_DisplayType.Chinese;

    //获取组件

    //上个月
    //下个月

    //上一年
    //下一年

    //上12年
    //下12年

    //生成UI
    //刷新UI

    //具体查看源码
}

2.2日期拾取器逻辑

public class DatePicker : UIBehaviour
{
    //持有一个日历,通过监听日历点击来获取日期
    private Calendar _calendar = null;

    private DateTime _dateTime = DateTime.Today;
    public DateTime DateTime
    {
        get { return _dateTime; }
        set
        {
            _dateTime = value;
            //自动刷新日期
            refreshDateText();
        }
    }

    protected override void Awake()
    {
        //监听获取的日期,并利用属性方法刷新Text显示
        _calendar.onDayClick.AddListener(dateTime => { DateTime = dateTime; });
    }

    private void refreshDateText()
    {
        //根据Calendar.DisplayType和选取的日期,来刷新Text显示
    }
}

使用方法:

1.日历

1.1 新建一个Calendar
1.2 获取组件并监听事件
private void Start ()
{
    Calendar calendar = transform.FindChild("Calendar").GetComponent<Calendar>();
    calendar.onDayClick.AddListener(time => { Debug.Log(string.Format("今天是{0}年{1}月{2}日" , time.Year , time.Month , time.Day)); });
    calendar.onMonthClick.AddListener(time => { Debug.Log(string.Format("本月是{0}年{1}月" , time.Year , time.Month)); });
    calendar.onYearClick.AddListener(time => { Debug.Log(string.Format("今年是{0}年" , time.Year)); });
}
1.3 运行点击即可看到输出

Unity中如何自主定义类 unity自定义组件_游戏引擎_04

2.日期拾取器

2.1 新建一个DatePicker
2.2 运行即可拾取日期,其他脚本调用DatePicker.DateTime获取拾取的日期

后续拓展:

1.日历和日期拾取器的面板都可以自己再设计,在组件中可看到Template模板的UI,更改样式即可;
2.后续我们还会更新颜色拾取器和标记工具(类似于QQ截图的功能)可以做一些标注并导出数据。
3.后续也会直接重写部分源码以优化组件,或者是新建其他UI组件,类似的一些高级的Text组件等。

GitGub下载源码地址: GitHub - spr1ngd/UnityCodes: SpringGUI是对UGUI的拓展,提供十多种UI组件用于快速开发。