appcompat-V7 v23.0.0状态栏的颜色黑色ActionMode时 [英] appcompat-v7 v23.0.0 statusbar color black when in ActionMode

查看:478
本文介绍了appcompat-V7 v23.0.0状态栏的颜色黑色ActionMode时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新

同样的问题present在最新的Gmail应用程序。我还是不明白,为什么谷歌会做出这样不愉快的UI变化。强迫症的我都疯了,每当我看到它

Same issue present in the latest Gmail app. I still don't understand why would Google make such unpleasant UI change. Obsessive in me goes crazy whenever I see it

我有这个奇怪的问题,appcompat-V7 23.问题我要说明不会发生与22系列

I have this weird issue with appcompat-v7 23. Issue I am going to describe does not happen with 22 series

您可以得到源$ C ​​$ C重现这种issuse形式 https://github.com/devserv/t/ 一旦建成,您可以点击并按住列表中的项目,以激活ActionMode

You can get source code that reproduces this issuse form https://github.com/devserv/t/ Once built, you can tap and hold an item in the list to activate ActionMode

问题:

当在ActionMode,appcompat原来的状态栏为黑色。这不会发生,如果我不使用以下

When in ActionMode, appcompat turns status bar to black. This does not happen if I don’t use following

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

在我的V21的风格,但我不得不使用它,因为我希望我的抽屉式导航看后面状态栏。

in my v21 style but I have to use it because I want my navigation drawer to look behind status bar.

我用以下,以避免黑色状态栏时ActionMode开始和结束

I used to use following to avoid black status bar when ActionMode started and ended

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

以上code没有创建/回避状态栏变黑,但不正确的appcompat的V23工作。相反,你看到一个黑色的短状态栏,同时ActionMode破坏。它看起来像相关播放时ActionMode摧毁了动画。

Above code did not create/avoided status bar turning black, but does not work properly on v23 of appcompat. Instead you see a short black status bar while ActionMode destroyed. It looks like related to the animation that plays when ActionMode destroyed.

我试图打开错误报告,但一直拒绝与注释

I have tried to open bug reports but it has been declined with comment

Don't re-create bugs.

我缺少的东西?

Am I missing something?

下面是屏幕截图的正常和行动模式

Here are the screen shots for normal and action mode

普通

在ActionMode

in ActionMode

推荐答案

版本23.0.0 V7​​ appcompat库介绍,淡入淡出的动作模式的动画当它开始和结束,你可以在这里一>:

The version 23.0.0 of v7 appcompat library introduced an animation that fades in and out the action mode when it's started and finished as you can read here:

的操作模式在消退,并正在按预期。

The action mode has fades in and is working as intended.

进行的变化被在方法 onDestroyActionMode AppCompatDelegateImplV7

The changes are made in the method onDestroyActionMode in 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;
}

在23.0.0版本又改为:

In version 23.0.0 it was changed to:

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

正如你可以看到 mWrapped.onDestroyActionMode(模式); 立即调用,动画结束时没有。这是导致黑状态栏在您的应用程序和其他应用程序,如Gmail和保持。

As you can see mWrapped.onDestroyActionMode(mode); is called immediately, not when the animation ends. This is what cause the black status bar in your app and in other apps like Gmail and Keep.

这是你找到工作,但不幸的是不可靠的,因为如果动画需要更长的时间,你可以看到黑色的状态栏反正变通方法。

The workaround that you found works, but unfortunately is not reliable, because if the animation takes longer you could see the black status bar anyway.

我认为谷歌应该纠正这个问题,并呼吁 onDestroyActionMode 动画真的是结束,只有当。在此同时,您可以更改带着几分反思这种行为。有必要覆盖您的活动 onSupportActionModeStarted 并调用该方法 fixActionModeCallback

I think Google should correct the issue and call onDestroyActionMode only when the animation is really ended. In the mean time you can change this behaviour with a bit of reflections. It is necessary to override onSupportActionModeStarted in your activity and call the method 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();
    }
}

这篇关于appcompat-V7 v23.0.0状态栏的颜色黑色ActionMode时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