安卓 (周日 - 周六) 选择控件 viewpager左右滑动

41 阅读1分钟
SUMOTuWeThFrSa

styles

<style name="WeekDayText">
    <item name="android:layout_width">0dp</item>
    <item name="android:layout_height">48dp</item>
    <item name="android:layout_weight">1</item>
    <item name="android:gravity">center</item>
    <item name="android:textSize">16sp</item>
</style>

R.layout.week_picker

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/weekViewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

R.layout.week_item

<?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="horizontal"
    android:padding="8dp">

    <TextView
        android:id="@+id/sundayView"
        style="@style/WeekDayText"
        android:text="日" />

    <TextView
        android:id="@+id/mondayView"
        style="@style/WeekDayText"
        android:text="一" />

    <!-- 周二到周五 -->
    <TextView
        android:id="@+id/tuesdayView"
        style="@style/WeekDayText"
        android:text="二" />

    <TextView
        android:id="@+id/wednesdayView"
        style="@style/WeekDayText"
        android:text="三" />

    <TextView
        android:id="@+id/thursdayView"
        style="@style/WeekDayText"
        android:text="四" />

    <TextView
        android:id="@+id/fridayView"
        style="@style/WeekDayText"
        android:text="五" />

    <TextView
        android:id="@+id/saturdayView"
        style="@style/WeekDayText"
        android:text="六" />

</LinearLayout>

WeekPicker

import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import global.xfinite.conso.library.R
import global.xfinite.conso.logtool.LogTool
import java.text.SimpleDateFormat
import java.util.*

class WeekPicker @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {

    private val viewPager: ViewPager2
    private var selectedDate = Calendar.getInstance()
    private var onDateSelectedListener: ((Date) -> Unit)? = null

    init {
        LayoutInflater.from(context).inflate(R.layout.week_picker, this, true)
        viewPager = findViewById(R.id.weekViewPager)

        setupViewPager()
    }

    private fun setupViewPager() {
        viewPager.adapter = WeekPagerAdapter()
        viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
            override fun onPageSelected(position: Int) {
                // 计算当前显示的周
                val weekOffset = position - Int.MAX_VALUE / 2
                selectedDate = getCalendarForWeek(weekOffset)
                onDateSelectedListener?.invoke(selectedDate.time)
            }
        })

        // 设置初始位置为中间,实现无限滑动
        viewPager.setCurrentItem(Int.MAX_VALUE / 2, false)
    }

    fun setOnDateSelectedListener(listener: (Date) -> Unit) {
        this.onDateSelectedListener = listener
    }

    private fun getCalendarForWeek(weekOffset: Int): Calendar {
        val calendar = Calendar.getInstance().apply {
            firstDayOfWeek = Calendar.SUNDAY
        }
        calendar.add(Calendar.WEEK_OF_YEAR, weekOffset)
        return calendar
    }

    private inner class WeekPagerAdapter : RecyclerView.Adapter<WeekViewHolder>() {
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WeekViewHolder {
            val view = LayoutInflater.from(parent.context)
                .inflate(R.layout.week_item, parent, false)
            return WeekViewHolder(view)
        }

        override fun onBindViewHolder(holder: WeekViewHolder, position: Int) {
            val weekOffset = position - Int.MAX_VALUE / 2
            val calendar = getCalendarForWeek(weekOffset)

            // 设置周日到周六的日期
            calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY)
            holder.bindWeek(calendar)
        }

        override fun getItemCount(): Int = Int.MAX_VALUE
    }

    private inner class WeekViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private val dayViews = listOf(
            itemView.findViewById<TextView>(R.id.sundayView),
            itemView.findViewById<TextView>(R.id.mondayView),
            itemView.findViewById<TextView>(R.id.tuesdayView),
            itemView.findViewById<TextView>(R.id.wednesdayView),
            itemView.findViewById<TextView>(R.id.thursdayView),
            itemView.findViewById<TextView>(R.id.fridayView),
            itemView.findViewById<TextView>(R.id.saturdayView)
        )

        fun bindWeek(startOfWeek: Calendar) {
            val dateFormat = SimpleDateFormat("d", Locale.getDefault())

            // 创建一个包含整周日期的列表
            val weekDays = (0 until 7).map { dayOffset ->
                val dayCalendar = startOfWeek.clone() as Calendar
                dayCalendar.add(Calendar.DAY_OF_YEAR, dayOffset)
                dayCalendar to dateFormat.format(dayCalendar.time)
            }

            dayViews.forEachIndexed { index, textView ->
                val (dayCalendar, dayText) = weekDays[index]

                // 设置日期文本
                textView.text = dayText

                // 设置点击事件
                textView.setOnClickListener {
                    selectedDate = dayCalendar.clone() as Calendar
                    highlightSelectedDay(index)
                    onDateSelectedListener?.invoke(selectedDate.time)
                    LogTool.d("WeekPicker", "Selected date: ${SimpleDateFormat("yyyy-MM-dd").format(selectedDate.time)}")
                }

                // 高亮选中的日期
                if (dayCalendar.get(Calendar.DAY_OF_YEAR) == selectedDate.get(Calendar.DAY_OF_YEAR) &&
                    dayCalendar.get(Calendar.YEAR) == selectedDate.get(Calendar.YEAR)) {
                    highlightSelectedDay(index)
                } else {
                    resetDayStyle(textView)
                }
            }
        }

        private fun highlightSelectedDay(selectedIndex: Int) {
            dayViews.forEachIndexed { index, textView ->
                if (index == selectedIndex) {
                    textView.setTextColor(ContextCompat.getColor(context, android.R.color.white))
                    textView.background = ContextCompat.getDrawable(context, R.drawable.border_r8_left_44d564_radius)
                } else {
                    resetDayStyle(textView)
                }
            }
        }

        private fun resetDayStyle(textView: TextView) {
            textView.setTextColor(ContextCompat.getColor(context, android.R.color.black))
            textView.background = null
        }
    }
}
<your.path.WeekPicker
    android:id="@+id/weekViewPagerLayout"
    android:layout_width="match_parent"
    android:layout_height="50dp"/>
val weekPicker = binding.weekViewPagerLayout
weekPicker.setOnDateSelectedListener { selectedDate ->
    // 处理日期选择
    LogTool.d("WeekPicker", "Selected date: $selectedDate")
}