Android TimePicker AM/PM 按钮不调用 onTimeChanged

发布于 2024-12-29 06:59:24 字数 2249 浏览 2 评论 0 原文

我在应用程序中实现 TimePicker 时遇到一些问题,该应用程序允许用户在插入数据库记录之前更改数据库记录的时间。

问题是,当按下 AM/PM 按钮时,不会调用 onTimeChanged(View, int, int) 方法。然而,每当我更改 TimePicker 的小时或分钟值时,都会调用 onTimeChanged() 。

场景:

  • 用户只需单击 AM/PM 按钮:AM/PM 更新
  • 用户单击小时/分钟:时间更新
  • 用户单击 AM/PM 按钮,然后更改小时/分钟:时间和AM/PM 已更新

我是否错误地认为应该能够单击 AM/PM 按钮来更新时间,而不必在 am/pm 按钮之后更改时间值?

我整理了一个小型测试项目来复制此内容,代码如下:

Activity

public class TestActivity extends Activity implements OnTimeChangedListener {

    private Calendar mCalendar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.timepicker);

        mCalendar = Calendar.getInstance();

        TimePicker tp = (TimePicker)findViewById(R.id.timepicker);
        tp.setIs24HourView(false);
        tp.setOnTimeChangedListener(this);
    }

    @Override
    public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
        Log.d("TAG", "In onTimeChanged");
        mCalendar.set(mCalendar.get(Calendar.YEAR),
                      mCalendar.get(Calendar.MONTH),
                      mCalendar.get(Calendar.DAY_OF_MONTH),
                      hourOfDay,
                      minute);

        setCalendarTime();
    }

    private void setCalendarTime() {
        Date date = mCalendar.getTime();

        if (date != null) {
            SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yy '@' h:mm a");
            String dateTime = formatter.format(date);

            Toast.makeText(this, dateTime, Toast.LENGTH_LONG).show();
        }
    }
}

timepicker.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:fillViewport="true">
    <TimePicker android:id="@+id/timepicker"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="5dip"
                android:layout_marginRight="5dip"/>
</LinearLayout>

I'm having some issues implementing a TimePicker in my application that allows the user to change the time of a database record prior to inserting it.

The problem is that when the AM/PM button is pressed, the onTimeChanged(View, int, int) method isn't invoked. Whenever I change either the hour or minute value of the TimePicker, onTimeChanged() is called, however.

Scenarios:

  • User just clicks the AM/PM button: AM/PM is NOT updated
  • User clicks the Hours/Minutes: Time is updated
  • User clicks the AM/PM button then changes the hours/minutes: Time and AM/PM is updated

Am I wrong in thinking that the AM/PM button should be able to be clicked to update the time without having to also change a time value after the am/pm button?

I've put together a small test project to replicate this and here's the code:

Activity

public class TestActivity extends Activity implements OnTimeChangedListener {

    private Calendar mCalendar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.timepicker);

        mCalendar = Calendar.getInstance();

        TimePicker tp = (TimePicker)findViewById(R.id.timepicker);
        tp.setIs24HourView(false);
        tp.setOnTimeChangedListener(this);
    }

    @Override
    public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
        Log.d("TAG", "In onTimeChanged");
        mCalendar.set(mCalendar.get(Calendar.YEAR),
                      mCalendar.get(Calendar.MONTH),
                      mCalendar.get(Calendar.DAY_OF_MONTH),
                      hourOfDay,
                      minute);

        setCalendarTime();
    }

    private void setCalendarTime() {
        Date date = mCalendar.getTime();

        if (date != null) {
            SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yy '@' h:mm a");
            String dateTime = formatter.format(date);

            Toast.makeText(this, dateTime, Toast.LENGTH_LONG).show();
        }
    }
}

timepicker.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:fillViewport="true">
    <TimePicker android:id="@+id/timepicker"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="5dip"
                android:layout_marginRight="5dip"/>
</LinearLayout>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

霓裳挽歌倾城醉 2025-01-05 06:59:24

我已经测试了代码。是的,你是对的,TimePicker AM/PM 按钮没有调用它应该调用的 onTimeChanged 方法。

