使用RecyclerView自定义日历功能实现记录

创建日期对象

// valid 代表是否是有效数据
class Day(var valid  : Boolean, var year : Int ,var month : Int ,var day : Int)

 xml布局文件

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/black"
    android:orientation="vertical"
    android:paddingHorizontal="@dimen/dp_20">    

<com.hjq.shape.layout.ShapeFrameLayout
        android:id="@+id/shapeFrameLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/dp_10"
        android:orientation="horizontal"
        android:paddingHorizontal="@dimen/dp_20"
        app:shape_radius="@dimen/dp_100"
        app:shape_solidColor="#C3FF44">

        <com.hjq.shape.view.ShapeImageView
            android:id="@+id/left"
            android:layout_width="@dimen/dp_40"
            android:layout_height="@dimen/dp_40"
            android:layout_gravity="center_vertical"
            android:padding="@dimen/dp_6"
            android:scaleX="-1"
            android:src="@mipmap/my_left_arrow"
            app:shape_radius="@dimen/dp_100"
            app:shape_solidColor="@color/black" />

        <TextView
            android:id="@+id/monthTv"
            android:layout_width="match_parent"
            android:layout_height="@dimen/dp_50"
            android:gravity="center"
            android:text="4月"
            android:textColor="@color/black"
            android:textSize="@dimen/sp_20"
            android:textStyle="bold" />

        <com.hjq.shape.view.ShapeImageView
            android:id="@+id/right"
            android:layout_width="@dimen/dp_40"
            android:layout_height="@dimen/dp_40"
            android:layout_gravity="end|center_vertical"
            android:padding="@dimen/dp_6"
            android:src="@mipmap/my_left_arrow"
            app:shape_radius="@dimen/dp_100"
            app:shape_solidColor="@color/black" />
    </com.hjq.shape.layout.ShapeFrameLayout>


    <com.hjq.shape.layout.ShapeLinearLayout
        android:id="@+id/shapeLinearLayout2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/dp_10"
        android:orientation="vertical"
        android:paddingHorizontal="@dimen/dp_10"
        android:paddingTop="@dimen/dp_10"
        android:paddingBottom="@dimen/dp_20"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/shapeFrameLayout"
        app:shape_radius="@dimen/dp_30"
        app:shape_solidColor="#FFCFE5">

        <com.hjq.shape.layout.ShapeLinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:paddingVertical="@dimen/dp_5"
            app:shape_radius="@dimen/dp_100"
            app:shape_solidColor="@color/white">

            <TextView
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center"
                android:text="日"
                android:textColor="@color/black"
                android:textSize="@dimen/sp_15"
                android:textStyle="bold" />

            <TextView
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center"
                android:text="一"
                android:textColor="@color/black"
                android:textSize="@dimen/sp_15"
                android:textStyle="bold" />

            <TextView
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center"
                android:text="二"
                android:textColor="@color/black"
                android:textSize="@dimen/sp_15"
                android:textStyle="bold" />

            <TextView
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center"
                android:text="三"
                android:textColor="@color/black"
                android:textSize="@dimen/sp_15"
                android:textStyle="bold" />

            <TextView
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center"
                android:text="四"
                android:textColor="@color/black"
                android:textSize="@dimen/sp_15"
                android:textStyle="bold" />

            <TextView
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center"
                android:text="五"
                android:textColor="@color/black"
                android:textSize="@dimen/sp_15"
                android:textStyle="bold" />

            <TextView
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center"
                android:text="六"
                android:textColor="@color/black"
                android:textSize="@dimen/sp_15"
                android:textStyle="bold" />
        </com.hjq.shape.layout.ShapeLinearLayout>

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/dayRecycleView1"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center_horizontal"
            android:gravity="center" />
    </com.hjq.shape.layout.ShapeLinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

控件来自于控件库 ,用普通的控件也行GitHub - getActivity/ShapeView: Shape 支持在布局中直接定义啦,支持设置阴影,文字渐变色,状态选择器

