Adil Saiyad
Adil Saiyad

Reputation: 1592

How to use DatePickerDialog in Kotlin?

In Java an DatePickerDialog can be use such as:

final Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH);
int day = c.get(Calendar.DAY_OF_MONTH);


DatePickerDialog dpd = new DatePickerDialog(getActivity(),new DatePickerDialog.OnDateSetListener()
{
   @Override
   public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth)
  {
      // Display Selected date in textbox
      lblDate.setText(""+ dayOfMonth+" "+MONTHS[monthOfYear] + ", " + year);
  }
}, year, month,day);
dpd.show();

How does Kotlin's DatePickerDialog use look like?

Upvotes: 47

Views: 74746

Answers (7)

Kehinde Onyekuwuluje.
Kehinde Onyekuwuluje.

Reputation: 19

dateColumn.setOnClickListener {
        val c = Calendar.getInstance()
        val yr = c.get(Calendar.YEAR)
        val month = c.get(Calendar.MONTH)
        val day = c.get(Calendar.DAY_OF_MONTH)
        val display = DatePickerDialog(context as BaseActivity, DatePickerDialog.OnDateSetListener {
                view, year, monthOfYear, dayOfMonth ->
            var monthInput = (monthOfYear + 1).toString()
            if (monthInput.toInt() == 1) {
                monthInput = "Jan"
            } else if (monthInput.toInt() == 2) {
                monthInput = "Feb"
            } else if (monthInput.toInt() == 3) {
                monthInput = "March"
            } else if (monthInput.toInt() == 4) {
                monthInput = "April"
            } else if (monthInput.toInt() == 5) {
                monthInput = "May"
            } else if (monthInput.toInt() == 6) {
                monthInput = "June"
            } else if (monthInput.toInt() == 7) {
                monthInput = "July"
            } else if (monthInput.toInt() == 8) {
                monthInput = "Aug"
            } else if (monthInput.toInt() == 9) {
                monthInput = "Sept"
            } else if (monthInput.toInt() == 10) {
                monthInput = "Oct"
            } else if (monthInput.toInt() == 11) {
                monthInput = "Nov"
            } else if (monthInput.toInt() == 12) {
                monthInput = "Dec"
            }
            dateColumn.text = ("$dayOfMonth $monthInput, $year")
        }, yr, month, day)
        display.datePicker.minDate = System.currentTimeMillis()
        display.show()
    }

Upvotes: 0

Derek
Derek

Reputation: 3016

It would look something like this:

val c = Calendar.getInstance()
val year = c.get(Calendar.YEAR)
val month = c.get(Calendar.MONTH)
val day = c.get(Calendar.DAY_OF_MONTH)


val dpd = DatePickerDialog(activity, DatePickerDialog.OnDateSetListener { view, year, monthOfYear, dayOfMonth ->

    // Display Selected date in textbox
    lblDate.setText("" + dayOfMonth + " " + MONTHS[monthOfYear] + ", " + year)

}, year, month, day)

dpd.show()

this was done by simply copying and pasting the code into a kotlin file in android studio. I would strongly recommend using it.

Upvotes: 87

I use Kotlin so I wanted a Kotlin solution and not a Java solution.

So first I look carefully over @FrostRocket's solution as a starting point. The solution of @FrostRocket was useful for me.

In my case, I ignore all the Kotlin world. As well as I can only use OffsetDateTime and not the calendar class. In addition, I have never used coroutine before, so I have to read and study coroutines in Kotlin. Let me know if you find in my code some theoretical or practical error.

First in my extension package I add a new File : ContextExtention.kt

import android.app.DatePickerDialog
import android.app.TimePickerDialog
import android.content.Context
import android.text.format.DateFormat
import java.time.OffsetDateTime
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

    suspend fun Context.openDateTimePicker(offsetDateTime: OffsetDateTime = OffsetDateTime.now()): OffsetDateTime =
suspendCoroutine { continuation ->
    val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, day ->
        //month (0-11 for compatibility with Calendar#MONTH)
        // day of the month (1-31, depending on month)
        val timeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
            offsetDateTime.let {
            val newOffsetDateTime =
                offsetDateTime.withHour(hour).withMinute(minute).withYear(year)
                    //withMonth from 1 (January) to 12 (December)
                    //so I have to adapt it.
                    .withMonth((month+1))
                    //withDayOfMonth from 1 to 28-31
                    //so no need adaptation
                    .withDayOfMonth(day)
                    continuation.resume(newOffsetDateTime)
                }
        }

        TimePickerDialog(
            this,
            timeSetListener,
            offsetDateTime.hour,
            offsetDateTime.minute,
            DateFormat.is24HourFormat(this)
        ).show()
    }

    //the initially selected month (0-11 for compatibility with Calendar#MONTH)
    //when offsetDateTime.monthValue from 1 (January) to 12 (December)
    //so I have to adapt it.
    DatePickerDialog(
        this,
        dateSetListener,
        offsetDateTime.year,
        (offsetDateTime.monthValue-1),
        offsetDateTime.dayOfMonth
    ).show()
}

So how can I run a suspended function? So you run a coroutine in a kotlinx.coroutines.Job, CoroutineScope made me remember about Grand Central Dispatcher in iPhone programming Where you have a list of quality of service.

In this case if you want to use the UI thread you have to use: Dispatchers.Main or Dispatchers.Main.immediate if you need better service.

