一,效果图
不带补签版本:
二,制作思路
使用切换图片背景颜色的方式,进行状态转换【灰色:已签到;蓝色:可签到;白色:未签到】
主要逻辑:
- 每次签到时保存一个签到日期,用于判断今日是否签到;
- 根据是否已签到显示UI界面,提示信息等;
- 未签到时,点击按钮,进行签到(保存签到日期,发放奖励,维护UI显示等);
- 另外,还需要进行新的一周签到开始的逻辑重置;
上述逻辑,基本上模拟了王者荣耀的签到面板功能了,下面我们开始实现吧。
三,场景搭建
Demo场景搭建如上图:(没有资源有点丑~)
- 制作一个签到按钮(一个Image,下面放了一个Image和一个Text)
- 复制六份(单独创建一个空物体,作为它们的父物体)
- 创建一个文本(随便放在哪里,显示提示信息用的)
四,代码实现
就是按上面说的实现的逻辑,代码中注释也写的很详细了,全部代码如下:
using System;
using UnityEngine;
using UnityEngine.UI;
public class SingInDemo : MonoBehaviour
{
// 签到按钮的父物体
public Transform WeekParent;
// 提示文字
public Text HintText;
// 上次签到时间 -- 和今天时间对比,确定是否今日已签到
private readonly string prefsLastCheckTime = "prefsLastCheckTime";
// 本周已签到几天 例:2 --> 表示周一,周二已签到
private readonly string prefsWeekAlreadyDay = "prefsWeekAlreadyDay";
// 今天周几
private int weekToday;
// 本周签到了几天
private int alreadyDay;
void Start()
{
//PlayerPrefs.DeleteAll();
weekToday = GetDateWeek(DateTime.Now.ToString());
AlreadyByWeek();
// 查看本周签到了几天了
alreadyDay = PlayerPrefs.GetInt(prefsWeekAlreadyDay);
for (int i = 0; i < WeekParent.childCount; i++)
{
GameObject go = WeekParent.GetChild(i).gameObject;
// 监听按钮点击
go.GetComponent<Button>().onClick.AddListener(() => { OnClickSingInBtn(go); });
// 标识是否已签到
bool isAlready = alreadyDay > i;
go.GetComponent<Image>().color = isAlready ? Color.gray : Color.white;
go.transform.GetChild(1).gameObject.SetActive(isAlready);
}
// 今天还没签到
if (!AlreadyByToDay())
{
WeekParent.GetChild(alreadyDay).GetComponent<Image>().color = Color.cyan;
}
// 显示提示信息
ShowHintText(alreadyDay);
}
// 点击签到按钮
private void OnClickSingInBtn(GameObject go)
{
// 点了星期 ?签到按钮
string week = go.name.Split('_')[1];
Debug.Log("点击了..." + go.name + "按钮, 是周" + week);
// 可签到
alreadyDay = PlayerPrefs.GetInt(prefsWeekAlreadyDay);
if (!AlreadyByToDay())
{
Debug.Log("签到成功,签到成功的是,是周" + week);
go.transform.GetChild(1).gameObject.SetActive(true);
go.transform.GetComponent<Image>().color = Color.gray;
PlayerPrefs.SetString(prefsLastCheckTime, DateTime.Now.ToString("d"));
PlayerPrefs.SetInt(prefsWeekAlreadyDay, ++alreadyDay);
// 显示提示信息
ShowHintText(alreadyDay);
Debug.Log("~~~~~~~~~~~~ 签到成功的奖励还没写哦 ~~~~~~~~~~~~");
}
else
{
Debug.Log("今日已签到,不能重复签到哦~");
}
}
/// <summary>
/// 本周是是否已签到 -- 计算上次签到时间 是不是在本周内
/// </summary>
void AlreadyByWeek()
{
if (!PlayerPrefs.HasKey(prefsLastCheckTime)) return;
// 本周周一
string startWeek = GetMondayDate(DateTime.Now).ToString("d");
// 上次签到时间的周一
DateTime dtmE = DateTime.Parse(PlayerPrefs.GetString(PlayerKey.SigninLastCheckTime.ToString()));
string lastWeek = GetMondayDate(dtmE).ToString("d");
// 上次签到周不是本周 && 今日未签到
if (startWeek != lastWeek && !AlreadyByToDay())
{
Debug.Log("新的一周开始,重置所有签到信息...");
PlayerPrefs.DeleteKey(prefsLastCheckTime);
PlayerPrefs.DeleteKey(prefsWeekAlreadyDay);
}
}
/// <summary>
/// 今天是否已签到
/// </summary>
/// <returns></returns>
bool AlreadyByToDay()
{
string today = DateTime.Now.ToString("d");
return PlayerPrefs.GetString(prefsLastCheckTime) == today;
}
/// <summary>
/// 返回传入日期是周几
/// </summary>
/// <param name="strYMD"></param>
/// <returns></returns>
int GetDateWeek(string strYMD)
{
int week = Convert.ToInt32(Convert.ToDateTime(strYMD).DayOfWeek);
// 0:表示是周日
return week != 0 ? week : 7;
}
// 提示文本
void ShowHintText(int alreadyDay)
{
if (!AlreadyByToDay())
{
HintText.text = "今日未签到, 本周已签到" + alreadyDay + " 天";
}
else
{
HintText.text = "今日已签到,本周已签: " + alreadyDay + " 天, 可补签" + (weekToday - alreadyDay) + " 天";;
}
}
/// <summary>
/// 计算某日起始日期(礼拜一的日期)
/// </summary>
/// <param name="someDate">该周中任意一天</param>
/// <returns>返回礼拜一日期,后面的具体时、分、秒和传入值相等</returns>
DateTime GetMondayDate(DateTime someDate)
{
int i = someDate.DayOfWeek - DayOfWeek.Monday;
if (i == -1) i = 6;// i值 > = 0 ,因为枚举原因,Sunday排在最前,此时Sunday-Monday=-1,必须+7=6。
TimeSpan ts = new TimeSpan(i, 0, 0, 0);
return someDate.Subtract(ts);
}
}
五,拓展补签版本
顺着上面的实现思路,很容易就是可以实现一个带补签的版本:
看下效果图:
其实就是把上面代码校验今天是否已签到
的地方修改为是否可补签
,然后添加一个补签逻辑就可以了。
场景搭建还是和上面一样,代码实现如下:
using System;
using UnityEngine;
using UnityEngine.UI;
public class SingInDemo : MonoBehaviour
{
// 签到按钮的父物体
public Transform WeekParent;
// 提示文字
public Text HintText;
// 上次签到时间 -- 和今天时间对比,确定是否今日已签到
private readonly string prefsLastCheckTime = "prefsLastCheckTime";
// 本周已签到几天 例:2 --> 表示周一,周二已签到
private readonly string prefsWeekAlreadyDay = "prefsWeekAlreadyDay";
// 今天周几
private int weekToday;
// 本周签到了几天
private int alreadyDay;
void Start()
{
//PlayerPrefs.DeleteAll();
weekToday = GetDateWeek(DateTime.Now.ToString());
AlreadyByWeek();
// 查看本周签到了几天了
alreadyDay = PlayerPrefs.GetInt(prefsWeekAlreadyDay);
for (int i = 0; i < WeekParent.childCount; i++)
{
GameObject go = WeekParent.GetChild(i).gameObject;
// 监听按钮点击
go.GetComponent<Button>().onClick.AddListener(() => { OnClickSingInBtn(go); });
// 标识是否已签到
bool isAlready = alreadyDay > i;
go.GetComponent<Image>().color = isAlready ? Color.gray : Color.white;
go.transform.GetChild(1).gameObject.SetActive(isAlready);
}
// 今天还没签到
if (weekToday - alreadyDay > 0) //(!AlreadyByToDay()) // todo...不可补签使用
{
WeekParent.GetChild(alreadyDay).GetComponent<Image>().color = Color.cyan;
}
// 显示提示信息
ShowHintText(alreadyDay);
}
// 点击签到按钮
private void OnClickSingInBtn(GameObject go)
{
// 点了星期 ?签到按钮
string week = go.name.Split('_')[1];
Debug.Log("点击了..." + go.name + "按钮, 是周" + week);
// 可签到
alreadyDay = PlayerPrefs.GetInt(prefsWeekAlreadyDay);
if (weekToday - alreadyDay > 0) //(!AlreadyByToDay()) // todo...不可补签使用
{
Debug.Log("签到成功,签到成功的是,是周" + week);
go.transform.GetChild(1).gameObject.SetActive(true);
go.transform.GetComponent<Image>().color = Color.gray;
PlayerPrefs.SetString(prefsLastCheckTime, DateTime.Now.ToString("d"));
PlayerPrefs.SetInt(prefsWeekAlreadyDay, ++alreadyDay);
// 显示提示信息
ShowHintText(alreadyDay);
#region 补签逻辑 -- todo..不需补签直接删掉即可
if (AlreadyByToDay())
{
Debug.Log("--- 补签成功, 这是本周第" + alreadyDay + "次签到 ---");
}
else
{
Debug.Log("+++ 签到成功, 这是本周第" + alreadyDay + "次签到 +++");
}
// 可补签~,添加可点击标识
if (weekToday - alreadyDay > 0)
{
WeekParent.GetChild(alreadyDay).GetComponent<Image>().color = Color.cyan;
}
#endregion
Debug.Log("~~~~~~~~~~~~ 签到成功的奖励还没写哦 ~~~~~~~~~~~~");
}
else
{
Debug.Log("今日已签到,不能重复签到哦~");
}
}
/// <summary>
/// 本周是是否已签到 -- 计算上次签到时间 是不是在本周内
/// </summary>
void AlreadyByWeek()
{
if (!PlayerPrefs.HasKey(prefsLastCheckTime)) return;
// 本周周一
string startWeek = GetMondayDate(DateTime.Now).ToString("d");
// 上次签到时间的周一
DateTime dtmE = DateTime.Parse(PlayerPrefs.GetString(PlayerKey.SigninLastCheckTime.ToString()));
string lastWeek = GetMondayDate(dtmE).ToString("d");
// 上次签到周不是本周 && 今日未签到
if (startWeek != lastWeek && !AlreadyByToDay())
{
Debug.Log("新的一周开始,重置所有签到信息...");
PlayerPrefs.DeleteKey(prefsLastCheckTime);
PlayerPrefs.DeleteKey(prefsWeekAlreadyDay);
}
}
/// <summary>
/// 今天是否已签到
/// </summary>
/// <returns></returns>
bool AlreadyByToDay()
{
string today = DateTime.Now.ToString("d");
return PlayerPrefs.GetString(prefsLastCheckTime) == today;
}
/// <summary>
/// 返回传入日期是周几
/// </summary>
/// <param name="strYMD"></param>
/// <returns></returns>
int GetDateWeek(string strYMD)
{
int week = Convert.ToInt32(Convert.ToDateTime(strYMD).DayOfWeek);
// 0:表示是周日
return week != 0 ? week : 7;
}
// 提示文本
void ShowHintText(int alreadyDay)
{
if (!AlreadyByToDay())
{
HintText.text = "今日未签到, 本周已签到" + alreadyDay + " 天";
}
else
{
HintText.text = "今日已签到,本周已签: " + alreadyDay + " 天, 可补签" + (weekToday - alreadyDay) + " 天";;
}
}
/// <summary>
/// 计算某日起始日期(礼拜一的日期)
/// </summary>
/// <param name="someDate">该周中任意一天</param>
/// <returns>返回礼拜一日期,后面的具体时、分、秒和传入值相等</returns>
DateTime GetMondayDate(DateTime someDate)
{
int i = someDate.DayOfWeek - DayOfWeek.Monday;
if (i == -1) i = 6;// i值 > = 0 ,因为枚举原因,Sunday排在最前,此时Sunday-Monday=-1,必须+7=6。
TimeSpan ts = new TimeSpan(i, 0, 0, 0);
return someDate.Subtract(ts);
}
}