在drawable中创建选中日期的样式文件 layout_onclick_style.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <!-- 设置圆角半径 -->
    <corners android:radius="15dp" />

    <!-- 设置边框宽度和颜色 -->
    <stroke
        android:width="1dp"
        android:color="#00FFEE" /> <!-- 设置边框颜色 -->
</shape>

在drawable中创建未选中日期的样式文件 layout_unclick_style.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <!-- 设置圆角半径 -->
    <corners android:radius="15dp" />

    <!-- 设置边框宽度和颜色 -->
    <stroke
        android:width="1dp"
        android:color="@color/white" /> <!-- 设置边框颜色 -->
</shape>

在drawable中创建今日日期的样式文件 layout_today_style.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <!-- 设置圆角半径 -->
    <corners android:radius="15dp" />

    <solid android:color="#00FFEE"/>
</shape>

创建适配器子项布局day_item_layout.xml 

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="@dimen/dp_10">

    <FrameLayout
        android:layout_width="@dimen/dp_30"
        android:layout_height="@dimen/dp_30"
        android:layout_gravity="center"
        android:id="@+id/frameLayout"
        android:background="@drawable/layout_unclick_style">

        <TextView
            android:id="@+id/timeTv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center"
            android:text="1"
            android:gravity="center"
            android:textSize="@dimen/sp_13"
            android:textColor="@color/white"/>

    </FrameLayout>

</FrameLayout>

创建适配器文件 DayAdapter.kt

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bubblesprite.flow.R
import com.bubblesprite.flow.databinding.DayItemLayoutBinding
import com.bubblesprite.flow.entity.Day
import com.bubblesprite.flow.utils.FlowUtils
import java.util.Calendar
import java.util.concurrent.Flow

class DayAdapter(val context: Context, var DayList: List<Day> ) :
    RecyclerView.Adapter<DayAdapter.ViewHolder>() {

    var onClickIndex = -1

    interface itemOnClickListener{
        fun setItemOnClickListener(timeInMillis : Long)
    }

    private var listener: itemOnClickListener? = null

    fun setItemOnClickListener(listener: itemOnClickListener) {
        this.listener = listener
    }

    inner class ViewHolder(binding: DayItemLayoutBinding) : RecyclerView.ViewHolder(binding.root) {
        val frameLayout = binding.frameLayout
        val timeTv = binding.timeTv
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding =
            DayItemLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return ViewHolder(binding)
    }


    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val day = DayList[position]
        if (day.valid) {  //有效数据

            holder.timeTv.text = day.day.toString()

            val (year,month,today) = getCurrentDate()
            if (onClickIndex == position){
                holder.frameLayout.background = context.getDrawable(R.drawable.layout_onclick_style)
                holder.timeTv.setTextColor( context.getResources().getColor(R.color.color_00FFEE))
            }else{
                holder.frameLayout.background = context.getDrawable(R.drawable.layout_unclick_style)
                holder.timeTv.setTextColor( context.getResources().getColor(R.color.white))
            }
            if (day.year == year && day.month == month && day.day == today){
                //如果是今天
                holder.frameLayout.background = context.getDrawable(R.drawable.layout_today_style)
                holder.timeTv.setTextColor( context.getResources().getColor(R.color.white))
            }
            holder.frameLayout.setOnClickListener {
                onClickIndex = position
                notifyDataSetChanged()

                listener!!.setItemOnClickListener(getTimestampAtMidnight(day.year,day.month,day.day))

            }
        } else {
            holder.frameLayout.background = null
            holder.timeTv.visibility = View.GONE
        }
    }
    fun getCurrentDate(): Triple<Int, Int, Int> {
         // 创建 Calendar 对象并获取当前时间
        val calendar = Calendar.getInstance()

        // 获取当前的年、月、日
        val year = calendar.get(Calendar.YEAR)
        val month = calendar.get(Calendar.MONTH) + 1 // 月份从 0 开始,因此需要加 1
        val day = calendar.get(Calendar.DAY_OF_MONTH)

        // 返回年、月、日的数字
       return Triple(year, month, day)
    }

    //获取日期的时间戳
    fun getTimestampAtMidnight(year: Int, month: Int, dayOfMonth: Int): Long {
        val calendar = Calendar.getInstance(TimeZone.getDefault())
        calendar.set(Calendar.YEAR, year)
        calendar.set(Calendar.MONTH, month - 1) // 注意:Java Calendar月份是从0开始的
        calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth)
        calendar.set(Calendar.HOUR_OF_DAY, 0)
        calendar.set(Calendar.MINUTE, 0)
        calendar.set(Calendar.SECOND, 0)
        calendar.set(Calendar.MILLISECOND, 0)

        return calendar.timeInMillis
    }
    override fun getItemCount() = DayList.size

 具体功能实现

