sy007 / CalendarView

一款强大的Android日历控件
85 stars 17 forks source link

能否额外支持加一个footView #14

Closed zhongcg closed 1 year ago

zhongcg commented 1 year ago

日历(mothView)下方想添加个列表,并跟随日历左右滑动。

sy007 commented 1 year ago

日历(mothView)下方想添加个列表,并跟随日历左右滑动。

可以的,最快下周加好。

zhongcg commented 1 year ago

大佬牛逼

sy007 commented 1 year ago

@zhongcg 你好,calendar-view 1.2.0版本支持了脚布局,请参考simple中SingleHorizontalActivity的写法

zhongcg commented 1 year ago

谢谢大佬,左右已经没问题,还有个问题是如何再实现上下滑动。因为我的footview是一个列表,用来展示当前月的所有节日。 滑动的话不能带上日历一起上下滑动,这个就比较蛋疼了

sy007 commented 1 year ago

谢谢大佬,左右已经没问题,还有个问题是如何再实现上下滑动。因为我的footview是一个列表,用来展示当前月的所有节日。 滑动的话不能带上日历一起上下滑动,这个就比较蛋疼了

@zhongcg 你好,这个属于业务上的个性化需求,不在日历库的范围内了。你可以看看CoordinatorLayout+RecyclerView。和NestedScrollView嵌套RecyclerView,这两种方案。后续有空可以考虑demo中加这个场景演示。

zhongcg commented 1 year ago

footview,多行超出屏幕的情况,在滑动到6行的月份时会展示不全。布局就是简单的linearlayout套n个textview, 还有外层嵌套了一个NestedScrollView

zhongcg commented 1 year ago

heightMode = HeightMode.DYNAMIC 的情况就会出现了。。 footerView会被截取掉日历一行的高度

zhongcg commented 1 year ago

还有个问题 不知道为什么设置成我这里heightMode = HeightMode.FIXED 没有效果。

zhongcg commented 1 year ago

footerView不支持动态高度。要是设计上的问题无法支持就只能把列表分离出去,翻页后再更新了,不跟随左右滑动了

sy007 commented 1 year ago

NestedScrollView

没有效果指的是什么意思,麻烦把遇到的问题列下。

zhongcg commented 1 year ago

第一个问题 private fun CalendarConfig.getAndFixHeightMode(): HeightMode { if (startCalendarDay.day != startCalendarDay.firstDayOfMonth || endCalendarDay.day != endCalendarDay.lastDayOfMonth) { return HeightMode.DYNAMIC } return heightMode } 这个方法导致设置FIxed无效,不明白这里的逻辑。

第二个问题就是FootView是个列表情况,每个月的底部列表数量不同,滑动后footview高度不足以把列表展示全

sy007 commented 1 year ago

第一个问题麻烦发下设置的参数。第二个问题不是日历控件的问题吧,你可以不用日历控件试试NestedScrollView嵌套RecyclerView+LinearLayout(多个TextView)。

