为什么要自定义日历?
在日常的工作中,很多时候的需求不是一个默认日历能够胜任的,虽然很多时候可以去GitHub上面搜索相关的库,但是总是会有一些局限性,这个时候就想到了自己来写一个日历控件,这样又方便还符合自己APP的主题,两全其美。
废话不多说,先上图:
需要使用哪些工具?
1、ViewPager肯定是首要的,因为我们的日历需要能够左右滑动切换
2、最最重要的当然是Calendar啦,它能够很好的帮助我们获取需要的时间
介绍一下Calendar的几个重要的方法
1、set方法:通过名字我们也知道这是一个赋值的方法,那么怎么使用呢?
val a = Calendar.getInstance()
//a.set(field:Int,value:Int) 参数一是我们需要赋值的类型 参数二是我们需要赋值的值
比方说我现在要把当前的日期设置为1号
a.set(Calendar.DATE,1) //这样就把日期改为了1号
其他的类推就行。
通过设置我们可以获得当月1号是星期几
val week = a.get(Calendar.DAY_OF_WEEK)
这样我们就知道从哪个位置开始啦
2、getActualMaximum:获取给定日历字段的可能最大值
我们需要获取当前月最大天数,如果不用这个方法,我们需要去判断当前月是大月还是小月,今年是闰年还是平年,有了这个方法就不需要啦
val a = Calendar.getInstance()
val days = a.getActualMaximum(Calendar.DATE)
3、add方法:添加
这个方法也是很实用的一个方法,比方说我们现在是1号我需要知道2号的时间戳,最笨的方法当然是拿之前的时间戳+24*3600,有了add方法就不需要了,我们只需要
a.add(Calendar.DATE, 1)
这样就把时间戳往后加了一天,是不是很方便。
Calendar里面还有一个同类的方法roll
a.roll(Calendar.DATE,1)两者都能往后一天
但是两个是有区别的
比方说现在是2018年1月31号
a.add(Calendar.DATE, 1)得出的会是2018年2月1号
而
a.roll(Calendar.DATE,1)得出的会是2018年1月1号
也就是说add会影响整个时间戳,而roll只会影响当前这个量级
现在我们知道了1号需要的位置和总天数,那么数据源就有了
val mDatas = ArrayList()
for (i in 1 until getWeekOfFirstDayInMonth()) {
mDatas.add(DatePickerBean2(0, 0))
}
val b = Calendar.getInstance()
b.timeInMillis = timeMillis.toLong() * 1000
b.set(Calendar.DATE, 1)
for (i in 0 until getDaysOfMonth(timeMillis)) { mDatas.add(DatePickerBean2((b.timeInMillis / 1000).toInt(), 0))
b.add(Calendar.DATE, 1)
}
一个简单的日历就有了,通过Calendar类,我们可以很方便的得到我们想要的数据
class DatePickerDialog2 : BaseActivity() {
private var timeMillis = 0
private var mViews = ArrayList()
private var pAdapter: MyAdapter? = null
private var isStart = 0
private var isEnd = 0
companion object {
const val REQUEST_CODE = 1718
fun show(context: Activity) {
val intent = Intent(context, DatePickerDialog2::class.java) context.startActivityForResult(intent, REQUEST_CODE)
}
}
override fun bindlayout(): Int = R.layout.fragment_date_picker2
override fun initListener() {
tvPre.setOnClickListener {
if (mPager.currentItem > 0) {
mPager.setCurrentItem(mPager.currentItem - 1, true)
}
}
tvNext.setOnClickListener {
mPager.setCurrentItem(mPager.currentItem + 1, true)
}
tvCancel.setOnClickListener { finish() }
tvConfirm.setOnClickListener {
if (isStart == 0) {
toast("请选择开始日期") return@setOnClickListener
}
if (isEnd == 0) {
toast("请选择结束日期")
return@setOnClickListener
}
val intent = Intent()
intent.putExtra("start", isStart)
intent.putExtra("end", isEnd)
setResult(Activity.RESULT_OK, intent)
finish()
}
}
override fun init() {
timeMillis = (Calendar.getInstance().timeInMillis / 1000).toInt() tvDate.bindText(TimeUtils.formatDate("yyyy年MM月", timeMillis.toString())) initAdapter()
mPager.addOnPageChangeListener(object :ViewPager.SimpleOnPageChangeListener() {
override fun onPageSelected(position: Int) { tvDate.bindText(TimeUtils.formatDate("yyyy年MM月",mViews[position].timeMillis.toString()))
if (position == mViews.size - 1) {
val a = Calendar.getInstance()
a.timeInMillis = timeMillis.toLong() * 1000
a.add(Calendar.MONTH, 1)
timeMillis = (a.timeInMillis / 1000).toInt()
initAdapter()
}
}
}) }
private fun initAdapter() {
val mDatas = ArrayList()
for (i in 1 until getWeekOfFirstDayInMonth()) {
mDatas.add(DatePickerBean2(0, 0))
}
val b = Calendar.getInstance()
b.timeInMillis = timeMillis.toLong() * 1000
b.set(Calendar.DATE, 1)
for (i in 0 until getDaysOfMonth(timeMillis)) { mDatas.add(DatePickerBean2((b.timeInMillis / 1000).toInt(), 0))
b.add(Calendar.DATE, 1)
}
val aadapter = DatePickerAdapter2(this@DatePickerDialog2, mDatas)
val contents = RecyclerView(this@DatePickerDialog2)
contents.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
contents.apply {
layoutManager = GridLayoutManager(this@DatePickerDialog2, 7) setHasFixedSize(true)
adapter = aadapter
}
aadapter.setOnItemClickListener {
when (mDatas[it].selectType) {
0 ->
{
if (isStart == 0) {
if (isEnd == 0 || mDatas[it].timeMillis < isEnd) {
mDatas[it].selectType = 1 isStart = mDatas[it].timeMillis
} else {
toast("开始日期不能在结束日期之后哦")
}
} else if (isEnd == 0) {
if (isStart == 0 || isStart < mDatas[it].timeMillis) {
mDatas[it].selectType = 2
isEnd = mDatas[it].timeMillis
} else {
toast("结束日期不能在开始日期之前哦")
}
}
}
1 -> {
mDatas[it].selectType = 0
isStart = 0
}
2 -> {
mDatas[it].selectType = 0
isEnd = 0
}
}
aadapter.refresh(mDatas).notifyItemChanged(it)
}
if (pAdapter == null) {
pAdapter = MyAdapter()
mViews.add(MyView(contents, timeMillis))
mPager.adapter = pAdapter
if (mPager.currentItem == mViews.size - 1) {
val a = Calendar.getInstance()
a.timeInMillis = timeMillis.toLong() * 1000
a.add(Calendar.MONTH, 1)
timeMillis = (a.timeInMillis / 1000).toInt()
initAdapter()
}
} else {
mViews.add(MyView(contents, timeMillis))
mPager.adapter.notifyDataSetChanged()
}
}
private inner class MyAdapter : PagerAdapter() {
override fun isViewFromObject(view: View?, obj: Any?): Boolean = view == obj
override fun getCount(): Int = mViews.size
override fun instantiateItem(container: ViewGroup, position: Int): Any { container.addView(mViews[position].view)
return mViews[position].view }
override fun destroyItem(container: ViewGroup, position: Int, `object`: Any?) { container.removeView(mViews[position].view)
}
}
private fun getWeekOfFirstDayInMonth(): Int {
val a = Calendar.getInstance()
a.timeInMillis = timeMillis.toLong() * 1000
a.set(Calendar.DATE, 1)
return a.get(Calendar.DAY_OF_WEEK)
}
data class MyView(val view: View, val timeMillis: Int)
private fun getDaysOfMonth(timeMillis: Int): Int {
val a = Calendar.getInstance()
a.timeInMillis = timeMillis.toLong() * 1000
return a.getActualMaximum(Calendar.DATE)
}
}