实际上,这是一个错误。已向谷歌报告。您可以在这里找到它
http://code.google.com/p/android/issues/detail ?id=18982

请投票、评论和评论给错误报告加注星标以提高其优先级并让开发团队尽快修复。

I have tested the code. Yes, you are right, TimePicker AM/PM button not invoking onTimeChanged method which it should.

Actually, Its a bug. It has been reported to google. You can find it here
http://code.google.com/p/android/issues/detail?id=18982

Please vote, comment & Star the bug report to raise its priority and to get it fixed by development team as soon as possible.

小姐丶请自重 2025-01-05 06:59:24

我找到了这个答案,但它对我不起作用,所以我想我会更新。

在 3.2(及更高版本?)中,时间选择器没有上午/下午按钮。相反,它有一个 NumberPicker。以下代码对我有用。最后一点是因为我需要将选择的时间限制为不早于“最小”日期且不大于“最大”日期,因此我必须检查匹配的 DatePicker 控件中选择的日期:

        NumberPicker amPmView  = (NumberPicker)((ViewGroup)tp.getChildAt(0)).getChildAt(3);
        amPmView.setOnValueChangedListener(new OnValueChangeListener() { 
            @Override
            public void onValueChange(NumberPicker arg0, int arg1, int arg2) {
                if(arg0.getValue()== 1){ 
                    if (tp.getCurrentHour() < 12)
                        tp.setCurrentHour(tp.getCurrentHour() + 12); 
                } 
                else{ 
                    if (tp.getCurrentHour() >= 12) 
                        tp.setCurrentHour(tp.getCurrentHour() - 12); 
                } 

                int year = dp.getYear();
                int month = dp.getMonth();
                int dayOfMonth = dp.getDayOfMonth();
                int hourOfDay = tp.getCurrentHour();
                int minute = tp.getCurrentMinute();

                if (year == min.get(Calendar.YEAR) && month == min.get(Calendar.MONTH) && dayOfMonth == min.get(Calendar.DAY_OF_MONTH)){
                    if ((hourOfDay < min.get(Calendar.HOUR_OF_DAY))||
                        (hourOfDay == min.get(Calendar.HOUR_OF_DAY) && (minute < min.get(Calendar.MINUTE)))){
                        tp.setCurrentHour(min.get(Calendar.HOUR_OF_DAY));
                        tp.setCurrentMinute(min.get(Calendar.MINUTE));
                    }
                }else if (year == max.get(Calendar.YEAR) && month == max.get(Calendar.MONTH) && dayOfMonth == max.get(Calendar.DAY_OF_MONTH)){
                    if ((hourOfDay > max.get(Calendar.HOUR_OF_DAY))||
                        (hourOfDay == max.get(Calendar.HOUR_OF_DAY) && (minute > max.get(Calendar.MINUTE)))){
                        tp.setCurrentHour(max.get(Calendar.HOUR_OF_DAY));
                        tp.setCurrentMinute(max.get(Calendar.MINUTE));
                    }
                }
            } 
        }); 

I found this answer, but it didn't work for me, so I thought I would update.

