How to pick a second using TimePicker, android

33.5k Views Asked by At

I have used TimePicker to make the user to choose time see here and here also. But I didnot find a way to make the user to select second also. Now user can select Hour and Minute but not second. If I want to set a time for 02:05:10 then what I have to do? How to pick a second using TimePicker?

7

There are 7 best solutions below

1
On BEST ANSWER

I think the best solution is to create your own TimePicker, by using the Time-class and three NumberPickers.

1
On

I wrote a Kotlin extension function to do this. It's messy but it gets the job done:

/**
 * Adds seconds number picker into the [TimePicker] format programmatically.
 * */
fun TimePicker.addSeconds() {
    val system = Resources.getSystem()
    val idHour = system.getIdentifier("hour", "id", "android")
    val idMinute = system.getIdentifier("minute", "id", "android")
    val idAmPm = system.getIdentifier("amPm", "id", "android")
    val idLayout = system.getIdentifier("timePickerLayout", "id", "android")
    val spinnerHour = findViewById<View>(idHour) as NumberPicker
    val spinnerMinute = findViewById<View>(idMinute) as NumberPicker
    val spinnerAmPm = findViewById<View>(idAmPm) as NumberPicker
    val outerLayout = findViewById<View>(idLayout) as LinearLayout
    val layout = outerLayout.getChildAt(0) as LinearLayout
    layout.removeAllViews()
    (spinnerAmPm.parent as ViewGroup).removeView(spinnerAmPm)

    layout.addView(spinnerHour)
    setImeOptions(spinnerHour, 0)
    layout.addView(spinnerMinute)
    setImeOptions(spinnerMinute, 1)

    val spinnerSecond = createSecondPicker(spinnerHour.context)
    layout.addView(spinnerSecond)
    setImeOptions(spinnerAmPm, 2)
    val params = spinnerHour.layoutParams
    spinnerSecond.layoutParams = params

    layout.addView(spinnerAmPm)
    setImeOptions(spinnerAmPm, 3)
}

private fun createSecondPicker(context: Context): NumberPicker {
    val spinnerSecond = NumberPicker(context)
    spinnerSecond.id = R.id.second
    spinnerSecond.setFormatter { i -> String.format("%02d", i) }
    spinnerSecond.minValue = 0
    spinnerSecond.maxValue = 59
    return spinnerSecond
}

You'll also need to add this id to res/values/ids.xml so that you can reference the seconds field programmatically using R.id.second

<item name="second" type="id"/>

Shoutout to this post for the idea: https://stackoverflow.com/a/60601077/1709354

1
On

One quick and dirty way is to use two TimePickers, One for hours,minutes, and use the minutes on the other one as secunds. Hide the unused hours under the first minutes. This only works in 24 hour mode. Must declare timepicker for seconds first so locates under.

<RelativeLayout
  <TimePicker
    android:id="@+id/timePicker_Sec"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="76dp" />
  <TimePicker
    android:id="@+id/timePicker"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignTop="@+id/timePicker_Sec"   
    android:layout_marginLeft="0dp" />
</RelativeLayout>
0
On

Here is a custom TimePickerDialog with seconds.

MainActivity.java

import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.NumberPicker;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
        final TextView timeTV = findViewById(R.id.time_text_view);
        timeTV.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                View view = View.inflate(MainActivity.this, R.layout.time_dialog, null);
                final NumberPicker numberPickerHour = view.findViewById(R.id.numpicker_hours);
                numberPickerHour.setMaxValue(23);
                numberPickerHour.setValue(sharedPreferences.getInt("Hours", 0));
                final NumberPicker numberPickerMinutes = view.findViewById(R.id.numpicker_minutes);
                numberPickerMinutes.setMaxValue(59);
                numberPickerMinutes.setValue(sharedPreferences.getInt("Minutes", 0));
                final NumberPicker numberPickerSeconds = view.findViewById(R.id.numpicker_seconds);
                numberPickerSeconds.setMaxValue(59);
                numberPickerSeconds.setValue(sharedPreferences.getInt("Seconds", 0));
                Button cancel = view.findViewById(R.id.cancel);
                Button ok = view.findViewById(R.id.ok);
                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                builder.setView(view);
                final AlertDialog alertDialog = builder.create();
                cancel.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        alertDialog.dismiss();
                    }
                });
                ok.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        timeTV.setText(numberPickerHour.getValue() + ":" + numberPickerMinutes.getValue() + ":" + numberPickerSeconds.getValue());
//                        timeTV.setText(String.format("%1$d:%2$02d:%3$02d", numberPickerHour.getValue(), numberPickerMinutes.getValue(), numberPickerSeconds.getValue()));
                        SharedPreferences.Editor editor = sharedPreferences.edit();
                        editor.putInt("Hours", numberPickerHour.getValue());
                        editor.putInt("Minutes", numberPickerMinutes.getValue());
                        editor.putInt("Seconds", numberPickerSeconds.getValue());
                        editor.apply();
                        alertDialog.dismiss();
                    }
                });
                alertDialog.show();
            }
        });
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/time_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click Me"
        android:textSize="24sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

time_dialog.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="16dp"
        android:gravity="center"
        android:orientation="horizontal">

        <NumberPicker
            android:id="@+id/numpicker_hours"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <NumberPicker
            android:id="@+id/numpicker_minutes"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            android:layout_marginRight="16dp" />

        <NumberPicker
            android:id="@+id/numpicker_seconds"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>

    <View
        android:id="@+id/view"
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#ffF0F0F0" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">

        <Button
            android:id="@+id/cancel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="@android:color/transparent"
            android:text="Cancel"
            android:textAllCaps="false" />

        <View
            android:id="@+id/view2"
            android:layout_width="1dp"
            android:layout_height="match_parent"
            android:background="#ffF0F0F0" />

        <Button
            android:id="@+id/ok"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="@android:color/transparent"
            android:text="OK"
            android:textAllCaps="true" />
    </LinearLayout>

</LinearLayout>
0
On

I've created my own time picker with seconds. You can try it here.

Time picker with seconds

I've added some other functionalities.

The main files are

my_time_picker_content.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"
android:layout_width="match_parent"
android:layout_height="wrap_content">


<LinearLayout
    android:id="@+id/hours_container"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_marginEnd="16dp"
    android:orientation="vertical"
    android:layout_marginVertical="8dp"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toStartOf="@+id/minutes_container"
    app:layout_constraintHorizontal_chainStyle="packed"
    app:layout_constraintStart_toStartOf="parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hours"
        android:layout_gravity="center_horizontal"
        android:layout_marginVertical="8dp"/>
    <NumberPicker
        android:id="@+id/hours"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:descendantFocusability="blocksDescendants" />
</LinearLayout>

<LinearLayout
    android:id="@+id/minutes_container"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:layout_marginVertical="8dp"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toStartOf="@+id/seconds_container"
    app:layout_constraintStart_toEndOf="@+id/hours_container">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Minutes"
        android:layout_gravity="center_horizontal"
        android:layout_marginVertical="8dp"/>
    <NumberPicker
        android:id="@+id/minutes"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:descendantFocusability="blocksDescendants" />
</LinearLayout>

<LinearLayout
    android:id="@+id/seconds_container"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_marginStart="16dp"
    android:layout_marginVertical="8dp"
    android:orientation="vertical"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toEndOf="@+id/minutes_container">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Seconds"
        android:layout_gravity="center_horizontal"
        android:layout_marginVertical="8dp"/>
    <NumberPicker
        android:id="@+id/seconds"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:descendantFocusability="blocksDescendants" />
</LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

MyTimePicker class

package com.themarto.mytimepicker

import android.app.AlertDialog
import android.app.Dialog
import android.os.Bundle
import android.view.View
import android.widget.LinearLayout
import android.widget.NumberPicker
import androidx.fragment.app.DialogFragment

/**
* Time Picker that shows a Dialog to select
* hours, minutes and seconds. You can choose
* to use only minutes and seconds by setting
* to false the property "includeHours".
*/
class MyTimePicker() : DialogFragment() {

    private lateinit var timePickerLayout: View
    private lateinit var hourPicker: NumberPicker
    private lateinit var minPicker: NumberPicker
    private lateinit var secPicker: NumberPicker

    private var onTimeSetOption:
                (hour: Int, minute: Int, second: Int) -> Unit = {_, _, _ -> }
    private var timeSetText: String = "Ok"

    private var onCancelOption: () -> Unit = {}
    private var cancelText: String = "Cancel"

    /**
    * Which value will appear a the start of
    * the Dialog for the Hour picker.
    * Default value is 0.
    */
    var initialHour: Int = 0
    /**
    * Which value will appear a the start of
    * the Dialog for the Minute picker.
    * Default value is 0.
    */
    var initialMinute: Int = 0
    /**
    * Which value will appear a the start of
    * the Dialog for the Second picker.
    * Default value is 0.
    */
    var initialSeconds: Int = 0

    /**
    * Max value for the Hour picker.
    * Default value is 23.
    */
    var maxValueHour: Int = 23
    /**
    * Max value for the Minute picker.
    * Default value is 59.
    */
    var maxValueMinute: Int = 59
    /**
    * Max value for the Second picker.
    * Default value is 59.
    */
    var maxValueSeconds: Int = 59

