Skip to content
This repository has been archived by the owner on Feb 8, 2022. It is now read-only.

Can I change the order? For example, year-month-day #161

Closed
mofada opened this issue Aug 23, 2018 · 5 comments
Closed

Can I change the order? For example, year-month-day #161

mofada opened this issue Aug 23, 2018 · 5 comments

Comments

@mofada
Copy link

mofada commented Aug 23, 2018

No description provided.

@agustinsivoplas
Copy link

Do you have a solution for this?

@mofada
Copy link
Author

mofada commented Aug 29, 2019

No, I don't, I use other .

@mofada mofada closed this as completed Aug 29, 2019
@agustinsivoplas
Copy link

I could achieve. I have created my own version of time picker with my layout but using library components. In my case I need month-day-year.

import android.content.Context
import android.text.format.DateFormat
import android.util.AttributeSet
import android.view.View
import android.widget.LinearLayout
import androidx.core.content.ContextCompat
import com.github.florent37.singledateandtimepicker.DateHelper
import com.github.florent37.singledateandtimepicker.widget.WheelAmPmPicker
import com.github.florent37.singledateandtimepicker.widget.WheelDayOfMonthPicker
import com.github.florent37.singledateandtimepicker.widget.WheelDayPicker
import com.github.florent37.singledateandtimepicker.widget.WheelHourPicker
import com.github.florent37.singledateandtimepicker.widget.WheelMinutePicker
import com.github.florent37.singledateandtimepicker.widget.WheelMonthPicker
import com.github.florent37.singledateandtimepicker.widget.WheelPicker
import com.github.florent37.singledateandtimepicker.widget.WheelYearPicker
import org.allinahealth.cv.R
import java.text.SimpleDateFormat
import java.util.ArrayList
import java.util.Calendar
import java.util.Date
import java.util.Locale

class CustomSingleDateAndTimePicker : LinearLayout {

    companion object {
        const val IS_CYCLIC_DEFAULT = true
        const val IS_CURVED_DEFAULT = false
        const val MUST_BE_ON_FUTUR_DEFAULT = false
        const val DELAY_BEFORE_CHECK_PAST = 200
        const val VISIBLE_ITEM_COUNT_DEFAULT = 7
        const val PM_HOUR_ADDITION = 12
        const val FORMAT_24_HOUR = "EEE d MMM H:mm"
        const val FORMAT_12_HOUR = "EEE d MMM h:mm a"
    }

    private var yearsPicker: WheelYearPicker
    private var monthPicker: WheelMonthPicker
    private var daysOfMonthPicker: WheelDayOfMonthPicker
    private var daysPicker: WheelDayPicker
    private var minutesPicker: WheelMinutePicker
    private var hoursPicker: WheelHourPicker
    private var amPmPicker: WheelAmPmPicker

    private val pickers = ArrayList<WheelPicker<*>>()

    private val listeners = ArrayList<OnDateChangedListener>()

    private var dtSelector: View
    private var mustBeOnFuture: Boolean = false

    private var minDate: Date? = null
    private var maxDate: Date? = null
    private var defaultDate: Date

    private var displayYears = false
    private var displayMonth = false
    private var displayDaysOfMonth = false
    private var displayDays = true
    private var displayMinutes = true
    private var displayHours = true

    private var isAmPm: Boolean = false

    constructor(context: Context) : this(context, null)

    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        defaultDate = Date()
        isAmPm = !DateFormat.is24HourFormat(context)

        View.inflate(context, R.layout.single_day_picker, this)

        yearsPicker = findViewById(R.id.yearPicker)
        monthPicker = findViewById(R.id.monthPicker)
        daysOfMonthPicker = findViewById(R.id.daysOfMonthPicker)
        daysPicker = findViewById(R.id.daysPicker)
        minutesPicker = findViewById(R.id.minutesPicker)
        hoursPicker = findViewById(R.id.hoursPicker)
        amPmPicker = findViewById(R.id.amPmPicker)
        dtSelector = findViewById(R.id.dtSelector)

        pickers.addAll(listOf(daysPicker, minutesPicker, hoursPicker, amPmPicker, daysOfMonthPicker, monthPicker, yearsPicker))