In 3.2 (and above?), the time picker does not have a button for am/pm. Instead it has a NumberPicker. The following code worked for me. The last bit is there because I needed to limit the time selected to no earlier than the 'min' date and no greater than the 'max' date, so I had to check the date selected in the matching DatePicker control:

        NumberPicker amPmView  = (NumberPicker)((ViewGroup)tp.getChildAt(0)).getChildAt(3);
        amPmView.setOnValueChangedListener(new OnValueChangeListener() { 
            @Override
            public void onValueChange(NumberPicker arg0, int arg1, int arg2) {
                if(arg0.getValue()== 1){ 
                    if (tp.getCurrentHour() < 12)
                        tp.setCurrentHour(tp.getCurrentHour() + 12); 
                } 
                else{ 
                    if (tp.getCurrentHour() >= 12) 
                        tp.setCurrentHour(tp.getCurrentHour() - 12); 
                } 

                int year = dp.getYear();
                int month = dp.getMonth();
                int dayOfMonth = dp.getDayOfMonth();
                int hourOfDay = tp.getCurrentHour();
                int minute = tp.getCurrentMinute();

                if (year == min.get(Calendar.YEAR) && month == min.get(Calendar.MONTH) && dayOfMonth == min.get(Calendar.DAY_OF_MONTH)){
                    if ((hourOfDay < min.get(Calendar.HOUR_OF_DAY))||
                        (hourOfDay == min.get(Calendar.HOUR_OF_DAY) && (minute < min.get(Calendar.MINUTE)))){
                        tp.setCurrentHour(min.get(Calendar.HOUR_OF_DAY));
                        tp.setCurrentMinute(min.get(Calendar.MINUTE));
                    }
                }else if (year == max.get(Calendar.YEAR) && month == max.get(Calendar.MONTH) && dayOfMonth == max.get(Calendar.DAY_OF_MONTH)){
                    if ((hourOfDay > max.get(Calendar.HOUR_OF_DAY))||
                        (hourOfDay == max.get(Calendar.HOUR_OF_DAY) && (minute > max.get(Calendar.MINUTE)))){
                        tp.setCurrentHour(max.get(Calendar.HOUR_OF_DAY));
                        tp.setCurrentMinute(max.get(Calendar.MINUTE));
                    }
                }
            } 
        }); 
明媚殇 2025-01-05 06:59:24

在代码中创建 TimePicker 时遇到同样的问题,并且提供的解决方案都不适合我。以下是我最终所做的。在 API 级别 18、21 和 23 上进行测试

final TimePicker tp = new TimePicker(getContext());
tp.setOnTimeChangedListener(this);
try {
    ViewGroup amPmView;
    ViewGroup v1 = (ViewGroup)tp.getChildAt(0);
    ViewGroup v2 = (ViewGroup)v1.getChildAt(0);
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        ViewGroup v3 = (ViewGroup)v2.getChildAt(0);
        amPmView = (ViewGroup)v3.getChildAt(3);
    } else {
        amPmView = (ViewGroup)v2.getChildAt(3);
    }
    View.OnClickListener listener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            tp.setCurrentHour((tp.getCurrentHour() + 12) % 24);
        }
    };
    View am = amPmView.getChildAt(0);
    View pm = amPmView.getChildAt(1);
    am.setOnClickListener(listener);
    pm.setOnClickListener(listener);
} catch (Exception e) {
    // DO nothing... just ignore the workaround if this fails.
}

Had the same issue when creating the TimePicker in code and none of the provided solutions worked for me. Below was what I ended up doing. Tested on API levels 18, 21 and 23

final TimePicker tp = new TimePicker(getContext());
tp.setOnTimeChangedListener(this);
try {
    ViewGroup amPmView;
    ViewGroup v1 = (ViewGroup)tp.getChildAt(0);
    ViewGroup v2 = (ViewGroup)v1.getChildAt(0);
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        ViewGroup v3 = (ViewGroup)v2.getChildAt(0);
        amPmView = (ViewGroup)v3.getChildAt(3);
    } else {
        amPmView = (ViewGroup)v2.getChildAt(3);
    }
    View.OnClickListener listener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            tp.setCurrentHour((tp.getCurrentHour() + 12) % 24);
        }
    };
    View am = amPmView.getChildAt(0);
    View pm = amPmView.getChildAt(1);
    am.setOnClickListener(listener);
    pm.setOnClickListener(listener);
} catch (Exception e) {
    // DO nothing... just ignore the workaround if this fails.
}
ヅ她的身影、若隐若现 2025-01-05 06:59:24

Velval 解决方案是唯一适用于不同 Android 版本且兼容的解决方案。我在 api 17 和 23 上尝试过。但它有一个问题,它阻止了 Android 6 上的原始点击侦听器。所以这是对我有用的。使用触摸而不是单击:

public class MyTimePicker extends TimePicker {

    private OnTimeChangedListener onTimeChangedListener;

    public MyTimePicker(Context context) {
        super(context);
        //  init();
    }

    public MyTimePicker(Context context, AttributeSet attrs) {
        super(context, attrs);
        //init();
    }