    /**
    * Min value for the Hour picker.
    * Default value is 0.
    */
    var minValueHour: Int = 0
    /**
    * Min value for the Minute picker.
    * Default value is 0.
    */
    var minValueMinute: Int = 0
    /**
    * Min value for the Second picker.
    * Default value is 0.
    */
    var minValueSecond: Int = 0

    /**
    * Default value is true.
    * If set to false the hour picker is not
    * visible in the Dialog
    */
    var includeHours: Boolean = true

    private var title: String? = null

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return activity?.let {
            // Use the Builder class for convenient dialog construction
            val builder = AlertDialog.Builder(it)

            timePickerLayout = requireActivity()
                .layoutInflater.inflate(R.layout.my_time_picker_content, null)

            setupTimePickerLayout()

            builder.setView(timePickerLayout)

            title?.let { title ->
                builder.setTitle(title)
            }
            builder.setPositiveButton(timeSetText) { _, _ ->
                var hour = hourPicker.value
                if (!includeHours) hour = 0
                onTimeSetOption(hour, minPicker.value, secPicker.value)
            }
                .setNegativeButton(cancelText) { _, _ ->
                    onCancelOption
                }
            // Create the AlertDialog object and return it
            builder.create()
        } ?: throw IllegalStateException("Activity cannot be null")
    }

    /**
    * Set the title displayed in the Dialog
    */
    fun setTitle(title: String) {
        this.title = title
    }

    /**
    * Set a listener to be invoked when the Set Time button of the dialog is pressed.
    * If have set includeHours to false, the hour parameter here will be always 0.
    * @param text text to display in the Set Time button.
    */
    fun setOnTimeSetOption (text: String, onTimeSet: (hour: Int, minute: Int, second: Int) -> Unit) {
        onTimeSetOption = onTimeSet
        timeSetText = text
    }

    /**
    * Set a listener to be invoked when the Cancel button of the dialog is pressed.
    * @param text text to display in the Cancel button.
    */
    fun setOnCancelOption (text: String, onCancelOption: () -> Unit) {
        this.onCancelOption = onCancelOption
        cancelText = text
    }

    private fun setupTimePickerLayout() {
        bindViews()

        setupMaxValues()
        setupMinValues()
        setupInitialValues()

        if (!includeHours) {
            timePickerLayout.findViewById<LinearLayout>(R.id.hours_container)
                .visibility = View.GONE
        }
    }

    private fun bindViews() {
        hourPicker = timePickerLayout.findViewById<NumberPicker>(R.id.hours)
        minPicker = timePickerLayout.findViewById<NumberPicker>(R.id.minutes)
        secPicker = timePickerLayout.findViewById<NumberPicker>(R.id.seconds)
    }

    private fun setupMaxValues () {
        hourPicker.maxValue = maxValueHour
        minPicker.maxValue = maxValueMinute
        secPicker.maxValue = maxValueSeconds
    }

    private fun setupMinValues () {
        hourPicker.minValue = minValueHour
        minPicker.minValue = minValueMinute
        secPicker.minValue = minValueSecond
    }

    private fun setupInitialValues () {
        hourPicker.value = initialHour
        minPicker.value = initialMinute
        secPicker.value = initialSeconds
    }
}

MainActivity class

package com.themarto.mytimepicker

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView

class MainActivity : AppCompatActivity() {
    private lateinit var timeText: TextView
    private lateinit var showDialogBtn: Button

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

        timeText = findViewById(R.id.timeText)
        showDialogBtn = findViewById(R.id.showDialogButton)

        showDialogBtn.setOnClickListener {

            val timePicker = MyTimePicker()
            timePicker.setTitle("Select time")
            //timePicker.includeHours = false
            timePicker.setOnTimeSetOption("Set time") {hour, minute, second ->
                timeText.text = "$hour : $minute : $second"
            }

            /* To show the dialog you have to supply the "fragment manager"
                and a tag (whatever you want)
            */
            timePicker.show(supportFragmentManager, "time_picker")
        }
    }
}
1
On

I've published an open source project on GitHub which has TimePicker with seconds:

https://github.com/IvanKovac/TimePickerWithSeconds

Have a look.

enter image description here

1
On

The best way around this would be to create three separate 'number pickers' instead of timepicker... I placed them within a linear layout and its working fine.

Then all you do is store the values inside three separate variables. int Hours, int Minutes, int Seconds and do your calculating.

This was my way around it without downloading any external sources which may contain viruses.

<LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center">

            <NumberPicker
                android:id="@+id/numpicker_hours"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">

            </NumberPicker>

            <NumberPicker
                android:id="@+id/numpicker_minutes"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="8dp"
                android:layout_marginRight="8dp">

            </NumberPicker>

            <NumberPicker
                android:id="@+id/numpicker_seconds"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">

            </NumberPicker>

        </LinearLayout>