        init(context, attrs)
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()

        yearsPicker.setOnYearSelectedListener { picker, position, year ->
            updateListener()
            checkMinMaxDate(picker)

            if (displayDaysOfMonth) {
                updateDaysOfMonth()
            }
        }

        monthPicker.setOnMonthSelectedListener { picker, monthIndex, monthName ->
            updateListener()
            checkMinMaxDate(picker)

            if (displayDaysOfMonth) {
                updateDaysOfMonth()
            }
        }

        daysOfMonthPicker
                .setDayOfMonthSelectedListener { picker, dayIndex ->
                    updateListener()
                    checkMinMaxDate(picker)
                }

        daysOfMonthPicker
                .setOnFinishedLoopListener {
                    if (displayMonth) {
                        monthPicker.scrollTo(monthPicker.currentItemPosition + 1)
                        updateDaysOfMonth()
                    }
                }

        daysPicker
                .setOnDaySelectedListener { picker, position, name, date ->
                    updateListener()
                    checkMinMaxDate(picker)
                }

        minutesPicker
                .setOnMinuteChangedListener { picker, minutes ->
                    updateListener()
                    checkMinMaxDate(picker)
                }
                .setOnFinishedLoopListener { hoursPicker.scrollTo(hoursPicker.currentItemPosition + 1) }

        hoursPicker
                .setOnFinishedLoopListener { daysPicker.scrollTo(daysPicker.currentItemPosition + 1) }
                .setHourChangedListener { picker, hour ->
                    updateListener()
                    checkMinMaxDate(picker)
                }

        amPmPicker
                .setAmPmListener { picker, isAm ->
                    updateListener()
                    checkMinMaxDate(picker)
                }

