2012-01-28 68 views
10

我有一些問題在我的應用程序中實現TimePicker,允許用戶在插入數據庫記錄之前更改其時間。Android TimePicker上午/下午按鈕不調用onTimeChanged

問題是,當按下AM/PM按鈕時,不會調用onTimeChanged(View,int,int)方法。但是,無論何時更改TimePicker的小時或分鐘值,都會調用onTimeChanged()。

方案:

  • 用戶只要點擊該AM/PM按鈕:AM/PM是更新
  • 用戶點擊時/分:時間更新
  • 用戶點擊AM/PM按鈕,然後更改小時/分鐘:時間和上午/下午更新

我錯了,認爲上午/下午按鈕應該能夠點擊更新時間,而不必在am/pm按鈕之後更改時間值?

我已經把一個小的測試項目,以複製這一這裏是代碼:

活動

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> 

回答

29

我已經測試的代碼。是的,你是對的,TimePicker AM/PM按鈕不會調用它應該的TimeChanged方法。

其實它是一個bug。據報道,谷歌。你可以在這裏找到它
http://code.google.com/p/android/issues/detail?id=18982

請投票,發表評論& bug報告,以提高其優先級,並得到它的開發團隊儘快修復。

+0

感謝這個信息,山姆! – hooked82 2012-02-06 15:56:57

+4

自2011年以來報告錯誤...不錯 – 2015-05-13 13:04:29

+0

感謝您的信息vivik – Jinu 2016-04-04 08:09:52

3

this鏈接顯示onTimeChanged();正在調用哪個觸發器e事件調度員。

如果你沒有得到你需要的(即使它似乎被髮送),你必須要

  • 擴展默認TimerPicker的事件,

  • 覆蓋mAmPmButton.setOnClickListener,

  • 並在視圖中包含您的版本。


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(); 
     } 
    }); 
+0

是的,我已經看到,在源。我甚至將源代碼拉下來,並將TimePicker/NumberPicker重新編譯爲本地類,並按預期工作。這個問題是,我不想爲這些拉來源,並有我自己定製的。我想知道爲什麼默認的在我的應用程序中沒有按預期工作? – hooked82 2012-01-30 19:32:10

+1

我不認爲如果你不做這些選擇,你就不會去實現它。 Timer包含在sdk中顯然有一個問題。 – user123321 2012-01-30 19:38:39

3

請使用下面的代碼,它工作正常。

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); 
          } 
        } 
       } 

      } 
     }); 
    } 
+0

謝謝,這個工程很好。我評論了v.setText(「AM/PM」)行,它仍然得到適當的更新。我不確定這是否是b/c tp.setCurrentHour()最終會觸發timeChanged事件。 – samosaris 2013-02-04 15:44:23

+0

我有這種方法的問題,檢查instanceof失敗。 – 2015-05-15 04:51:23

6

我發現了這個答案,但它不適合我,所以我想我會更新。

在3.2(及以上?)中,時間選取器沒有am/pm的按鈕。相反,它有一個NumberPicker。以下代碼適用於我。最後一位是因爲我需要限制選擇的時間不早於'min'日期並且不大於'max'日期,所以我必須檢查在匹配的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)); 
        } 
       } 
      } 
     }); 
0

我做,如果TimePicker選擇AM和虛假如果TimePicker選擇PM這種方法多數民衆贊成在返回true。注意: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; 
    } 

} 
0

我想分享我的解決方案,因爲這裏發佈的其他解決方法不適用於我。但我能夠弄明白。此行:

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,所以我不確定這一點。我在SDK分鐘測試8針對API在代碼中創建的TimePicker並沒有提供解決方案的工作對我來說,當22

HTH

3

有同樣的問題。以下是我最終做的。測試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. 
} 
+0

這段代碼設法將監聽器放在AM/PM上,但現在AM/PM不能正常工作,因爲您已經由監聽器替換了默認監聽器。請告知 – 2016-04-09 18:38:54

+0

我用OnTouch替換了onClickListener,以便不覆蓋原始的點擊監聽器 – 2016-04-09 20:23:03

+1

Hi @Hisham,此解決方法的整體思路是修復默認偵聽器,因爲它具有Vivek指出的錯誤。默認監聽器不會調用onTimeChanged回調函數,因此您需要將其替換爲您的自定義監聽器,並調用tp.setCurrentHour((tp.getCurrentHour()+ 12)%24);以確保在正確的時間觸發回調。 – velval 2016-04-10 07:12:15

4

Velval解決方案是與不同的Android vesrions兼容的唯一解決方案。我在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. 
     } 


    } 
} 
+0

這是一個很好的解決方法,而谷歌解決了這個問題;這可能不會很快。 – duke 2017-08-19 16:08:30

0

我也面臨使用API​​ 21的同樣的問題,這個問題尚未得到解決。

我替換TimePickerDialog的TimePicker視圖,它工作。

以下代碼使用從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(); 
} 
1

隨着API 25牛軋糖,Velval /希沙姆的代碼是唯一一個工作,但不是在橫向模式。 我改變了代碼,它工作正常:):

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()); 
    } 
} 
} 
相關問題