zhongcg commented 1 year ago
        cvSingleCalendarView.apply {

            val startCalendar = Calendar.getInstance().apply {
                set(Calendar.YEAR, 1900)
                set(Calendar.DAY_OF_MONTH, getActualMinimum(Calendar.DAY_OF_MONTH))
                set(Calendar.MONTH, getActualMinimum(Calendar.MONTH))
            }
            val endCalendar = Calendar.getInstance().apply {
                set(Calendar.YEAR, 2100)
                set(Calendar.MONTH, getActualMaximum(Calendar.MONTH))
            }
            //初始化日历展示范围和样式
            val calendarConfig = CalendarConfig(startCalendar, endCalendar).apply {
                //横向滑动
                orientation = RecyclerView.HORIZONTAL
                //ViewPager滚动模式
                scrollMode = ScrollMode.PAGE
                //固定6行高度
                heightMode = HeightMode.FIXED
                //月份视图上展示额外日期
                isDisplayExtraDay = true
            }
zhongcg commented 1 year ago

写到外部是没有问题,把列表写到footview里是觉得一起滑动的效果会好一点,就跟华为日历效果一样,跟随滑动的效果。

sy007 commented 1 year ago
        cvSingleCalendarView.apply {

            val startCalendar = Calendar.getInstance().apply {
                set(Calendar.YEAR, 1900)
                set(Calendar.DAY_OF_MONTH, getActualMinimum(Calendar.DAY_OF_MONTH))
                set(Calendar.MONTH, getActualMinimum(Calendar.MONTH))
            }
            val endCalendar = Calendar.getInstance().apply {
                set(Calendar.YEAR, 2100)
                set(Calendar.MONTH, getActualMaximum(Calendar.MONTH))
            }
            //初始化日历展示范围和样式
            val calendarConfig = CalendarConfig(startCalendar, endCalendar).apply {
                //横向滑动
                orientation = RecyclerView.HORIZONTAL
                //ViewPager滚动模式
                scrollMode = ScrollMode.PAGE
                //固定6行高度
                heightMode = HeightMode.FIXED
                //月份视图上展示额外日期
                isDisplayExtraDay = true
            }

要开启FIXED模式,你必须将你的startCalendar的日期设置为该月份的第一天,即1号;将endCalendar的日期设置为该月份的最后一天。不然空间内部会强制改为DYNAMIC模式。你创建的endCalendar,只设置了年和月,日期还是今天的。如果日期设置为该月份的最后一天,可以使用 getActualMaximum(Calendar.DAY_OF_MONTH)

zhongcg commented 1 year ago

大佬运行一下这段代码你左右滑动一下就理解我说footview的问题了,不知道这个问题能否解决。 recycleview的会高度越来越小。

import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.os.Bundle import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.sy007.calendar. import com.sy007.calendar.databinding.ActivitySingleHorizontalBinding import com.sy007.calendar.entity.CalendarDay import com.sy007.calendar.simple.BaseActivity import com.sy007.calendar.simple.utils.LunarCalendar import java.util.

class SingleHorizontalActivity : BaseActivity() {

private var selectedDay: CalendarDay? = null
private lateinit var binding: ActivitySingleHorizontalBinding
private lateinit var tvCurrentSelectedDate: TextView
private var footerData = mutableMapOf<CalendarDay, MutableList<Int>>()

init {

    val calendar = Calendar.getInstance()
    calendar.set(1900, Calendar.JANUARY, 1)

    while (calendar.get(Calendar.YEAR) == 1900) {
        val list = mutableListOf<Int>()
        for (index in 1..Random().nextInt(10)) {
            list.add(index)
        }
        footerData[CalendarDay(calendar)] = list

        calendar.add(Calendar.MONTH, 1)
    }
}

companion object {
    private const val TAG = "SingleHorizontalActivity"
    fun start(context: Context) {
        val intent = Intent(context, SingleHorizontalActivity::class.java)
        context.startActivity(intent)
    }
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivitySingleHorizontalBinding.inflate(LayoutInflater.from(this))
    setContentView(binding.root)
    tvCurrentSelectedDate = binding.layoutCurrentSingleSelectContainer.tvCurrentSelectedDate
    setTitle("单选横向滑动(ViewPager滑动模式)")
    //初始化节日
    LunarCalendar.init(this@SingleHorizontalActivity)
    binding.apply {
        cvSingleCalendarView.apply {
            val startCalendar = Calendar.getInstance()
            startCalendar.set(1900, Calendar.JANUARY, 1)

            val endCalendar = Calendar.getInstance().apply {
                add(Calendar.MONTH, 10)
                set(Calendar.DAY_OF_MONTH, getActualMaximum(Calendar.DAY_OF_MONTH))
            }
            //初始化日历展示范围和样式
            val calendarConfig = CalendarConfig(startCalendar, endCalendar).apply {
                //横向滑动
                orientation = RecyclerView.HORIZONTAL
                //ViewPager滚动模式
                scrollMode = ScrollMode.PAGE
                //固定6行高度
                heightMode = HeightMode.FIXED
                //月份视图上展示额外日期
                isDisplayExtraDay = true
            }
            headerViewBinder = object : MonthHeaderViewBinder<View>() {
                override fun create(parent: ViewGroup): View {
                    return LayoutInflater.from(parent.context).inflate(
                        R.layout.item_header_view,
                        parent,
                        false
                    )

                }

                override fun onBind(view: View, calendarDay: CalendarDay) {
                    view.findViewById<TextView>(R.id.tv_header_title).text =
                        "header:${calendarDay.formatDate("yyyy-MM-dd")}"
                }
            }
            monthViewBinder = object : MonthViewBinder<SingleMonthViewSimple2> {
                override fun create(parent: ViewGroup): SingleMonthViewSimple2 {
                    return LayoutInflater.from(parent.context).inflate(
                        R.layout.layout_single_month_view_simple2,
                        parent,
                        false
                    ) as SingleMonthViewSimple2
                }

                override fun onBind(view: SingleMonthViewSimple2, calendarDay: CalendarDay) {
                    view.apply {
                        //设置选中的日期
                        selected = selectedDay
                        onSelectedListener = object : OnSelectedListener {
                            override fun onSelected(selected: CalendarDay) {
                                selectedDay = selected
                                //点击日期后滑动到指定日期
                                binding.cvSingleCalendarView.smoothScrollToMonth(selected)
                                tvCurrentSelectedDate.text = selected.formatDate("yyyy-MM-dd")
                            }
                        }
                    }
                }
            }
            footerViewBinder = object : MonthFooterViewBinder<View> {
                override fun create(parent: ViewGroup): View {
                    return LayoutInflater.from(parent.context).inflate(
                        R.layout.item_footer_view,
                        parent,
                        false
                    )
                }

                override fun onBind(view: View, calendarDay: CalendarDay) {
                    val rv = view.findViewById<RecyclerView>(R.id.rv)
                    rv.adapter = MyAdapter(footerData[calendarDay])
                    rv.layoutManager = LinearLayoutManager(context)

                }
            }
            //监听月份滚动监听
            monthScrollListener = object : OnMonthScrollListener {
                @SuppressLint("LongLogTag")
                override fun onScroll(calendarDay: CalendarDay) {
                    Log.d(TAG, calendarDay.toString())
                }
            }
            //设置数据
            setUp(calendarConfig)
        }
    }
}

inner class MyAdapter(val list: MutableList<Int>?) :
    RecyclerView.Adapter<MyAdapter.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val tv = TextView(parent.context)
        tv.textSize = 20f
        return ViewHolder(tv)
    }

    override fun getItemCount(): Int = list?.size ?: 0

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        (holder.itemView as TextView).text = list!![position].toString()
    }

    inner class ViewHolder(itemView: TextView) : RecyclerView.ViewHolder(itemView) {
    }
}

}