    public MyTimePicker(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // init();
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public MyTimePicker(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // Stop ScrollView from getting involved once you interact with the View
        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
            ViewParent p = getParent();
            if (p != null)
                p.requestDisallowInterceptTouchEvent(true);
        }
        return false;
    }

    @Override
    public void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener) {
        super.setOnTimeChangedListener(onTimeChangedListener);
        this.onTimeChangedListener = onTimeChangedListener;
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        init();
    }

    private void init() {

        try {
            ViewGroup amPmView;
            ViewGroup v1 = (ViewGroup) getChildAt(0);
            ViewGroup v2 = (ViewGroup) v1.getChildAt(0);
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                ViewGroup v3 = (ViewGroup) v2.getChildAt(0);
                amPmView = (ViewGroup) v3.getChildAt(3);
            } else {
                amPmView = (ViewGroup) v2.getChildAt(3);
            }
            View.OnTouchListener listener = new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                        onTimeChangedListener.onTimeChanged(MyTimePicker.this, getCurrentHour(), getCurrentMinute());
                    } else {
                        int hour = getCurrentHour();
                        if (hour >= 12) {
                            hour -= 12;
                        } else {
                            hour += 12;
                        }
                        onTimeChangedListener.onTimeChanged(MyTimePicker.this, hour, getCurrentMinute());
                    }

                    return false;
                }

            };
            View am = amPmView.getChildAt(0);
            View pm = amPmView.getChildAt(1);

            am.setOnTouchListener(listener);
            pm.setOnTouchListener(listener);
        } catch (Exception e) {
            // DO nothing... just ignore the workaround if this fails.
        }


    }
}

Velval solution is the only solution that works and compatiple with different Android vesrions. I tried it on api 17 and 23. but it has an issue that it prevent original on click listener on Android 6. so here is what worked with me. to use touch instead of click:

public class MyTimePicker extends TimePicker {

    private OnTimeChangedListener onTimeChangedListener;

    public MyTimePicker(Context context) {
        super(context);
        //  init();
    }

    public MyTimePicker(Context context, AttributeSet attrs) {
        super(context, attrs);
        //init();
    }

    public MyTimePicker(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // init();
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public MyTimePicker(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // Stop ScrollView from getting involved once you interact with the View
        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
            ViewParent p = getParent();
            if (p != null)
                p.requestDisallowInterceptTouchEvent(true);
        }
        return false;
    }

    @Override
    public void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener) {
        super.setOnTimeChangedListener(onTimeChangedListener);
        this.onTimeChangedListener = onTimeChangedListener;
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        init();
    }

    private void init() {

        try {
            ViewGroup amPmView;
            ViewGroup v1 = (ViewGroup) getChildAt(0);
            ViewGroup v2 = (ViewGroup) v1.getChildAt(0);
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                ViewGroup v3 = (ViewGroup) v2.getChildAt(0);
                amPmView = (ViewGroup) v3.getChildAt(3);
            } else {
                amPmView = (ViewGroup) v2.getChildAt(3);
            }
            View.OnTouchListener listener = new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                        onTimeChangedListener.onTimeChanged(MyTimePicker.this, getCurrentHour(), getCurrentMinute());
                    } else {
                        int hour = getCurrentHour();
                        if (hour >= 12) {
                            hour -= 12;
                        } else {
                            hour += 12;
                        }
                        onTimeChangedListener.onTimeChanged(MyTimePicker.this, hour, getCurrentMinute());
                    }

                    return false;
                }

            };
            View am = amPmView.getChildAt(0);
            View pm = amPmView.getChildAt(1);

            am.setOnTouchListener(listener);
            pm.setOnTouchListener(listener);
        } catch (Exception e) {
            // DO nothing... just ignore the workaround if this fails.
        }


    }
}
揽清风入怀 2025-01-05 06:59:24

请使用下面的代码,它对我来说工作正常。

