先看效果图:
主要代码
package com.example.fly
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
class JCalendarView(context: Context, attributeSet: AttributeSet) :
FrameLayout(context, attributeSet) {
private var lastTv: ImageView? = null
private var nextTv:ImageView? = null
private var dateTv: TextView? = null
private var nowTv:TextView? = null
private var calendarRv: RecyclerView? = null
private val addYear = 0
private var mAdapter: CalendarAdapter=CalendarAdapter()
@SuppressLint("SimpleDateFormat")
private val sdf = SimpleDateFormat("yyyy-MM-dd") //日期格式化
private val mCalendar = Calendar.getInstance() //日历控件初始化
init {
initView(context)
}
private fun initView(context: Context) {
val inflater = LayoutInflater.from(context)
inflater.inflate(R.layout.layout_calendar, this)
lastTv = findViewById(R.id.lastTv)
nextTv = findViewById(R.id.nextTv)
dateTv = findViewById(R.id.dateTv)
calendarRv = findViewById(R.id.recyclerView)
nowTv = findViewById(R.id.tv_now)
calendarRv!!.layoutManager = GridLayoutManager(context, 7)
calendarRv!!.adapter = mAdapter
initData()
nowTv!!.setOnClickListener { v: View? ->
val date = Date()
mCalendar.time = date
val datess = sdf.format(date)
mAdapter.setSelectDate(Integer.valueOf(datess.substring(8)))
initData()
}
nextTv!!.setOnClickListener { v: View? ->
mCalendar.add(Calendar.MONTH, +1) //月份+1
initData()
}
//“上一个”点击事件
lastTv!!.setOnClickListener { v: View? ->
mCalendar.add(Calendar.MONTH, -1) //月份-1
initData()
}
}
@SuppressLint("SetTextI18n")
private fun initData() {
val datess = sdf.format(mCalendar.time)
dateTv!!.text ="${datess.substring(0, 4)} | ${datess.substring(5, 7)} . ${datess.substring(8) }"
val cells = ArrayList<Date>()
val calendar = mCalendar.clone() as Calendar //克隆日历对象
calendar[Calendar.DAY_OF_MONTH] = 1 //置于当月第一天;
val prevDays = calendar[Calendar.DAY_OF_WEEK] - 1 //获取上个月最后一天是星期几
calendar.add(Calendar.DAY_OF_MONTH, -prevDays) //第一天
// //获取每月有几周
// int actualMaximum = calendar.getActualMaximum(Calendar.WEEK_OF_MONTH);
// int maxCount = actualMaximum * 7; //设置每个月最大天数
//循环存入集合中
while (cells.size < 35) {
cells.add(calendar.time)
calendar.add(Calendar.DAY_OF_MONTH, 1) //日期+1
}
//判断当月的最后一天是否在集合里面
val cal = mCalendar.clone() as Calendar
cal.add(Calendar.MONTH, 0)
cal[Calendar.DAY_OF_MONTH] = cal.getActualMaximum(Calendar.DAY_OF_MONTH)
val preMonth = cal.time
if (!cells.contains(preMonth)) {
for (i in 0..6) {
cells.add(calendar.time)
calendar.add(Calendar.DAY_OF_MONTH, 1)
}
}
mAdapter.submitList(cells)
mAdapter.setmListener(object : CalendarAdapter.OnItemClickListener {
override fun onItemClick(v: View?, position: Int, data: String?) {
dateTv!!.text ="${data!!.substring(0, 4)} | ${data.substring(5, 7)} . ${data.substring(8) }"
}
})
}
}
class CalendarAdapter : RecyclerView.Adapter<CalendarAdapter.ViewHolder>() {
private var mList: List<Date> = ArrayList()
private var mSelectPosition = -1
// 创建一个接口来处理点击事件
interface OnItemClickListener {
fun onItemClick(v: View?, position: Int, data: String?)
}
private var mDay = 0
private var mListener: OnItemClickListener? = null
fun setmListener(mListener: OnItemClickListener?) {
this.mListener = mListener
}
@SuppressLint("NotifyDataSetChanged")
fun submitList(list: List<Date>) {
mList = list
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.item_calendar, parent, false)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
@SuppressLint("SimpleDateFormat")
val mDate = SimpleDateFormat("yyyy-MM-dd").format(mList[position])
//2023-11-13
val day = mDate.substring(8).toInt()
val month = mDate.substring(5, 7).toInt()
val year = mDate.substring(0, 4).toInt()
var isTheSameMonth = false //是否与当前月份相同
if (month == getNowMonth()) { //月份相同
isTheSameMonth = true
}
//若显示的日期月份与当前月份相同,则设置字体颜色是黑色
if (isTheSameMonth) {
holder.itemTv.setTextColor(Color.parseColor("#333333"))
} else {
holder.itemTv.setTextColor(Color.parseColor("#999999"))
}
if (day == 1) {
if (month == getNowMonth()) {
holder.itemTv.setText(getNowMonth().toString() + "月")
} else {
val months: Int = getNowMonth() + 1
holder.itemTv.text = if (months > 12) 1.toString() + "月" else months.toString() + "月"
}
holder.itemTv.setTextColor(Color.parseColor("#E71421"))
} else {
holder.itemTv.text = day.toString()
}
//设置当前日期字体为红色
if (getNowDay() == day && getNowMonth() == month && getNowYear() == year) {
holder.itemTv.setTextColor(Color.parseColor("#E71421"))
holder.layout.setBackgroundResource(R.drawable.shape_ffe2e1_rounded_20dp)
} else {
holder.layout.setBackgroundColor(Color.WHITE)
}
if (position == mSelectPosition) {
holder.itemTv.setTextColor(Color.parseColor("#ffffff"))
holder.layout.setBackgroundResource(R.drawable.shape_e71421_rounded_20dp)
}
if (day == mDay) {
holder.itemTv.setTextColor(Color.parseColor("#ffffff"))
holder.layout.setBackgroundResource(R.drawable.shape_e71421_rounded_20dp)
}
holder.layout.setOnClickListener { v: View? ->
// setSelectPostion(position);
setSelectDate(day)
mListener?.onItemClick(v, position, mDate)
}
}
override fun getItemCount(): Int {
return mList.size
}
@SuppressLint("NotifyDataSetChanged")
fun setSelectPostion(postion: Int) {
mSelectPosition = postion
notifyDataSetChanged()
}
@SuppressLint("NotifyDataSetChanged")
fun setSelectDate(day: Int) {
mDay = day
notifyDataSetChanged()
}
private fun getNowYear(): Int {
val calendar = Calendar.getInstance()
return calendar[Calendar.YEAR]
}
private fun getNowMonth(): Int {
val calendar = Calendar.getInstance()
return calendar[Calendar.MONTH] + 1
}
private fun getNowDay(): Int {
val calendar = Calendar.getInstance()
return calendar[Calendar.DAY_OF_MONTH]
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var itemTv: TextView
var layout: LinearLayout
init {
itemTv = itemView.findViewById(R.id.itemTv)
layout = itemView.findViewById(R.id.llayout)
}
}
}
布局文件
1、layout_calendar:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<TextView
android:id="@+id/dateTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="2022年11月"
android:layout_gravity="center"
android:textColor="#333"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_now"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:text="回到今天"
android:textColor="#999"
android:layout_gravity="center"
android:layout_marginStart="24dp"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical"
android:textColor="#999"
android:layout_gravity="center"
android:layout_marginStart="24dp"
android:textSize="14sp"
android:textStyle="bold" />
<ImageView
android:id="@+id/lastTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/icon_gengduo"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:rotation="180"
android:layout_marginEnd="8dp"
/>
<ImageView
android:id="@+id/nextTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/icon_gengduo"
android:paddingEnd="16dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
/>
</LinearLayout>
<LinearLayout
android:id="@+id/weekLl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:orientation="horizontal">
<TextView
android:id="@+id/Tv1"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_weight="1"
android:gravity="center"
android:text="日"
android:textColor="#999"
android:textSize="14sp" />
<TextView
android:id="@+id/Tv2"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_weight="1"
android:gravity="center"
android:text="一"
android:textColor="#999"
android:textSize="14sp" />
<TextView
android:id="@+id/Tv3"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_weight="1"
android:gravity="center"
android:text="二"
android:textColor="#999"
android:textSize="14sp" />
<TextView
android:id="@+id/Tv4"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_weight="1"
android:gravity="center"
android:text="三"
android:textColor="#999"
android:textSize="14sp" />
<TextView
android:id="@+id/Tv5"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_weight="1"
android:gravity="center"
android:text="四"
android:textColor="#999"
android:textSize="14sp" />
<TextView
android:id="@+id/Tv6"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_weight="1"
android:gravity="center"
android:text="五"
android:textColor="#999"
android:textSize="14sp" />
<TextView
android:id="@+id/Tv7"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_weight="1"
android:gravity="center"
android:text="六"
android:textColor="#999"
android:textSize="14sp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center" />
</LinearLayout>
2、item_calendar
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/llayout"
android:layout_width="40dp"
android:layout_height="40dp"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/itemTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="1"
android:textColor="#999"
android:textSize="14sp" />
</LinearLayout>
3、shape:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#e71421"/>
<corners android:radius="20dp"/>
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="20dp" />
<solid android:color="#ffe2e1" />
</shape>
欢迎大家指正不足的地方;