        setDefaultDate(this.defaultDate) // update displayed date
    }

    override fun setEnabled(enabled: Boolean) {
        super.setEnabled(enabled)
        for (picker in pickers) {
            picker.isEnabled = enabled
        }
    }

    fun setDisplayYears(displayYears: Boolean) {
        this.displayYears = displayYears
        yearsPicker.visibility = if (displayYears) View.VISIBLE else View.GONE
    }

    fun setDisplayMonths(displayMonths: Boolean) {
        this.displayMonth = displayMonths
        monthPicker.visibility = if (displayMonths) View.VISIBLE else View.GONE
        checkSettings()
    }

    fun setDisplayDaysOfMonth(displayDaysOfMonth: Boolean) {
        this.displayDaysOfMonth = displayDaysOfMonth
        daysOfMonthPicker.visibility = if (displayDaysOfMonth) View.VISIBLE else View.GONE

        if (displayDaysOfMonth) {
            updateDaysOfMonth()
        }
        checkSettings()
    }

    fun setDisplayDays(displayDays: Boolean) {
        this.displayDays = displayDays
        daysPicker.visibility = if (displayDays) View.VISIBLE else View.GONE
        checkSettings()
    }

    fun setDisplayMinutes(displayMinutes: Boolean) {
        this.displayMinutes = displayMinutes
        minutesPicker.visibility = if (displayMinutes) View.VISIBLE else View.GONE
    }

    fun setDisplayHours(displayHours: Boolean) {
        this.displayHours = displayHours
        hoursPicker.visibility = if (displayHours) View.VISIBLE else View.GONE

        setIsAmPm(this.isAmPm)
        hoursPicker.setIsAmPm(isAmPm)
    }

    fun setDisplayMonthNumbers(displayMonthNumbers: Boolean) {
        this.monthPicker.setDisplayMonthNumbers(displayMonthNumbers)
        this.monthPicker.updateAdapter()
    }

    fun setTodayText(todayText: String?) {
        if (todayText != null && !todayText.isEmpty()) {
            daysPicker.setTodayText(todayText)
        }
    }

    fun setCurved(curved: Boolean) {
        for (picker in pickers) {
            picker.isCurved = curved
        }
    }

    fun setCyclic(cyclic: Boolean) {
        for (picker in pickers) {
            picker.isCyclic = cyclic
        }
    }

    fun setTextSize(textSize: Int) {
        for (picker in pickers) {
            picker.itemTextSize = textSize
        }
    }

    fun setSelectedTextColor(selectedTextColor: Int) {
        for (picker in pickers) {
            picker.selectedItemTextColor = selectedTextColor
        }
    }

    fun setTextColor(textColor: Int) {
        for (picker in pickers) {
            picker.itemTextColor = textColor
        }
    }

    fun setSelectorColor(selectorColor: Int) {
        dtSelector.setBackgroundColor(selectorColor)
    }

    fun setSelectorHeight(selectorHeight: Int) {
        val dtSelectorLayoutParams = dtSelector.layoutParams
        dtSelectorLayoutParams.height = selectorHeight
        dtSelector.layoutParams = dtSelectorLayoutParams
    }

    fun setVisibleItemCount(visibleItemCount: Int) {
        for (picker in pickers) {
            picker.visibleItemCount = visibleItemCount
        }
    }

    fun setIsAmPm(isAmPm: Boolean) {
        this.isAmPm = isAmPm

        amPmPicker.visibility = if (isAmPm && displayHours) View.VISIBLE else View.GONE
        hoursPicker.setIsAmPm(isAmPm)
    }

    fun isAmPm(): Boolean {
        return isAmPm
    }

    fun setDayFormatter(simpleDateFormat: SimpleDateFormat?) {
        if (simpleDateFormat != null) {
            this.daysPicker.setDayFormatter(simpleDateFormat)
        }
    }

    fun getMinDate(): Date? {
        return minDate
    }

    fun setMinDate(minDate: Date) {
        this.minDate = minDate
        setMinYear()
    }

    fun getMaxDate(): Date? {
        return maxDate
    }

    fun setMaxDate(maxDate: Date) {
        this.maxDate = maxDate
        setMinYear()
    }

    fun setCustomLocale(locale: Locale) {
        for (p in pickers) {
            p.setCustomLocale(locale)
            p.updateAdapter()
        }
    }

    private fun checkMinMaxDate(picker: WheelPicker<*>) {
        checkBeforeMinDate(picker)
        checkAfterMaxDate(picker)
    }

    private fun checkBeforeMinDate(picker: WheelPicker<*>) {
        picker.postDelayed({
            if (minDate != null && isBeforeMinDate(getDate())) {
                for (p in pickers) {
                    p.scrollTo(p.findIndexOfDate(minDate!!))
                }
            }
        }, DELAY_BEFORE_CHECK_PAST.toLong())
    }

    private fun checkAfterMaxDate(picker: WheelPicker<*>) {
        picker.postDelayed({
            if (maxDate != null && isAfterMaxDate(getDate())) {
                for (p in pickers) {
                    p.scrollTo(p.findIndexOfDate(maxDate!!))
                }
            }
        }, DELAY_BEFORE_CHECK_PAST.toLong())
    }

    private fun isBeforeMinDate(date: Date): Boolean {
        return DateHelper.getCalendarOfDate(date).before(DateHelper.getCalendarOfDate(minDate))
    }

    private fun isAfterMaxDate(date: Date): Boolean {
        return DateHelper.getCalendarOfDate(date).after(DateHelper.getCalendarOfDate(maxDate))
    }

    fun addOnDateChangedListener(listener: OnDateChangedListener) {
        this.listeners.add(listener)
    }

    fun removeOnDateChangedListener(listener: OnDateChangedListener) {
        this.listeners.remove(listener)
    }

    fun checkPickersMinMax() {
        for (picker in pickers) {
            checkMinMaxDate(picker)
        }
    }

    fun getDate(): Date {
        var hour = hoursPicker.currentHour
        if (isAmPm && amPmPicker.isPm) {
            hour += PM_HOUR_ADDITION
        }
        val minute = minutesPicker.currentMinute

        val calendar = Calendar.getInstance()

        if (displayDays) {
            val dayDate = daysPicker.currentDate
            calendar.time = dayDate
        } else {
            if (displayMonth) {
                calendar.set(Calendar.MONTH, monthPicker.currentMonth)
            }

            if (displayYears) {
                calendar.set(Calendar.YEAR, yearsPicker.currentYear)
            }

            if (displayDaysOfMonth) {
                val daysInMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH)
                if (daysOfMonthPicker.currentDay >= daysInMonth) {
                    calendar.set(Calendar.DAY_OF_MONTH, daysInMonth)
                } else {
                    calendar.set(Calendar.DAY_OF_MONTH, daysOfMonthPicker.currentDay + 1)
                }
            }
        }

        calendar.set(Calendar.HOUR_OF_DAY, hour)
        calendar.set(Calendar.MINUTE, minute)

        return calendar.time
    }

    fun setStepMinutes(minutesStep: Int) {
        minutesPicker.setStepMinutes(minutesStep)
    }

    fun setHoursStep(hoursStep: Int) {
        hoursPicker.setHoursStep(hoursStep)
    }

    fun setDefaultDate(date: Date?) {
        if (date != null) {
            this.defaultDate = date

            updateDaysOfMonth()

            for (picker in pickers) {
                picker.setDefaultDate(defaultDate)
            }
        }
    }

    fun selectDate(calendar: Calendar?) {
        if (calendar == null) {
            return
        }

        val date = calendar.time
        for (picker in pickers) {
            picker.selectDate(date)
        }

        if (displayDaysOfMonth) {
            updateDaysOfMonth()
        }
    }

    private fun updateListener() {
        val date = getDate()
        val format = if (isAmPm) FORMAT_12_HOUR else FORMAT_24_HOUR
        val displayed = DateFormat.format(format, date).toString()
        for (listener in listeners) {
            listener.onDateChanged(displayed, date)
        }
    }

    private fun updateDaysOfMonth() {
        val date = getDate()
        val calendar = Calendar.getInstance()
        calendar.time = date
        updateDaysOfMonth(calendar)
    }

    private fun updateDaysOfMonth(calendar: Calendar) {
        val daysInMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH)
        daysOfMonthPicker.daysInMonth = daysInMonth
        daysOfMonthPicker.updateAdapter()
    }

    fun setMustBeOnFuture(mustBeOnFuture: Boolean) {
        this.mustBeOnFuture = mustBeOnFuture
        if (mustBeOnFuture) {
            minDate = Calendar.getInstance().time // minDate is Today
        }
    }

    fun mustBeOnFuture(): Boolean {
        return mustBeOnFuture
    }

    private fun setMinYear() {

        if (displayYears && this.minDate != null && this.maxDate != null) {
            val calendar = Calendar.getInstance()
            calendar.time = this.minDate
            yearsPicker.setMinYear(calendar.get(Calendar.YEAR))
            calendar.time = this.maxDate
            yearsPicker.setMaxYear(calendar.get(Calendar.YEAR))
        }
    }

    private fun checkSettings() {
        if (displayDays && (displayDaysOfMonth || displayMonth)) {
            throw IllegalArgumentException("You can either display days with months or days and months separately")
        }
    }

    private fun init(context: Context, attrs: AttributeSet?) {
        attrs?.let {
            val a = context.obtainStyledAttributes(attrs, R.styleable.SingleDateAndTimePicker)

            val resources = resources
            setTodayText(a.getString(R.styleable.SingleDateAndTimePicker_picker_todayText))
            setTextColor(a.getColor(R.styleable.SingleDateAndTimePicker_picker_textColor, ContextCompat.getColor(context, R.color.picker_default_text_color)))
            setSelectedTextColor(a.getColor(R.styleable.SingleDateAndTimePicker_picker_selectedTextColor, ContextCompat.getColor(context, R.color.picker_default_selected_text_color)))
            setSelectorColor(a.getColor(R.styleable.SingleDateAndTimePicker_picker_selectorColor, ContextCompat.getColor(context, R.color.picker_default_selector_color)))
            setSelectorHeight(a.getDimensionPixelSize(R.styleable.SingleDateAndTimePicker_picker_selectorHeight, resources.getDimensionPixelSize(R.dimen.wheelSelectorHeight)))
            setTextSize(a.getDimensionPixelSize(R.styleable.SingleDateAndTimePicker_picker_textSize, resources.getDimensionPixelSize(R.dimen.WheelItemTextSize)))
            setCurved(a.getBoolean(R.styleable.SingleDateAndTimePicker_picker_curved, IS_CURVED_DEFAULT))
            setCyclic(a.getBoolean(R.styleable.SingleDateAndTimePicker_picker_cyclic, IS_CYCLIC_DEFAULT))
            setMustBeOnFuture(a.getBoolean(R.styleable.SingleDateAndTimePicker_picker_mustBeOnFuture, MUST_BE_ON_FUTUR_DEFAULT))
            setVisibleItemCount(a.getInt(R.styleable.SingleDateAndTimePicker_picker_visibleItemCount, VISIBLE_ITEM_COUNT_DEFAULT))

            setDisplayDays(a.getBoolean(R.styleable.SingleDateAndTimePicker_picker_displayDays, displayDays))
            setDisplayMinutes(a.getBoolean(R.styleable.SingleDateAndTimePicker_picker_displayMinutes, displayMinutes))
            setDisplayHours(a.getBoolean(R.styleable.SingleDateAndTimePicker_picker_displayHours, displayHours))
            setDisplayMonths(a.getBoolean(R.styleable.SingleDateAndTimePicker_picker_displayMonth, displayMonth))
            setDisplayYears(a.getBoolean(R.styleable.SingleDateAndTimePicker_picker_displayYears, displayYears))
            setDisplayDaysOfMonth(a.getBoolean(R.styleable.SingleDateAndTimePicker_picker_displayDaysOfMonth, displayDaysOfMonth))
            setDisplayMonthNumbers(a.getBoolean(R.styleable.SingleDateAndTimePicker_picker_displayMonthNumbers, monthPicker.displayMonthNumbers()))

            checkSettings()
            setMinYear()

            a.recycle()

            if (displayDaysOfMonth) {
                updateDaysOfMonth(Calendar.getInstance())
            }
        }
    }

    interface OnDateChangedListener {
        fun onDateChanged(displayed: String, date: Date)
    }
}