final TimePicker tp=(TimePicker)findViewById(R.id.timePicker1);
    View amPmView  = ((ViewGroup)tp.getChildAt(0)).getChildAt(2);
    if(amPmView instanceof Button)
    {
        amPmView.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Log.d("OnClickListener", "OnClickListener called");
                if(v instanceof Button)
                {
                    if(((Button) v).getText().equals("AM"))
                    {
                        ((Button) v).setText("PM");
                         if (tp.getCurrentHour() < 12) {
                             tp.setCurrentHour(tp.getCurrentHour() + 12);
                            }  

                    }
                    else{
                        ((Button) v).setText("AM");
                         if (tp.getCurrentHour() >= 12) {
                             tp.setCurrentHour(tp.getCurrentHour() - 12);
                            }
                    }
                }

            }
        });
    }

Please use the below code it is working fine for me.

final TimePicker tp=(TimePicker)findViewById(R.id.timePicker1);
    View amPmView  = ((ViewGroup)tp.getChildAt(0)).getChildAt(2);
    if(amPmView instanceof Button)
    {
        amPmView.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Log.d("OnClickListener", "OnClickListener called");
                if(v instanceof Button)
                {
                    if(((Button) v).getText().equals("AM"))
                    {
                        ((Button) v).setText("PM");
                         if (tp.getCurrentHour() < 12) {
                             tp.setCurrentHour(tp.getCurrentHour() + 12);
                            }  

                    }
                    else{
                        ((Button) v).setText("AM");
                         if (tp.getCurrentHour() >= 12) {
                             tp.setCurrentHour(tp.getCurrentHour() - 12);
                            }
                    }
                }

            }
        });
    }
情丝乱 2025-01-05 06:59:24

链接显示 onTimeChanged(); 正在被调用,从而触发事件调度程序。

如果您没有获得所需的事件(即使它看起来正在发送),您必须

  • 扩展默认的 TimerPicker,

  • 覆盖 mAmPmButton.setOnClickListener,

    p>

  • 并将您的版本包含在视图中。


mAmPmButton.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            requestFocus();
            if (mIsAm) {

                // Currently AM switching to PM
                if (mCurrentHour < 12) {
                    mCurrentHour += 12;
                }                
            } else {

                // Currently PM switching to AM
                if (mCurrentHour >= 12) {
                    mCurrentHour -= 12;
                }
            }
            mIsAm = !mIsAm;
            mAmPmButton.setText(mIsAm ? mAmText : mPmText);
            onTimeChanged();
        }
    });

this link shows that onTimeChanged(); is getting called which triggers the event dispatcher.

If you're not getting the events you need (even though it appears to be sending) you have have to

  • extend the default TimerPicker,

  • override mAmPmButton.setOnClickListener,

  • and include your version in the view.


mAmPmButton.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            requestFocus();
            if (mIsAm) {

                // Currently AM switching to PM
                if (mCurrentHour < 12) {
                    mCurrentHour += 12;
                }                
            } else {

                // Currently PM switching to AM
                if (mCurrentHour >= 12) {
                    mCurrentHour -= 12;
                }
            }
            mIsAm = !mIsAm;
            mAmPmButton.setText(mIsAm ? mAmText : mPmText);
            onTimeChanged();
        }
    });
埖埖迣鎅 2025-01-05 06:59:24

对于 API 25 Nougat,Velval / Hisham 的代码是唯一可以工作但不能在横向模式下工作的代码。
我更改了代码,它工作正常:):

