简体   繁体   中英

Android digital clock textview timepicker using buttons

I'm newbie Java programmer and newbie Android app developer... and i'm trying to make a simple 24h digital clock acting like a timepicker. I don't want to use the standard TimePicker widget in this case. App should work on Android 2.1+ also.

My clock i supposed look like this 23:59 . When the user clicks on the clock rightmost field, buttons ranging from 0 to 9 (placed in the same Fragment) should update this rightmost field. The field should also be highlighted. I accomplished this with

    view.setBackgroundResource(R.color.solid_grey);

Other fields should be updated in the same way, with some logic to avoid invalid values of course. Highlighting should be removed from first touched field when user touch another field.

My crappy solution to the problem: What i did was to make five TextViews, one for each number and one for the colon. I have attached onTouch listeners to the changeable fields in the clock and onClick listeners for the buttons. Then i have some more or less complicated code with viewholders and tagging buttons with viewholder and what not to get all of this to work.

There MUST be a better way to do this! Don't you think?

First i tried to have a single TextView and just check which index in the string representing the clock in the textview, that was clicked. But this didn't work very good with highlighting. The index was also hard to compute with precision since i could not come up with a better idea than to use

    (int) event.getX();

inside the OnTouchListener for the clock TextView.

Any ideas on how to accomplish this in the simplest possible way? If not, i have to stick with the butt-ugly hard to maintain code i made (no i won't post it here). :S

Ok, i'll post my own bulky solution here. It might not be pretty but it is working. Feel free to modify it to your liking. Keep in mind that I'm a newbie from Sweden. :P

colors.xml

    <?xml version="1.0" encoding="utf-8"?>
    <resources>    
        <!-- The two most significant hex sets the transparency value -->
        <color name="timefield_highlight_color">#FF8F8F8F</color>
        <color name="timefield_no_highlight_color">#FF000000</color>
    </resources>

timepicker_digital_24h.xml Change the @dimen-stuff to your liking. Include this in your layout, using xml include-tag, wherever you want. DON'T change the id: s of the views.

    <merge xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <RelativeLayout
            android:id="@+id/layout_timepicker_digital_24h"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="@dimen/vertical_margin" >

            <TextView
                android:id="@+id/textview_time_set_colon_divider"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:maxLength="1"
                android:singleLine="true"
                android:text=""
                android:textSize="@dimen/alarm_time_huge_textsize"
                tools:ignore="SpUsage" />

            <TextView
                android:id="@+id/textview_time_set_hour_right"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_toLeftOf="@id/textview_time_set_colon_divider"
                android:maxLength="1"
                android:singleLine="true"
                android:text=""
                android:textSize="@dimen/alarm_time_huge_textsize"
                tools:ignore="SpUsage" />

            <TextView
                android:id="@+id/textview_time_set_hour_left"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_toLeftOf="@id/textview_time_set_hour_right"
                android:maxLength="1"
                android:singleLine="true"
                android:text=""
                android:textSize="@dimen/alarm_time_huge_textsize"
                tools:ignore="SpUsage" />

            <TextView
                android:id="@+id/textview_time_set_minute_left"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_toRightOf="@id/textview_time_set_colon_divider"
                android:maxLength="1"
                android:singleLine="true"
                android:text=""
                android:textSize="@dimen/alarm_time_huge_textsize"
                tools:ignore="SpUsage" />

            <TextView
                android:id="@+id/textview_time_set_minute_right"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_toRightOf="@id/textview_time_set_minute_left"
                android:maxLength="1"
                android:singleLine="true"
                android:text=""
                android:textSize="@dimen/alarm_time_huge_textsize"
                tools:ignore="SpUsage" />
        </RelativeLayout>

        <LinearLayout
            android:id="@+id/layout_time_buttons_row_1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="@dimen/horizontal_margin_small"
            android:layout_marginRight="@dimen/horizontal_margin_small" >

            <Button
                android:id="@+id/button_1_time_set"
                style="?android:attr/buttonStyleSmall"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/button_set_time_margin"
                android:layout_weight="1"
                android:text="1"
                android:textSize="@dimen/button_set_time_textsize"
                tools:ignore="HardcodedText" />

            <Button
                android:id="@+id/button_2_time_set"
                style="?android:attr/buttonStyleSmall"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/button_set_time_margin"
                android:layout_weight="1"
                android:text="2"
                android:textSize="@dimen/button_set_time_textsize"
                tools:ignore="HardcodedText" />

            <Button
                android:id="@+id/button_3_time_set"
                style="?android:attr/buttonStyleSmall"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/button_set_time_margin"
                android:layout_weight="1"
                android:text="3"
                android:textSize="@dimen/button_set_time_textsize"
                tools:ignore="HardcodedText" />
        </LinearLayout>

        <LinearLayout
            android:id="@+id/layout_time_buttons_row_2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="@dimen/horizontal_margin_small"
            android:layout_marginRight="@dimen/horizontal_margin_small" >

            <Button
                android:id="@+id/button_4_time_set"
                style="?android:attr/buttonStyleSmall"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/button_set_time_margin"
                android:layout_weight="1"
                android:text="4"
                android:textSize="@dimen/button_set_time_textsize"
                tools:ignore="HardcodedText" />

            <Button
                android:id="@+id/button_5_time_set"
                style="?android:attr/buttonStyleSmall"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/button_set_time_margin"
                android:layout_weight="1"
                android:text="5"      
                android:textSize="@dimen/button_set_time_textsize"
                tools:ignore="HardcodedText" />

            <Button
                android:id="@+id/button_6_time_set"
                style="?android:attr/buttonStyleSmall"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/button_set_time_margin"
                android:layout_weight="1"
                android:text="6"
                android:textSize="@dimen/button_set_time_textsize"
                tools:ignore="HardcodedText" />
        </LinearLayout>

        <LinearLayout
            android:id="@+id/layout_time_buttons_row_3"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="@dimen/horizontal_margin_small"
            android:layout_marginRight="@dimen/horizontal_margin_small" >

            <Button
                android:id="@+id/button_7_time_set"
                style="?android:attr/buttonStyleSmall"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/button_set_time_margin"
                android:layout_weight="1"
                android:text="7"
                android:textSize="@dimen/button_set_time_textsize"
                tools:ignore="HardcodedText" />

            <Button
                android:id="@+id/button_8_time_set"
                style="?android:attr/buttonStyleSmall"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/button_set_time_margin"
                android:layout_weight="1"
                android:text="8"
                android:textSize="@dimen/button_set_time_textsize"
                tools:ignore="HardcodedText" />

            <Button
                android:id="@+id/button_9_time_set"
                style="?android:attr/buttonStyleSmall"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/button_set_time_margin"
                android:layout_weight="1"
                android:text="9"
                android:textSize="@dimen/button_set_time_textsize"
                tools:ignore="HardcodedText" />
        </LinearLayout>

        <Button
            android:id="@+id/button_0_time_set"
            style="?android:attr/buttonStyleSmall"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="@dimen/vertical_margin_large"
            android:layout_marginLeft="@dimen/horizontal_margin"
            android:layout_marginRight="@dimen/horizontal_margin"
            android:layout_marginTop="@dimen/button_set_time_margin"
            android:text="0"
            android:textSize="@dimen/button_set_time_textsize"
            tools:ignore="HardcodedText" />

    </merge>

Enums.java

    package com.example.example.timepicker;

    public class Enums {

            public static enum TimeField {
                HOUR_LEFT, HOUR_RIGHT, MINUTE_LEFT, MINUTE_RIGHT, NONE;


            public TimeField nextReal()  {  

                TimeField fields[] = TimeField.values();
                int ordinal = this.ordinal(); // incoming field index

                switch(ordinal) {
                case 0:                                     // HOUR_LEFT
                    ordinal = 1;
                    break;
                case 1:                                     // HOUR_RIGHT
                    ordinal = 2;
                    break;
                case 2:                             // MINUTE_LEFT
                    ordinal = 3;
                    break;
                case 3:                             // MINUTE_RIGHT
                    ordinal = 0;
                    break;
                case 4:                             // NONE
                    ordinal = 0;
                }
                return fields[ordinal];
            }  
            }

    }

TimePickerDigital24h.java

(There is a toast-string in this code that you have to define in your strings.xml .)

    package com.example.example.timepicker;

    import android.app.Activity;
    import android.content.Context;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.View.OnTouchListener;
    import android.widget.Button;
    import android.widget.TextView;
    import android.widget.Toast;

    import com.example.example.R;
    import com.example.example.timepicker.Enums.TimeField;

    public class TimePickerDigital24h implements OnClickListener, OnTouchListener {

            private TimeField mTimeFieldToSet = TimeField.HOUR_LEFT;
            private TextView mTextViewHourLeft, mTextViewHourRight, mTextViewMinuteLeft, mTextViewMinuteRight;
            private Context mContext;

            public TimePickerDigital24h (Context context, String hourOfDay, String minute) {

                    mContext = context;

                    mTextViewHourLeft = (TextView) ((Activity) context).findViewById(R.id.textview_time_set_hour_left);
                    mTextViewHourLeft.setText(hourOfDay.substring(0, 1));
                    mTextViewHourRight = (TextView) ((Activity) context).findViewById(R.id.textview_time_set_hour_right);   
                    mTextViewHourRight.setText(hourOfDay.substring(1, 2));
                    mTextViewMinuteLeft = (TextView) ((Activity) context).findViewById(R.id.textview_time_set_minute_left);
                    mTextViewMinuteLeft.setText(minute.substring(0, 1));
                    mTextViewMinuteRight = (TextView) ((Activity) context).findViewById(R.id.textview_time_set_minute_right);
                    mTextViewMinuteRight.setText(minute.substring(1, 2));

                    mTextViewHourLeft.setOnTouchListener(this);
                    mTextViewHourRight.setOnTouchListener(this);
                    mTextViewMinuteLeft.setOnTouchListener(this);
                    mTextViewMinuteRight.setOnTouchListener(this);

                    this.setTimeFieldHighlight(TimeField.HOUR_LEFT);

                    Button button0 = (Button) ((Activity) context).findViewById(R.id.button_0_time_set);
                    button0.setOnClickListener(this);
                    Button button1 = (Button) ((Activity) context).findViewById(R.id.button_1_time_set);
                    button1.setOnClickListener(this);
                    Button button2 = (Button) ((Activity) context).findViewById(R.id.button_2_time_set);
                    button2.setOnClickListener(this);
                    Button button3 = (Button) ((Activity) context).findViewById(R.id.button_3_time_set);
                    button3.setOnClickListener(this);
                    Button button4 = (Button) ((Activity) context).findViewById(R.id.button_4_time_set);
                    button4.setOnClickListener(this);
                    Button button5 = (Button) ((Activity) context).findViewById(R.id.button_5_time_set);
                    button5.setOnClickListener(this);
                    Button button6 = (Button) ((Activity) context).findViewById(R.id.button_6_time_set);
                    button6.setOnClickListener(this);
                    Button button7 = (Button) ((Activity) context).findViewById(R.id.button_7_time_set);
                    button7.setOnClickListener(this);
                    Button button8 = (Button) ((Activity) context).findViewById(R.id.button_8_time_set);
                    button8.setOnClickListener(this);
                    Button button9 = (Button) ((Activity) context).findViewById(R.id.button_9_time_set);
                    button9.setOnClickListener(this);
            }


            @Override
            public boolean onTouch(View view, MotionEvent event) {
                    switch(view.getId()) {
                    case R.id.textview_time_set_hour_left:
                            mTimeFieldToSet = TimeField.HOUR_LEFT;
                            this.setTimeFieldHighlight(mTimeFieldToSet);
                            return true;
                    case R.id.textview_time_set_hour_right:
                            mTimeFieldToSet = TimeField.HOUR_RIGHT;
                            this.setTimeFieldHighlight(mTimeFieldToSet);
                            return true;
                    case R.id.textview_time_set_minute_left:
                            mTimeFieldToSet = TimeField.MINUTE_LEFT;
                            this.setTimeFieldHighlight(mTimeFieldToSet);
                            return true;
                    case R.id.textview_time_set_minute_right:
                            mTimeFieldToSet = TimeField.MINUTE_RIGHT;
                            this.setTimeFieldHighlight(mTimeFieldToSet);
                            return true;
                    }
                    return false;
            }


            @Override
            public void onClick(View view) {

                    int valueToSet = 0;

                    switch(view.getId()) {
                    case R.id.button_0_time_set:
                            valueToSet = 0;
                            break;
                    case R.id.button_1_time_set:
                            valueToSet = 1;
                            break;
                    case R.id.button_2_time_set:
                            valueToSet = 2;
                            break;
                    case R.id.button_3_time_set:
                            valueToSet = 3;
                            break;
                    case R.id.button_4_time_set:
                            valueToSet = 4;
                            break;
                    case R.id.button_5_time_set:
                            valueToSet = 5;
                            break;
                    case R.id.button_6_time_set:
                            valueToSet = 6;
                            break;
                    case R.id.button_7_time_set:
                            valueToSet = 7;
                            break;
                    case R.id.button_8_time_set:
                            valueToSet = 8;
                            break;
                    case R.id.button_9_time_set:
                            valueToSet = 9;
                            break;
                    }

                    try {
                            this.setTimeField(valueToSet);
                    } catch (UnsupportedOperationException e) {
                            Toast.makeText(mContext, mContext.getString(R.string.toast_time_set_error), Toast.LENGTH_LONG).show();
                            //e.printStackTrace();
                    }

            }

            // Setter for timefields in the clock time display. Also highlights the correct field.
            private void setTimeField (int valueToSet) throws UnsupportedOperationException {
                    int hourLeft = Integer.parseInt(mTextViewHourLeft.getText().toString());
                    int hourRight = Integer.parseInt(mTextViewHourRight.getText().toString());

                    UnsupportedOperationException exception = new UnsupportedOperationException("Input value invalid for this clock field");

                    setTimeFieldHighlight(mTimeFieldToSet.nextReal());

                    switch(mTimeFieldToSet) {       
                    case HOUR_LEFT:
                            if (valueToSet <= 1) {
                                    mTextViewHourLeft.setText("" + valueToSet);
                                    mTimeFieldToSet = TimeField.HOUR_RIGHT;
                                    break;
                            } else if (valueToSet <= 2 && hourRight <= 3) {
                                    mTextViewHourLeft.setText("" + valueToSet);
                                    mTimeFieldToSet = TimeField.HOUR_RIGHT;
                                    break;
                            } else if (valueToSet <= 2 && hourRight >= 4) {
                                    mTextViewHourRight.setText("3");
                                    mTextViewHourLeft.setText("" + valueToSet);
                                    mTimeFieldToSet = TimeField.HOUR_RIGHT;
                                    break;
                            } else {
                                    setTimeFieldHighlight(mTimeFieldToSet);
                                    throw exception;
                            }

                    case HOUR_RIGHT:
                            if (valueToSet <= 3) {
                                    mTextViewHourRight.setText("" + valueToSet);
                                    mTimeFieldToSet = TimeField.MINUTE_LEFT;
                                    break;
                            } else if (valueToSet > 3 && hourLeft <= 1) {
                                    mTextViewHourRight.setText("" + valueToSet);
                                    mTimeFieldToSet = TimeField.MINUTE_LEFT;
                                    break;
                            } else if (valueToSet > 3 && hourLeft >= 2) {
                                    mTextViewHourLeft.setText("1");
                                    mTextViewHourRight.setText("" + valueToSet);
                                    mTimeFieldToSet = TimeField.MINUTE_LEFT;
                                    break;
                            } else {
                                    setTimeFieldHighlight(mTimeFieldToSet);
                                    throw exception;
                            }

                    case MINUTE_LEFT:
                            if (valueToSet <= 5) {
                                    mTextViewMinuteLeft.setText("" + valueToSet);
                                    mTimeFieldToSet = TimeField.MINUTE_RIGHT;
                                    break;
                            } else {
                                    setTimeFieldHighlight(mTimeFieldToSet);
                                    throw exception;
                            }

                    case MINUTE_RIGHT:
                            mTextViewMinuteRight.setText("" + valueToSet);
                            mTimeFieldToSet = TimeField.HOUR_LEFT;
                            break;

                    case NONE:
                    }

            }

            // Highlighting of the fields in the clock display
            private void setTimeFieldHighlight(TimeField field) {

                    switch(field) {
                    case HOUR_LEFT:
                            mTextViewHourLeft.setBackgroundResource(R.color.timefield_highlight_color);
                            mTextViewHourRight.setBackgroundResource(R.color.timefield_no_highlight_color);
                            mTextViewMinuteLeft.setBackgroundResource(R.color.timefield_no_highlight_color);
                            mTextViewMinuteRight.setBackgroundResource(R.color.timefield_no_highlight_color);
                            break;
                    case HOUR_RIGHT:
                            mTextViewHourLeft.setBackgroundResource(R.color.timefield_no_highlight_color);
                            mTextViewHourRight.setBackgroundResource(R.color.timefield_highlight_color);
                            mTextViewMinuteLeft.setBackgroundResource(R.color.timefield_no_highlight_color);
                            mTextViewMinuteRight.setBackgroundResource(R.color.timefield_no_highlight_color);
                            break;
                    case MINUTE_LEFT:
                            mTextViewHourLeft.setBackgroundResource(R.color.timefield_no_highlight_color);
                            mTextViewHourRight.setBackgroundResource(R.color.timefield_no_highlight_color);
                            mTextViewMinuteLeft.setBackgroundResource(R.color.timefield_highlight_color);
                            mTextViewMinuteRight.setBackgroundResource(R.color.timefield_no_highlight_color);
                            break;
                    case MINUTE_RIGHT:
                            mTextViewHourLeft.setBackgroundResource(R.color.timefield_no_highlight_color);
                            mTextViewHourRight.setBackgroundResource(R.color.timefield_no_highlight_color);
                            mTextViewMinuteLeft.setBackgroundResource(R.color.timefield_no_highlight_color);
                            mTextViewMinuteRight.setBackgroundResource(R.color.timefield_highlight_color);
                            break;
                    case NONE:
                            mTextViewHourLeft.setBackgroundResource(R.color.timefield_no_highlight_color);
                            mTextViewHourRight.setBackgroundResource(R.color.timefield_no_highlight_color);
                            mTextViewMinuteLeft.setBackgroundResource(R.color.timefield_no_highlight_color);
                            mTextViewMinuteRight.setBackgroundResource(R.color.timefield_no_highlight_color);
                    }

            }

            public String getHourOfDay() {
                    String hourOfDay = mTextViewHourLeft.getText().toString()
                                    + mTextViewHourRight.getText().toString();
                    return hourOfDay;
            }

            public String getMinute() {
                    String minute = mTextViewMinuteLeft.getText().toString()
                                    + mTextViewMinuteRight.getText().toString();
                    return minute;
            }

    }

**Put this code in your Fragment's OnActivityCreated method to instantiate the TimePickerDigital24h object: **

    mTimePicker = new TimePickerDigital24h(getActivity(), "23", "59");

You can read back the time set by the user this way:

    mTimePicker.getHourOfDay();
    mTimePicker.getMinute();

I'm sure the code could be better in many ways. If you guys know how to do this in a much simpler way, please let me know. / TiredDude

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM