2015-08-31 32 views
5

CẬP NHẬTappcompat-v7 v23.0.0 statusbar màu đen khi ở ActionMode

Cùng một vấn đề hiện tại trong ứng dụng Gmail mới nhất. Tôi vẫn không hiểu tại sao Google lại làm thay đổi giao diện người dùng khó chịu như vậy. Ám ảnh trong tôi đi điên bất cứ khi nào tôi nhìn thấy nó

HỎI

Tôi có vấn đề kỳ lạ này với appcompat-v7 23. Issue Tôi sẽ mô tả không xảy ra với 22 loạt

Bạn có thể nhận mã nguồn tái tạo hình thức issuse này https://github.com/devserv/t/ Khi xây dựng, bạn có thể chạm và giữ một mục trong danh sách để kích hoạt ActionMode

Sự cố:

Khi đang hoạt độngMode, appcompat chuyển thanh trạng thái sang màu đen. Điều này không xảy ra nếu tôi không sử dụng theo dõi

<item name="android:statusBarColor">@android:color/transparent</item> 
<item name="android:windowDrawsSystemBarBackgrounds">true</item> 

theo kiểu v21 nhưng tôi phải sử dụng vì tôi muốn ngăn điều hướng của tôi nhìn phía sau thanh trạng thái.


tôi sử dụng để sử dụng sau đây để tránh thanh trạng thái màu đen khi ActionMode bắt đầu và kết thúc

public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { 
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
     getActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.appColorPrimaryDark)); 
    } 

}

public void onDestroyActionMode(ActionMode actionMode) { 
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
     getActivity().getWindow().setStatusBarColor(getResources().getColor(android.R.color.transparent)); 
    } 

    mMode = null; 
} 

Trên mã đã không tạo/tránh thanh trạng thái chuyển màu đen, nhưng không hoạt động đúng trên v23 của appcompat. Thay vào đó bạn thấy một thanh trạng thái màu đen ngắn trong khi ActionMode bị phá hủy. Dường như liên quan đến hoạt ảnh phát khi ActionMode bị hủy.

Tôi đã cố gắng để mở báo cáo lỗi nhưng nó đã bị từ chối với bình luận

Don't re-create bugs. 

Tôi có thiếu cái gì?

Sau đây là các ảnh chụp màn hình cho chế độ bình thường và hành động

Bình thường enter image description here

trong ActionMode enter image description here

+0

Bạn đã thử bản phát hành 23.0.1 chưa? Nó đã được triển khai ngày hôm nay. Mức api của thiết bị của bạn là bao nhiêu? –

+0

Có, vẫn như cũ. Họ thậm chí không chấp nhận báo cáo lỗi – nLL

Trả lời

5

Trong trường hợp chỉ có màu là vấn đề, bạn có thể thay đổi nó. Chỉ với một tài nguyên màu cố định.

<color name="abc_input_method_navigation_guard" tools:override="true">@color/primary_dark</color> 

Rõ ràng ?colorPrimaryDark sẽ không hoạt động, thậm chí không có sẵn trên API 21.


Quan điểm trách nhiệm đối với nền thanh trạng thái màu đen được lưu trữ trong AppCompatDelegateImplV7.mStatusGuard. Bạn có thể lấy đại biểu bằng cách gọi số getDelegate() từ hoạt động của mình và truy cập trường mStatusGuard bằng cách phản ánh. Sau khi bắt đầu chế độ hành động, bạn có thể tham khảo chế độ xem này và tùy chỉnh nó theo cách bạn muốn.

Điều này được tìm thấy trong AppCompat 24.1.1.

1

ai? Đây là cách giải quyết mà tôi đã đưa ra. Sự chậm trễ.

@Override 
    public void onDestroyActionMode(ActionMode mode) { 

     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
      new Handler().postDelayed(new Runnable() { 
       @Override 
       public void run() { 
        try { 
         getActivity().getWindow().setStatusBarColor(getResources().getColor(android.R.color.transparent)); 
        } 
        catch(Exception e) 
        { 
         e.printStackTrace(); 
        } 
       } 
      }, 400); 

     } 
     mActionMode = null; 

    } 
6

Phiên bản 23.0.0 của v7 appcompat library giới thiệu một hình ảnh động mà mất dần trong và ngoài các chế độ hoạt động khi nó được bắt đầu và kết thúc như bạn có thể đọc here:

Phương thức hành động có fades trong và Làm việc như dự định.

Những thay đổi được thực hiện trong phương pháp onDestroyActionMode trong AppCompatDelegateImplV7:

public void onDestroyActionMode(ActionMode mode) { 
    mWrapped.onDestroyActionMode(mode); 
    if (mActionModePopup != null) { 
     mWindow.getDecorView().removeCallbacks(mShowActionModePopup); 
     mActionModePopup.dismiss(); 
    } else if (mActionModeView != null) { 
     mActionModeView.setVisibility(View.GONE); 
     if (mActionModeView.getParent() != null) { 
      ViewCompat.requestApplyInsets((View) mActionModeView.getParent()); 
     } 
    } 
    if (mActionModeView != null) { 
     mActionModeView.removeAllViews(); 
    } 
    if (mAppCompatCallback != null) { 
     mAppCompatCallback.onSupportActionModeFinished(mActionMode); 
    } 
    mActionMode = null; 
} 