public class AMPMTimePicker extends TimePicker {

private static final String TAG = "AMPMTimePicker";
private OnTimeChangedListener onTimeChangedListener;

public AMPMTimePicker(Context context) {
    super(context);
}

public AMPMTimePicker(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public AMPMTimePicker(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public AMPMTimePicker(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    // Stop ScrollView from getting involved once you interact with the View
    if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
        ViewParent p = getParent();
        if (p != null)
            p.requestDisallowInterceptTouchEvent(true);
    }
    return false;
}

@Override
public void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener) {
    super.setOnTimeChangedListener(onTimeChangedListener);
    this.onTimeChangedListener = onTimeChangedListener;
}

@Override
protected void onFinishInflate() {
    super.onFinishInflate();
    init();
}

@SuppressWarnings("deprecation")
private void init() {
    try {
        ViewGroup amPmView;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

            // LinearLayout (LOLLIPOP)
            // GridLayout (M-LANDSCAPE)
            // LinearLayout (M-PORTRAIT)
            ViewGroup v1 = (ViewGroup) getChildAt(0);

            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {

                // FrameLayout (LOLLIPOP-LANDSCAPE)
                // FrameLayout - id:time_header (LOLLIPOP-PORTRAIT)
                ViewGroup v2 = (ViewGroup) v1.getChildAt(0);

                // FrameLayout - id:TimeHeader (LOLLIPOP-LANDSCAPE)
                // LinearLayout (LOLLIPOP-PORTRAIT)
                ViewGroup v3 = (ViewGroup) v2.getChildAt(0);

                if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
                    ViewGroup v4 = (ViewGroup) v3.getChildAt(0); // LinearLayout (LOLLIPOP)
                    amPmView = (ViewGroup) v4.getChildAt(3); // LinearLayout - id:ampm_layout (LOLLIPOP)
                } else { // PORTRAIT
                    amPmView = (ViewGroup) v3.getChildAt(3); // LinearLayout - id:ampm_layout (LOLLIPOP)
                }
            } else { // M and after
                if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
                    ViewGroup v2 = (ViewGroup) v1.getChildAt(1); // RelativeLayout (M)
                    amPmView = (ViewGroup) v2.getChildAt(1); // LinearLayout - id:ampm_layout (M)
                } else {
                    ViewGroup v2 = (ViewGroup) v1.getChildAt(0); // RelativeLayout - id:time_header (M)
                    amPmView = (ViewGroup) v2.getChildAt(3); // LinearLayout - id:ampm_layout (M)
                }
            }

            View am = amPmView.getChildAt(0); // AppCompatCheckedTextView - id:am_label
            View pm = amPmView.getChildAt(1); // AppCompatCheckedTextView - id:pm_label

            View.OnTouchListener listener = new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    int hour;
                    int minute;
                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                        hour = getCurrentHour();
                        minute = getCurrentMinute();
                    } else {
                        hour = getHour();
                        minute = getMinute();
                    }
                    hour = (hour >= 12) ? hour - 12 : hour + 12;
                    onTimeChangedListener.onTimeChanged(AMPMTimePicker.this, hour, minute);
                    return false;
                }
            };
            am.setOnTouchListener(listener);
            pm.setOnTouchListener(listener);
        }
    } catch (Exception e) {
        Log.e(TAG, "TimePicker is not defined for this Android version : " + e.getMessage());
    }
}
}

With API 25 Nougat, code of Velval / Hisham is the only one that works but not in landscape mode.
I changed the code and it works fine :) :

public class AMPMTimePicker extends TimePicker {

private static final String TAG = "AMPMTimePicker";
private OnTimeChangedListener onTimeChangedListener;

public AMPMTimePicker(Context context) {
    super(context);
}

public AMPMTimePicker(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public AMPMTimePicker(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public AMPMTimePicker(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    // Stop ScrollView from getting involved once you interact with the View
    if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
        ViewParent p = getParent();
        if (p != null)
            p.requestDisallowInterceptTouchEvent(true);
    }
    return false;
}

@Override
public void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener) {
    super.setOnTimeChangedListener(onTimeChangedListener);
    this.onTimeChangedListener = onTimeChangedListener;
}

@Override
protected void onFinishInflate() {
    super.onFinishInflate();
    init();
}

@SuppressWarnings("deprecation")
private void init() {
    try {
        ViewGroup amPmView;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

            // LinearLayout (LOLLIPOP)
            // GridLayout (M-LANDSCAPE)
            // LinearLayout (M-PORTRAIT)
            ViewGroup v1 = (ViewGroup) getChildAt(0);

            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {

                // FrameLayout (LOLLIPOP-LANDSCAPE)
                // FrameLayout - id:time_header (LOLLIPOP-PORTRAIT)
                ViewGroup v2 = (ViewGroup) v1.getChildAt(0);

                // FrameLayout - id:TimeHeader (LOLLIPOP-LANDSCAPE)
                // LinearLayout (LOLLIPOP-PORTRAIT)
                ViewGroup v3 = (ViewGroup) v2.getChildAt(0);

                if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
                    ViewGroup v4 = (ViewGroup) v3.getChildAt(0); // LinearLayout (LOLLIPOP)
                    amPmView = (ViewGroup) v4.getChildAt(3); // LinearLayout - id:ampm_layout (LOLLIPOP)
                } else { // PORTRAIT
                    amPmView = (ViewGroup) v3.getChildAt(3); // LinearLayout - id:ampm_layout (LOLLIPOP)
                }
            } else { // M and after
                if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
                    ViewGroup v2 = (ViewGroup) v1.getChildAt(1); // RelativeLayout (M)
                    amPmView = (ViewGroup) v2.getChildAt(1); // LinearLayout - id:ampm_layout (M)
                } else {
                    ViewGroup v2 = (ViewGroup) v1.getChildAt(0); // RelativeLayout - id:time_header (M)
                    amPmView = (ViewGroup) v2.getChildAt(3); // LinearLayout - id:ampm_layout (M)
                }
            }

            View am = amPmView.getChildAt(0); // AppCompatCheckedTextView - id:am_label
            View pm = amPmView.getChildAt(1); // AppCompatCheckedTextView - id:pm_label

            View.OnTouchListener listener = new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    int hour;
                    int minute;
                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                        hour = getCurrentHour();
                        minute = getCurrentMinute();
                    } else {
                        hour = getHour();
                        minute = getMinute();
                    }
                    hour = (hour >= 12) ? hour - 12 : hour + 12;
                    onTimeChangedListener.onTimeChanged(AMPMTimePicker.this, hour, minute);
                    return false;
                }
            };
            am.setOnTouchListener(listener);
            pm.setOnTouchListener(listener);
        }
    } catch (Exception e) {
        Log.e(TAG, "TimePicker is not defined for this Android version : " + e.getMessage());
    }
}
}
浅语花开 2025-01-05 06:59:24

这是我整理的一个支持 Android 4.0+ 的快速项目。基本上,它显示一个始终与 TimePicker 同步的 TextView,无论用户正在操纵哪个垂直旋转器。

https://gist.github.com/danialgoodwin/5694256

Here's a quick project that I threw together that supports Android 4.0+. Basically, it shows a TextView that is always in sync with the TimePicker, regardless of which vertical spinner is being manipulated by the user.

https://gist.github.com/danialgoodwin/5694256

单身情人 2025-01-05 06:59:24

我使此方法在 TimePicker 选择 AM 时返回 true,如果 TimePicker 选择 PM 则返回 false。注意:suppresLint 对于 Api 8 不起作用 .getvalue() 语句

Saludos! :)

@SuppressLint("NewApi")
private boolean isAM(TimePicker timePicker){
    NumberPicker numberPickerAmPm  = (NumberPicker)((ViewGroup) timePicker.getChildAt(0)).getChildAt(3);
    if(numberPickerAmPm.getValue()==0){
        //sendToast("es am");
        return true;
    }else{
       //sendToast("es pm");
        return false;
    }

}

i make this method thats return true if the TimePicker select AM and false if the TimePicker select PM. note: the suppresLint is for Api 8 don't work .getvalue() statement

Saludos!! :)

@SuppressLint("NewApi")
private boolean isAM(TimePicker timePicker){
    NumberPicker numberPickerAmPm  = (NumberPicker)((ViewGroup) timePicker.getChildAt(0)).getChildAt(3);
    if(numberPickerAmPm.getValue()==0){
        //sendToast("es am");
        return true;
    }else{
       //sendToast("es pm");
        return false;
    }

}
卖梦商人 2025-01-05 06:59:24

我也想分享我的解决方案,因为此处发布的其他解决方法对我不起作用。但我能弄清楚。此行:

    View amPmView  = ((ViewGroup)tp.getChildAt(0)).getChildAt(2);