import android.widget.TextView
import androidx.lifecycle.Observer
// the R import here 
// the openDateTimePicker import here 
// the TimeHelper (is text formatter) import here 
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch


class FooFragment : Fragment() {

private lateinit var viewModel: FooViewModel

private lateinit var dateButton: Button
private lateinit var dateText: TextView
private var datePickerJob : Job? = null
val uiScope = CoroutineScope(Dispatchers.Main)

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    val root =
     inflater.inflate(R.layout.foo_fragment, container, false)
    dateButton = root.findViewById(R.id.textButtonChangeDate)
    dateText = root.findViewById(R.id.textViewWeighingDateValue)
    viewModel = ViewModelProvider(this).get(FooViewModel::class.java)
    return root
}

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    viewModel.dateTimeText.observe(viewLifecycleOwner, Observer {
        dateText.text = it.format(TimeHelper.formatter)
//the call to setNewDateTime will refresh this value
    })
}

override fun onStart() {
    super.onStart()
    dateButton.setOnClickListener {
        datePickerJob = uiScope.launch {
            viewModel.setNewDateTime(context?.openDateTimePicker())
//setNewDateTime is a setValue in a MutableLiveData
        }
    }

}

override fun onStop() {
    super.onStop()
    dateButton.setOnClickListener(null)
    datePickerJob?.cancel()
}

}

Upvotes: 1

0xMatthewGroves
0xMatthewGroves

Reputation: 3239

If you'd like to use coroutines to bridge the callback pattern, you can use a solution like this one. Note, I'm using both the Date and Time picker here, but you can easily remove the TimePicker logic if you don't require it.

suspend fun Context.openDateTimePicker(calendar: Calendar = Calendar.getInstance()): Instant =
    suspendCoroutine { continuation ->
        val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, day ->
            val timeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
                calendar
                    .apply { set(year, month, day, hour, minute) }
                    .run { Instant.ofEpochMilli(timeInMillis).truncatedTo(ChronoUnit.MINUTES) }
                    .let { continuation.resume(it) }
            }

            TimePickerDialog(
                this,
                timeSetListener,
                calendar.get(Calendar.HOUR_OF_DAY),
                calendar.get(Calendar.MINUTE),
                DateFormat.is24HourFormat(this)
            ).show()
        }

        DatePickerDialog(
            this,
            dateSetListener,
            calendar.get(Calendar.YEAR),
            calendar.get(Calendar.MONTH),
            calendar.get(Calendar.DAY_OF_MONTH)
        ).show()
    }

Upvotes: 3

Prabh deep
Prabh deep

Reputation: 1042

use show date picker on button click

   val cal = Calendar.getInstance()
    val y = cal.get(Calendar.YEAR)
    val m = cal.get(Calendar.MONTH)
    val d = cal.get(Calendar.DAY_OF_MONTH)


    val datepickerdialog:DatePickerDialog = DatePickerDialog(activity, DatePickerDialog.OnDateSetListener { view, year, monthOfYear, dayOfMonth ->

    // Display Selected date in textbox
    lblDate.setText("" + dayOfMonth + " " + MONTHS[monthOfYear] + ", " + year)
        }, y, m, d)

    datepickerdialog.show()

and this used for show time picker on button click

textView54.setOnClickListener {
                val c:Calendar= Calendar.getInstance()
                val hh=c.get(Calendar.HOUR_OF_DAY)
                val mm=c.get(Calendar.MINUTE)
                val timePickerDialog:TimePickerDialog=TimePickerDialog(this@VendorRegistration,TimePickerDialog.OnTimeSetListener { view, hourOfDay, minute ->
                    textView54.setText( ""+hourOfDay + ":" + minute);
                },hh,mm,true)
                timePickerDialog.show()

Upvotes: 5

Alexandr Kovalenko
Alexandr Kovalenko

Reputation: 1051

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val textView: TextView  = findViewById(R.id.textView_date)
        textView.text = SimpleDateFormat("dd.MM.yyyy").format(System.currentTimeMillis())

        var cal = Calendar.getInstance()

        val dateSetListener = DatePickerDialog.OnDateSetListener { view, year, monthOfYear, dayOfMonth ->
            cal.set(Calendar.YEAR, year)
            cal.set(Calendar.MONTH, monthOfYear)
            cal.set(Calendar.DAY_OF_MONTH, dayOfMonth)

            val myFormat = "dd.MM.yyyy" // mention the format you need
            val sdf = SimpleDateFormat(myFormat, Locale.US)
            textView.text = sdf.format(cal.time)

        }

        textView.setOnClickListener {
            DatePickerDialog(this@MainActivity, dateSetListener,
                    cal.get(Calendar.YEAR),
                    cal.get(Calendar.MONTH),
                    cal.get(Calendar.DAY_OF_MONTH)).show()
        }
    }
}

Upvotes: 29

Swapnil
Swapnil

Reputation: 344

Kotlin Anko Android Example:

alert {

    isCancelable = false

    lateinit var datePicker: DatePicker

    customView {
        verticalLayout {
            datePicker = datePicker {
                maxDate = System.currentTimeMillis()
            }
        }
    }

    yesButton {
        val parsedDate = "${datePicker.dayOfMonth}/${datePicker.month + 1}/${datePicker.year}"
    }

    noButton { }

}.show()

Upvotes: 10

Related Questions