Trong phiên bản 23.0.0 nó đã được đổi thành:

public void onDestroyActionMode(ActionMode mode) { 
    mWrapped.onDestroyActionMode(mode); 
    if (mActionModePopup != null) { 
     mWindow.getDecorView().removeCallbacks(mShowActionModePopup); 
    } 

    if (mActionModeView != null) { 
     endOnGoingFadeAnimation(); 
     mFadeAnim = ViewCompat.animate(mActionModeView).alpha(0f); 
     mFadeAnim.setListener(new ViewPropertyAnimatorListenerAdapter() { 
      @Override 
      public void onAnimationEnd(View view) { 
       mActionModeView.setVisibility(View.GONE); 
       if (mActionModePopup != null) { 
        mActionModePopup.dismiss(); 
       } else if (mActionModeView.getParent() instanceof View) { 
        ViewCompat.requestApplyInsets((View) mActionModeView.getParent()); 
       } 
       mActionModeView.removeAllViews(); 
       mFadeAnim.setListener(null); 
       mFadeAnim = null; 
      } 
     }); 
    } 
    if (mAppCompatCallback != null) { 
     mAppCompatCallback.onSupportActionModeFinished(mActionMode); 
    } 
    mActionMode = null; 
} 

Như bạn thấy mWrapped.onDestroyActionMode(mode); được gọi ngay lập tức, không phải khi hoạt ảnh kết thúc. Đây là nguyên nhân gây ra thanh trạng thái màu đen trong ứng dụng của bạn và trong các ứng dụng khác như Gmail và Keep.

Giải pháp thay thế mà bạn thấy có hiệu quả, nhưng tiếc là không đáng tin cậy, bởi vì nếu hoạt ảnh mất nhiều thời gian hơn, bạn vẫn có thể thấy thanh trạng thái màu đen.

Tôi nghĩ rằng Google nên khắc phục sự cố và gọi onDestroyActionMode chỉ khi hoạt ảnh thực sự kết thúc. Trong thời gian đó, bạn có thể thay đổi hành vi này bằng một chút phản xạ. Nó là cần thiết để ghi đè onSupportActionModeStarted trong hoạt động của bạn và gọi phương thức fixActionModeCallback:

@Override 
public void onSupportActionModeStarted(ActionMode mode) { 
    super.onSupportActionModeStarted(mode); 

    //Call this method 
    fixActionModeCallback(this, mode); 
} 