创建全局变量

    var thisYear = 0
    var thisMonth = 0

 创建方法

    fun initAdapter(year: Int, month: Int) {

        val (daysInMonth, firstDayOfWeek) = getMonthDetails(year, month)

        val newDayList = ArrayList<Day>()
        if (firstDayOfWeek < 7) {
            for (i in 0 until firstDayOfWeek) {
                newDayList.add(Day(false, 0, 0, 0))
            }
        }

        for (i in 1..daysInMonth) {
            newDayList.add(Day(true, year, month, i))
        }
        binding.dayRecycleView1.layoutManager = GridLayoutManager(requireContext(), 7)
        val adapter = DayAdapter(requireContext(), newDayList)
        adapter.setItemOnClickListener(this)
        binding.dayRecycleView1.adapter = adapter

    }

    fun getMonthDetails(year: Int, month: Int): Pair<Int, Int> {
        val calendar = Calendar.getInstance()
        calendar.set(year, month - 1, 1) // 注意月份从0开始

        // 获取该月的天数
        val daysInMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH)

        // 获取该月第一天的星期数,1表示星期日,2表示星期一,以此类推
        val firstDayOfWeek = calendar.get(Calendar.DAY_OF_WEEK)

        return Pair(daysInMonth, firstDayOfWeek-1)
    }
fun getCurrentDate(): Triple<Int, Int, Int> {
        // 创建 Calendar 对象并获取当前时间
        val calendar = Calendar.getInstance()

        // 获取当前的年、月、日
        val year = calendar.get(Calendar.YEAR)
        val month = calendar.get(Calendar.MONTH) + 1 // 月份从 0 开始,因此需要加 1
        val day = calendar.get(Calendar.DAY_OF_MONTH)

        // 返回年、月、日的数字
        return Triple(year, month, day)
    }

onCreate()方法

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val (thisYear,thisMonth,today) = getCurrentDate()
        binding.monthTv.text = "$thisMonth 月"
        this.thisYear = thisYear
        this.thisMonth = thisMonth

        initAdapter(thisYear,thisMonth)


        binding.left.setOnClickListener {
            if (it.isVisible){
                thisMonth-=1
                if (thisMonth-1 == 0){
                    binding.left.visibility = View.INVISIBLE
                }
                binding.monthTv.text = "$thisMonth 月"
                binding.right.visibility = View.VISIBLE
                initAdapter(thisYear,thisMonth)
            }

        }
        binding.right.setOnClickListener {
            if (it.isVisible){
                thisMonth+=1
                if (thisMonth+1 == 13){
                    binding.right.visibility = View.INVISIBLE
                }
                binding.monthTv.text = "$thisMonth 月"
                binding.left.visibility = View.VISIBLE
                initAdapter(thisYear,thisMonth)
            }
        }
    }

使用了ViewBinding来绑定控件,不会的自己去学

日期点击事件的回调

//让你的类实现适配的itemOnClickListener接口
class Tab1Fragment : BaseFragment(),
    DayAdapter.itemOnClickListener{
        
。。。

//实现这个方法:
override fun setItemOnClickListener(timeInMillis : Long) {
        //具体的点击事件逻辑
    }

}

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小趴菜8227

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值