先看效果图:
主要代码
package com.example.flyimport 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.Dateclass JCalendarView(context: Context, attributeSet: AttributeSet) :FrameLayout(context, attributeSet) {private var lastTv: ImageView? = nullprivate var nextTv:ImageView? = nullprivate var dateTv: TextView? = nullprivate var nowTv:TextView? = nullprivate var calendarRv: RecyclerView? = nullprivate val addYear = 0private 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 = mAdapterinitData()nowTv!!.setOnClickListener { v: View? ->val date = Date()mCalendar.time = dateval datess = sdf.format(date)mAdapter.setSelectDate(Integer.valueOf(datess.substring(8)))initData()}nextTv!!.setOnClickListener { v: View? ->mCalendar.add(Calendar.MONTH, +1) //月份+1initData()}//“上一个”点击事件lastTv!!.setOnClickListener { v: View? ->mCalendar.add(Calendar.MONTH, -1) //月份-1initData()}}@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 Calendarcal.add(Calendar.MONTH, 0)cal[Calendar.DAY_OF_MONTH] = cal.getActualMaximum(Calendar.DAY_OF_MONTH)val preMonth = cal.timeif (!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 = 0private var mListener: OnItemClickListener? = nullfun setmListener(mListener: OnItemClickListener?) {this.mListener = mListener}@SuppressLint("NotifyDataSetChanged")fun submitList(list: List<Date>) {mList = listnotifyDataSetChanged()}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-13val 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() + 1holder.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 = postionnotifyDataSetChanged()}@SuppressLint("NotifyDataSetChanged")fun setSelectDate(day: Int) {mDay = daynotifyDataSetChanged()}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: TextViewvar layout: LinearLayoutinit {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"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><TextViewandroid: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" /><TextViewandroid: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" /><TextViewandroid: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" /><ImageViewandroid: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"/><ImageViewandroid: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><LinearLayoutandroid:id="@+id/weekLl"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="20dp"android:orientation="horizontal"><TextViewandroid: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" /><TextViewandroid: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" /><TextViewandroid: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" /><TextViewandroid: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" /><TextViewandroid: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" /><TextViewandroid: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" /><TextViewandroid: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.RecyclerViewandroid: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"><TextViewandroid: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>
欢迎大家指正不足的地方;