private void fixActionModeCallback(AppCompatActivity activity, ActionMode mode) { 
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) 
     return; 

    if (!(mode instanceof StandaloneActionMode)) 
     return; 

    try { 
     final Field mCallbackField = mode.getClass().getDeclaredField("mCallback"); 
     mCallbackField.setAccessible(true); 
     final Object mCallback = mCallbackField.get(mode); 

     final Field mWrappedField = mCallback.getClass().getDeclaredField("mWrapped"); 
     mWrappedField.setAccessible(true); 
     final ActionMode.Callback mWrapped = (ActionMode.Callback) mWrappedField.get(mCallback); 

     final Field mDelegateField = AppCompatActivity.class.getDeclaredField("mDelegate"); 
     mDelegateField.setAccessible(true); 
     final Object mDelegate = mDelegateField.get(activity); 

     mCallbackField.set(mode, new ActionMode.Callback() { 

      @Override 
      public boolean onCreateActionMode(android.support.v7.view.ActionMode mode, Menu menu) { 
       return mWrapped.onCreateActionMode(mode, menu); 
      } 

      @Override 
      public boolean onPrepareActionMode(android.support.v7.view.ActionMode mode, Menu menu) { 
       return mWrapped.onPrepareActionMode(mode, menu); 
      } 

      @Override 
      public boolean onActionItemClicked(android.support.v7.view.ActionMode mode, MenuItem item) { 
       return mWrapped.onActionItemClicked(mode, item); 
      } 

      @Override 
      public void onDestroyActionMode(final android.support.v7.view.ActionMode mode) { 
       Class mDelegateClass = mDelegate.getClass().getSuperclass(); 
       Window mWindow = null; 
       PopupWindow mActionModePopup = null; 
       Runnable mShowActionModePopup = null; 
       ActionBarContextView mActionModeView = null; 
       AppCompatCallback mAppCompatCallback = null; 
       ViewPropertyAnimatorCompat mFadeAnim = null; 
       android.support.v7.view.ActionMode mActionMode = null; 

       Field mFadeAnimField = null; 
       Field mActionModeField = null; 

       while (mDelegateClass != null) { 
        try { 
         if (TextUtils.equals("AppCompatDelegateImplV7", mDelegateClass.getSimpleName())) { 
          Field mActionModePopupField = mDelegateClass.getDeclaredField("mActionModePopup"); 
          mActionModePopupField.setAccessible(true); 
          mActionModePopup = (PopupWindow) mActionModePopupField.get(mDelegate); 

          Field mShowActionModePopupField = mDelegateClass.getDeclaredField("mShowActionModePopup"); 
          mShowActionModePopupField.setAccessible(true); 
          mShowActionModePopup = (Runnable) mShowActionModePopupField.get(mDelegate); 

          Field mActionModeViewField = mDelegateClass.getDeclaredField("mActionModeView"); 
          mActionModeViewField.setAccessible(true); 
          mActionModeView = (ActionBarContextView) mActionModeViewField.get(mDelegate); 

          mFadeAnimField = mDelegateClass.getDeclaredField("mFadeAnim"); 
          mFadeAnimField.setAccessible(true); 
          mFadeAnim = (ViewPropertyAnimatorCompat) mFadeAnimField.get(mDelegate); 

          mActionModeField = mDelegateClass.getDeclaredField("mActionMode"); 
          mActionModeField.setAccessible(true); 
          mActionMode = (android.support.v7.view.ActionMode) mActionModeField.get(mDelegate); 

         } else if (TextUtils.equals("AppCompatDelegateImplBase", mDelegateClass.getSimpleName())) { 
          Field mAppCompatCallbackField = mDelegateClass.getDeclaredField("mAppCompatCallback"); 
          mAppCompatCallbackField.setAccessible(true); 
          mAppCompatCallback = (AppCompatCallback) mAppCompatCallbackField.get(mDelegate); 

          Field mWindowField = mDelegateClass.getDeclaredField("mWindow"); 
          mWindowField.setAccessible(true); 
          mWindow = (Window) mWindowField.get(mDelegate); 
         } 

         mDelegateClass = mDelegateClass.getSuperclass(); 
        } catch (NoSuchFieldException e) { 
         e.printStackTrace(); 
        } catch (IllegalAccessException e) { 
         e.printStackTrace(); 
        } 
       } 

       if (mActionModePopup != null) { 
        mWindow.getDecorView().removeCallbacks(mShowActionModePopup); 
       } 

       if (mActionModeView != null) { 
        if (mFadeAnim != null) { 
         mFadeAnim.cancel(); 
        } 

        mFadeAnim = ViewCompat.animate(mActionModeView).alpha(0.0F); 

        final PopupWindow mActionModePopupFinal = mActionModePopup; 
        final ActionBarContextView mActionModeViewFinal = mActionModeView; 
        final ViewPropertyAnimatorCompat mFadeAnimFinal = mFadeAnim; 
        final AppCompatCallback mAppCompatCallbackFinal = mAppCompatCallback; 
        final android.support.v7.view.ActionMode mActionModeFinal = mActionMode; 
        final Field mFadeAnimFieldFinal = mFadeAnimField; 
        final Field mActionModeFieldFinal = mActionModeField; 

        mFadeAnim.setListener(new ViewPropertyAnimatorListenerAdapter() { 
         public void onAnimationEnd(View view) { 
          mActionModeViewFinal.setVisibility(View.GONE); 
          if (mActionModePopupFinal != null) { 
           mActionModePopupFinal.dismiss(); 
          } else if (mActionModeViewFinal.getParent() instanceof View) { 
           ViewCompat.requestApplyInsets((View) mActionModeViewFinal.getParent()); 
          } 

          mActionModeViewFinal.removeAllViews(); 
          mFadeAnimFinal.setListener((ViewPropertyAnimatorListener) null); 

          try { 
           if (mFadeAnimFieldFinal != null) { 
            mFadeAnimFieldFinal.set(mDelegate, null); 
           } 
          } catch (IllegalAccessException e) { 
           e.printStackTrace(); 
          } 

          mWrapped.onDestroyActionMode(mode); 

          if (mAppCompatCallbackFinal != null) { 
           mAppCompatCallbackFinal.onSupportActionModeFinished(mActionModeFinal); 
          } 

          try { 
           if (mActionModeFieldFinal != null) { 
            mActionModeFieldFinal.set(mDelegate, null); 
           } 
          } catch (IllegalAccessException e) { 
           e.printStackTrace(); 
          } 
         } 
        }); 
       } 
      } 
     }); 

    } catch (NoSuchFieldException e) { 
     e.printStackTrace(); 
    } catch (IllegalAccessException e) { 
     e.printStackTrace(); 
    } 
} 
+0

Tôi đã chắc chắn hoạt hình gây ra nó, (xem trả lời của tôi dưới đây) trả lời của bạn xác nhận điều này. Những gì tôi không hiểu là những gì họ nhấn mạnh rằng nó đang làm việc như dự định. Rõ ràng là không. – nLL

+0

Tôi nghĩ rằng họ không hiểu rõ vấn đề. Vấn đề không phải là bản thân hình ảnh động (rõ ràng là hoạt động như dự định) nhưng thực tế là 'onDestroyActionMode' được gọi quá sớm. –

+0

Hy vọng rằng @ chris-bane nhận thức được nó – nLL

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