似乎没有返回 AM_PM 的选择器轮。

    NumberPicker amPmView  = (NumberPicker ((ViewGroup)tp.getChildAt(0)).getChildAt(3);

这也不是,因为它返回一个 TextView。看起来这似乎是选择器上指定的标签。

但使用后者,获取第四个子元素会返回 AM_PM 的选择轮。这是我到目前为止所得到的:

    NumberPicker amPmView = (NumberPicker)((ViewGroup) mTimePicker.getChildAt(0)).getChildAt(4);
    amPmView.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() 
    {
        @Override
        public void onValueChange(NumberPicker picker, int oldVal, int newVal) 
        {
            Log.i(NoteApplication.TAG, "AM_PM selected...");
        }
    });

现在我能够检测 AM_PM 的变化。我希望这可以帮助其他一些无法通过 getChildAt(2)getChildAt(3) 检索它的人,如其他答案所述。

另请注意,TimePicker 类就是这种情况,我还没有在 TimePickerDialog 上尝试过这一点,所以我不确定是否适用。我正在针对 api 22 的 min sdk 8 进行测试

。HTH

I would like to share my solution as well since the other workarounds posted here doesn't work for me. But I am able to figure it out. This line:

    View amPmView  = ((ViewGroup)tp.getChildAt(0)).getChildAt(2);

Doesn't seem to return the picker wheel for AM_PM.

    NumberPicker amPmView  = (NumberPicker ((ViewGroup)tp.getChildAt(0)).getChildAt(3);

Neither this as well, since this one returns a TextView. It seems it seems it is the label designated on the picker.

But using the latter, getting the 4th child element returns me the picker wheel for AM_PM. Here is what I got so far:

    NumberPicker amPmView = (NumberPicker)((ViewGroup) mTimePicker.getChildAt(0)).getChildAt(4);
    amPmView.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() 
    {
        @Override
        public void onValueChange(NumberPicker picker, int oldVal, int newVal) 
        {
            Log.i(NoteApplication.TAG, "AM_PM selected...");
        }
    });

Now I am able to detect changes in AM_PM. I hope this help some other people who can't retrieve it via getChildAt(2) or getChildAt(3) as described by other answers.

Also take note that this is the case for the class TimePicker, I haven't tried this yet on a TimePickerDialog so I am not sure for that one. I am testing at min sdk 8 targeting api 22.

HTH

欢烬 2025-01-05 06:59:24

我在使用API​​ 21时也遇到了同样的问题,而且问题还没有解决。

我将 TimePicker 视图替换为 TimePickerDialog 并且它起作用了。

以下代码使用从 TimePickerDialog 中选取的时间设置 TextView。您可以用任何逻辑替换 tv.setText() :

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    final TextView tv = (TextView)findViewById(R.id.textView);

    Calendar calendar = Calendar.getInstance();
    int hour = calendar.get(Calendar.HOUR_OF_DAY);
    int minute = calendar.get(Calendar.MINUTE);
    TimePickerDialog timePickerDialog = new TimePickerDialog(this,
            new TimePickerDialog.OnTimeSetListener() {
                @Override
                public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
                    tv.setText(String.format(Locale.getDefault(),"Hour: %d, Minute: %d ",hourOfDay,minute));
                }
    }, hour, minute, true);
    timePickerDialog.show();
}

I've also faced the same problem using API 21, and the problem hasn't been solved yet.

I replaced the TimePicker view for a TimePickerDialog and it worked.

The following code sets a TextView with the time picked from the TimePickerDialog. You can replace the tv.setText() with any logic :

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    final TextView tv = (TextView)findViewById(R.id.textView);

    Calendar calendar = Calendar.getInstance();
    int hour = calendar.get(Calendar.HOUR_OF_DAY);
    int minute = calendar.get(Calendar.MINUTE);
    TimePickerDialog timePickerDialog = new TimePickerDialog(this,
            new TimePickerDialog.OnTimeSetListener() {
                @Override
                public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
                    tv.setText(String.format(Locale.getDefault(),"Hour: %d, Minute: %d ",hourOfDay,minute));
                }
    }, hour, minute, true);
    timePickerDialog.show();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文