single_day_picker.xml

**

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center_vertical"
    android:gravity="center"
    android:orientation="horizontal">

    <com.github.florent37.singledateandtimepicker.widget.WheelMonthPicker
        android:id="@+id/monthPicker"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="5dp"
        app:wheel_atmospheric="true"
        app:wheel_item_align="right" />

    <com.github.florent37.singledateandtimepicker.widget.WheelDayOfMonthPicker
        android:id="@+id/daysOfMonthPicker"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="5dp"
        app:wheel_atmospheric="true"
        app:wheel_item_align="right" />

    <com.github.florent37.singledateandtimepicker.widget.WheelDayPicker
        android:id="@+id/daysPicker"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        app:wheel_atmospheric="true"
        app:wheel_item_align="right" />

    <com.github.florent37.singledateandtimepicker.widget.WheelYearPicker
        android:id="@+id/yearPicker"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="5dp"
        app:wheel_atmospheric="true"
        app:wheel_item_align="right" />

    <com.github.florent37.singledateandtimepicker.widget.WheelHourPicker
        android:id="@+id/hoursPicker"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_marginLeft="30dp"
        android:layout_marginRight="30dp"
        app:wheel_atmospheric="true"
        app:wheel_item_align="center" />

    <com.github.florent37.singledateandtimepicker.widget.WheelMinutePicker
        android:id="@+id/minutesPicker"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        app:wheel_atmospheric="true"
        app:wheel_item_align="center" />

    <com.github.florent37.singledateandtimepicker.widget.WheelAmPmPicker
        android:id="@+id/amPmPicker"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:paddingLeft="30dp"
        app:wheel_atmospheric="true"
        app:wheel_item_align="center"
        app:wheel_visible_item_count="2" />

</LinearLayout>

<View
    android:id="@+id/dtSelector"
    android:layout_width="match_parent"
    android:layout_height="@dimen/wheelSelectorHeight"
    android:layout_gravity="center_vertical"
    android:alpha="0.2"
    android:background="@color/picker_default_selector_color" />

**

The result.

Screen Shot 2019-08-28 at 22 17 49

@mofada
Copy link
Author

mofada commented Aug 29, 2019

Okay thank you

@chinalwb
Copy link

chinalwb commented Sep 9, 2020

@agustinsivoplas Your answer helps me a lot, thank you man!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants