為什么要自定義日歷?
在日常的工作中,很多時候的需求不是一個默認日歷能夠勝任的,雖然很多時候可以去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)
}
}