2016-10-05 20 views
8

Từ nhu cầu khách hàng của chúng tôi, chúng tôi muốn giữ lại phong cách Holo trên DatePickerDialog cho tất cả các phiên bản hệ điều hành Android, sth như: DatePicker on Android 7-DatePickerDialog Holo phong cách thất bại trên Android 7 Nougat

Nhưng nó dường như không làm việc một cách chính xác trên Android 7:

DatePicker on Android 7

Từ thực hiện của tôi:

new DatePickerDialog(getContext(), AlertDialog.THEME_HOLO_LIGHT, 
         mCalendarPickerListener, 
         calendar.get(Calendar.YEAR), 
         calendar.get(Calendar.MONTH), 
         calendar.get(Calendar.DAY_OF_MONTH)); 

Tính năng này hoạt động tốt cho Android trước 7. Mọi người có cùng sự cố?

được sửa đổi: giải pháp được tìm thấy sẽ được cố định trong API 25 https://code.google.com/u/106133255289400340786/

+0

Bạn đã cập nhật thư viện hỗ trợ của mình chưa? – Shuddh

+0

@Shuddh đã thử nhưng vẫn giống nhau :) Tôi đã thử '24 .2.1 'https://developer.android.com/topic/libraries/support-library/revisions.html –

+0

Tôi cũng đang gặp sự cố này. Bất cứ ai có một giải pháp? – FinalFive

Trả lời

16

Tôi sử dụng DatePickerDialog để nhắc người dùng cho sinh nhật của họ. Thật không may, tôi đã nhận được một số khiếu nại từ người dùng về hộp thoại Theo chủ đề vật chất khi dùng thử, vì vậy việc chuyển sang hộp thoại không phải là một tùy chọn cho tôi: Tôi phải tuân theo hộp thoại theo chủ đề Holo.

Nó chỉ ra rằng Android 7.0 vận chuyển với một lỗi: cố gắng sử dụng chủ đề Holo trên nền tảng này thay vì quay trở lại bằng cách sử dụng bị hỏng Chủ đề tài liệu cho DatePickerDialog.Xem các báo cáo này hai lỗi:

tôi đã sử dụng một hình thức sửa đổi của this workaround by Jeff Lockhart tham chiếu trong những báo cáo lỗi:

private static final class FixedHoloDatePickerDialog extends DatePickerDialog { 
    private FixedHoloDatePickerDialog(Context context, OnDateSetListener callBack, 
             int year, int monthOfYear, int dayOfMonth) { 
     super(context, callBack, year, monthOfYear, dayOfMonth); 

     // Force spinners on Android 7.0 only (SDK 24). 
     // Note: I'm using a naked SDK value of 24 here, because I'm 
     // targeting SDK 23, and Build.VERSION_CODES.N is not available yet. 
     // But if you target SDK >= 24, you should have it. 
     if (Build.VERSION.SDK_INT == 24) { 
      try { 
       final Field field = this.findField(
         DatePickerDialog.class, 
         DatePicker.class, 
         "mDatePicker" 
       ); 

       final DatePicker datePicker = (DatePicker) field.get(this); 
       final Class<?> delegateClass = Class.forName(
         "android.widget.DatePicker$DatePickerDelegate" 
       ); 
       final Field delegateField = this.findField(
         DatePicker.class, 
         delegateClass, 
         "mDelegate" 
       ); 

       final Object delegate = delegateField.get(datePicker); 
       final Class<?> spinnerDelegateClass = Class.forName(
         "android.widget.DatePickerSpinnerDelegate" 
       ); 

       if (delegate.getClass() != spinnerDelegateClass) { 
        delegateField.set(datePicker, null); 
        datePicker.removeAllViews(); 

        final Constructor spinnerDelegateConstructor = 
          spinnerDelegateClass.getDeclaredConstructor(
            DatePicker.class, 
            Context.class, 
            AttributeSet.class, 
            int.class, 
            int.class 
          ); 
        spinnerDelegateConstructor.setAccessible(true); 

        final Object spinnerDelegate = spinnerDelegateConstructor.newInstance(
          datePicker, 
          context, 
          null, 
          android.R.attr.datePickerStyle, 
          0 
        ); 
        delegateField.set(datePicker, spinnerDelegate); 

        datePicker.init(year, monthOfYear, dayOfMonth, this); 
        datePicker.setCalendarViewShown(false); 
        datePicker.setSpinnersShown(true); 
       } 
      } catch (Exception e) { /* Do nothing */ } 
     } 
    } 

    /** 
    * Find Field with expectedName in objectClass. If not found, find first occurrence of 
    * target fieldClass in objectClass. 
    */ 
    private Field findField(Class objectClass, Class fieldClass, String expectedName) { 
     try { 
      final Field field = objectClass.getDeclaredField(expectedName); 
      field.setAccessible(true); 
      return field; 
     } catch (NoSuchFieldException e) { /* Ignore */ } 

     // Search for it if it wasn't found under the expectedName. 
     for (final Field field : objectClass.getDeclaredFields()) { 
      if (field.getType() == fieldClass) { 
       field.setAccessible(true); 
       return field; 
      } 
     } 

     return null; 
    } 
} 

Điều này không là:

  • Lấy tin DatePicker mDatePicker lĩnh vực thuộc thoại
  • này Lấy tin DatePickerDelegate mDelegate lĩnh vực thuộc này thoại
  • Kiểm tra xem các đại biểu chưa được một thể hiện của DatePickerSpinnerDelegate (loại đại biểu chúng ta muốn)
  • Hủy bỏ tất cả quan điểm từ các DatePicker, vì họ là những widget lịch Chất liệu
  • Tạo một thể hiện mới của DatePickerSpinnerDelegate, và gán nó vào mDelegate lĩnh vực mDatePicker này thoại
  • Re-init ialize mDatePicker với thông tin lịch và một số params để làm cho nó thổi phồng spinners

Để sử dụng workaround này, tôi tạo ra một ContextThemeWrapper xung quanh tôi Context, cho phép tôi để thiết lập một chủ đề, trong trường hợp này Holo:

final Context themedContext = new ContextThemeWrapper(
     this.getContext(), 
     android.R.style.Theme_Holo_Light_Dialog 
); 

final DatePickerDialog dialog = new FixedHoloDatePickerDialog(
     themedContext, 
     datePickerListener, 
     calender.get(Calendar.YEAR), 
     calendar.get(Calendar.MONTH), 
     calendar.get(Calendar.DAY_OF_MONTH) 
); 

Ghi chú:

  • Điều này sử dụng phản ánh để truy cập các trường riêng tư. Nói chung, đây không phải là một cách tiếp cận mạnh mẽ và bạn không thể tin tưởng vào nó. Tôi đang giảm thiểu rủi ro ở đây bằng 1) hạn chế việc này thành một phiên bản SDK, v24; và 2) gói toàn bộ bit của mã phản chiếu trong một khối try {...} catch (Exception e) {/* NOP */}, vì vậy nếu bất kỳ sự phản ánh nào không thành công, thì sẽ không có gì xảy ra và dự phòng Vật liệu mặc định bị hỏng (sẽ bị hỏng) sẽ được sử dụng.
  • Báo cáo lỗi ở trên cho biết rằng sự cố này đã được khắc phục trong Android 7.1 (SDK 25). Tôi chưa thử nghiệm điều này.
  • original workaround code là dành cho TimePickerDialog gặp phải sự cố tương tự. Tôi đã sửa đổi nó để làm việc với DatePickerDialog thay vào đó, và cũng đơn giản hóa các giải pháp được ít chung chung, và cụ thể hơn cho trường hợp sử dụng chính xác của tôi. Tuy nhiên, bạn có thể sử dụng phiên bản gốc hoàn chỉnh hơn và chỉ tinh chỉnh nó cho Date thay vì Time.
+0

mặc dù đó là một vấn đề xung quanh vấn đề nhưng dù sao, điều này nghe có vẻ khả thi –

+0

âm thanh như FIX chính xác nên sử dụng API 25 https://code.google.com/u/106133255289400340786/ –

+0

đặt trình nghe ngày không hoạt động, luôn quay trở lại ngày init – WolfJee

0

chọn ngày có nó riêng theo phong cách riêng biệt https://developer.android.com/reference/android/R.style.html#Widget_DatePicker

tôi nghĩ rằng bạn cần R.style.Widget.Holo.DatePicker thay vì AlertDialog.THEME_HOLO_LIGHT. Có thể bạn cần tạo kiểu trống rỗng của riêng mình có @android:style/Widget.Holo.DatePicker làm kiểu gốc và sử dụng.

+0

nó không hoạt động chính xác, thay vào đó nó hiển thị lịch toàn màn hình với khoảng trống trống. –

Các vấn đề liên quan