sy007 commented 1 year ago

段代码你左右滑动一下就理解我说footview的问题了,不知道这个问题能否解决。 recycleview的会高度越来越小

大佬运行一下这段代码你左右滑动一下就理解我说footview的问题了,不知道这个问题能否解决。 recycleview的会高度越来越小。

import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.os.Bundle import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.sy007.calendar. import com.sy007.calendar.databinding.ActivitySingleHorizontalBinding import com.sy007.calendar.entity.CalendarDay import com.sy007.calendar.simple.BaseActivity import com.sy007.calendar.simple.utils.LunarCalendar import java.util.

class SingleHorizontalActivity : BaseActivity() {

private var selectedDay: CalendarDay? = null
private lateinit var binding: ActivitySingleHorizontalBinding
private lateinit var tvCurrentSelectedDate: TextView
private var footerData = mutableMapOf<CalendarDay, MutableList<Int>>()

init {

    val calendar = Calendar.getInstance()
    calendar.set(1900, Calendar.JANUARY, 1)

    while (calendar.get(Calendar.YEAR) == 1900) {
        val list = mutableListOf<Int>()
        for (index in 1..Random().nextInt(10)) {
            list.add(index)
        }
        footerData[CalendarDay(calendar)] = list

        calendar.add(Calendar.MONTH, 1)
    }
}

companion object {
    private const val TAG = "SingleHorizontalActivity"
    fun start(context: Context) {
        val intent = Intent(context, SingleHorizontalActivity::class.java)
        context.startActivity(intent)
    }
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivitySingleHorizontalBinding.inflate(LayoutInflater.from(this))
    setContentView(binding.root)
    tvCurrentSelectedDate = binding.layoutCurrentSingleSelectContainer.tvCurrentSelectedDate
    setTitle("单选横向滑动(ViewPager滑动模式)")
    //初始化节日
    LunarCalendar.init(this@SingleHorizontalActivity)
    binding.apply {
        cvSingleCalendarView.apply {
            val startCalendar = Calendar.getInstance()
            startCalendar.set(1900, Calendar.JANUARY, 1)

            val endCalendar = Calendar.getInstance().apply {
                add(Calendar.MONTH, 10)
                set(Calendar.DAY_OF_MONTH, getActualMaximum(Calendar.DAY_OF_MONTH))
            }
            //初始化日历展示范围和样式
            val calendarConfig = CalendarConfig(startCalendar, endCalendar).apply {
                //横向滑动
                orientation = RecyclerView.HORIZONTAL
                //ViewPager滚动模式
                scrollMode = ScrollMode.PAGE
                //固定6行高度
                heightMode = HeightMode.FIXED
                //月份视图上展示额外日期
                isDisplayExtraDay = true
            }
            headerViewBinder = object : MonthHeaderViewBinder<View>() {
                override fun create(parent: ViewGroup): View {
                    return LayoutInflater.from(parent.context).inflate(
                        R.layout.item_header_view,
                        parent,
                        false
                    )

                }

                override fun onBind(view: View, calendarDay: CalendarDay) {
                    view.findViewById<TextView>(R.id.tv_header_title).text =
                        "header:${calendarDay.formatDate("yyyy-MM-dd")}"
                }
            }
            monthViewBinder = object : MonthViewBinder<SingleMonthViewSimple2> {
                override fun create(parent: ViewGroup): SingleMonthViewSimple2 {
                    return LayoutInflater.from(parent.context).inflate(
                        R.layout.layout_single_month_view_simple2,
                        parent,
                        false
                    ) as SingleMonthViewSimple2
                }

                override fun onBind(view: SingleMonthViewSimple2, calendarDay: CalendarDay) {
                    view.apply {
                        //设置选中的日期
                        selected = selectedDay
                        onSelectedListener = object : OnSelectedListener {
                            override fun onSelected(selected: CalendarDay) {
                                selectedDay = selected
                                //点击日期后滑动到指定日期
                                binding.cvSingleCalendarView.smoothScrollToMonth(selected)
                                tvCurrentSelectedDate.text = selected.formatDate("yyyy-MM-dd")
                            }
                        }
                    }
                }
            }
            footerViewBinder = object : MonthFooterViewBinder<View> {
                override fun create(parent: ViewGroup): View {
                    return LayoutInflater.from(parent.context).inflate(
                        R.layout.item_footer_view,
                        parent,
                        false
                    )
                }

                override fun onBind(view: View, calendarDay: CalendarDay) {
                    val rv = view.findViewById<RecyclerView>(R.id.rv)
                    rv.adapter = MyAdapter(footerData[calendarDay])
                    rv.layoutManager = LinearLayoutManager(context)

                }
            }
            //监听月份滚动监听
            monthScrollListener = object : OnMonthScrollListener {
                @SuppressLint("LongLogTag")
                override fun onScroll(calendarDay: CalendarDay) {
                    Log.d(TAG, calendarDay.toString())
                }
            }
            //设置数据
            setUp(calendarConfig)
        }
    }
}

inner class MyAdapter(val list: MutableList<Int>?) :
    RecyclerView.Adapter<MyAdapter.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val tv = TextView(parent.context)
        tv.textSize = 20f
        return ViewHolder(tv)
    }

    override fun getItemCount(): Int = list?.size ?: 0

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        (holder.itemView as TextView).text = list!![position].toString()
    }

    inner class ViewHolder(itemView: TextView) : RecyclerView.ViewHolder(itemView) {
    }
}

}

加个q聊吧:632702731

zhongcg commented 1 year ago

292739873 加你啦

zhongcg commented 1 year ago

感谢大佬耐心解答