При использовании ActionMode, в строке состояния окрашивается в черный цвет на Lollipop
У меня есть строка состояния со следующим в теме, установленной на нем:
<!-- Base Theme for all "Material"-esque styles. We use NoActionBar
so we can use the Toolbar at runtime.
-->
<style name="Material" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowTranslucentStatus">true</item>
...
</style>
У меня также есть DrawerLayout для большинства моих действий, который устанавливает цвет строки состояния по моему вкусу, используя:
mDrawerLayout.setStatusBarBackgroundColor(getResources().getColor(R.color.myapp_green));
Я использую Toolbar, а не стандартный ActionBar, поэтому он существует в моем макете (т. е. навигационный ящик рисует поверх него).
Все работает нормально, за исключением того, что в одном из моих занятий у меня есть режим множественного выбора с ActionMode. При этом ActionMode активирован (с помощью длительное нажатие), он накладывает Toolbar, используя:
<item name="android:windowActionModeOverlay">true</item>
<item name="windowActionModeOverlay">true</item>
<item name="actionModeStyle">@style/Material.Widget.ActionMode</item>
Стиль Material.Widget.ActionMode таков:
<style name="Material.Widget.ActionMode" parent="@style/Widget.AppCompat.ActionMode">
<item name="android:background">@color/myapp_green</item>
<item name="background">@color/myapp_green</item>
</style>
Теперь проблема в том, что всякий раз, когда это происходит, строка состояния превращается из цвета
myapp_green в черный. Это почти как если бы прозрачность строки состояния была отключена (я использую Android 5.0). Я задаюсь вопросом, как я мог бы заставить это поведение не происходить, и сохранить цвет строки состояния/прозрачность как есть.Я попытался добавить <item name="android:windowTranslucentStatus">true</item> в стили режима действия, а также добавить <item name="android:statusBarColor">@color/myapp_green</item> в стиле для ActionMode, оба без успеха.
Обновление:
Интересно, имеет ли это какое-то отношение к тому, что я устанавливаю фон строки состояния. Все мои классы активности являются производными от NavigationDrawerActivity.java:
/**
* An {@link Activity} that supports a Navigation Drawer, which is a pull-out panel for navigation
* menus. This drawer is pulled out from the left side of the screen (right side on RTL devices).
*/
public class NavigationDrawerActivity extends ActionBarActivity
implements AdapterView.OnItemClickListener {
private static final String LOGTAG = NavigationDrawerActivity.class.getSimpleName();
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private LayoutInflater mInflater;
private NavigationDrawerItemAdapter mAdapter;
private ActionBarDrawerToggle mDrawerToggle;
private NavigationDrawerItem[] mNavigationDrawerItems;
private Toolbar mAppBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// We have to call super.setContentView() here because BaseActivity redefines setContentView(),
// and we don't want to use that.
super.setContentView(R.layout.navigation_drawer);
mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
setupNavigationDrawer();
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
mDrawerToggle.syncState();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch(id) {
case android.R.id.home:
return mDrawerToggle.onOptionsItemSelected(item);
}
return super.onOptionsItemSelected(item);
}
/**
* Toggles the state of the navigation drawer (i.e. closes it if it's open, and opens it if
* it's closed).
*/
public void toggleNavigationDrawer() {
if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
closeNavigationDrawer();
} else {
openNavigationDrawer();
}
}
/**
* Opens the navigation drawer.
*/
public void openNavigationDrawer() {
mDrawerLayout.openDrawer(GravityCompat.START);
}
/**
* Closes the navigation drawer.
*/
public void closeNavigationDrawer() {
mDrawerLayout.closeDrawer(GravityCompat.START);
}
/**
* Initializes items specific to the navigation drawer.
*/
private void setupNavigationDrawer() {
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerLayout.setStatusBarBackgroundColor(getResources().getColor(R.color.wiw_green));
mAppBar = (Toolbar) findViewById(R.id.app_bar);
setSupportActionBar(mAppBar);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeButtonEnabled(true);
actionBar.setDisplayShowHomeEnabled(false);
mDrawerToggle = new ActionBarDrawerToggle(
this, /* Our context (Activity that hosts this drawer) */
mDrawerLayout, /* The DrawerLayout where the nav drawer will be drawn */
R.string.drawer_open, /* Description of "open drawer", for accessibility */
R.string.drawer_close /* Description of "close drawer", for accessibility */
) {
/**
* Called when a drawer has settled in a completely closed state.
*/
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
supportInvalidateOptionsMenu();
}
/**
* Called when a drawer has settled in a completely open state.
*/
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
supportInvalidateOptionsMenu();
}
};
mDrawerList = (ListView) mDrawerLayout.findViewById(R.id.drawer_list);
mNavigationDrawerItems = buildNavDrawerItemsList();
setupAdapter(mNavigationDrawerItems);
setupNavigationDrawerHeader();
mDrawerLayout.setDrawerListener(mDrawerToggle);
mDrawerList.setOnItemClickListener(this);
}
@Override
public void onItemClick(AdapterView<?> parent, View aView, int aPosition, long aId) {
// Code not relevant
}
/**
* Set the inner content view of this {@link NavigationDrawerActivity} to have a given layout.
*
* @param aLayoutId The id of the layout to load into the inner content view of this activity.
*/
public void setDrawerContent(int aLayoutId) {
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ViewGroup root = (ViewGroup)findViewById(R.id.drawer_content);
inflater.inflate(aLayoutId, root);
}
}
Мне действительно нужно запустить DrawerLayout.setStatusBarBackgroundColor(), чтобы это возымело эффект. Просто изменение colorPrimaryDark в values-v21/styles.xml не влияет на строку состояния. Я чувствую, что это может быть корнем проблемы... Эти классы являются преобразованная из нематериальной темы в новую, похожую на материал тему, поэтому мне интересно, не пропустил ли я что-то, когда я сделал преобразование в colorPrimaryDark, чтобы быть правильно распознанным.
9 ответов:
Я публикую ответ здесь, потому что, хотя другие решения были полезны, ни одно из них не ответило на вопрос точно. Я смог выяснить, что звонок в
DrawerLayout.setStatusBarBackgroundColor()был причиной неприятностей. Мое решение заключается в следующем:
- включить
windowTranslucentStatusиwindowDrawsSystemBarBackgroundsв главной теме.- удалите вызов
DrawerLayout.setStatusBarBackgroundColor()внутри моегоNavigationDrawerActivity, из которого происходят все классыActivity.- задайте следующие стили в моей базовой теме
values-v21/styles.xml:@color/app_green @color/app_green @color/app_green_dark @color/app_green_dark ?attr/colorPrimaryDark ?attr/colorPrimaryDark
Внутри Класс
NavigationDrawerActivity, в его методеonCreate(), я выполняю следующее (Спасибо @Tinadm за эту часть ответа):getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);Внутри моего класса, который представляет
ActionMode, я добавил следующие методы:@Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); // This is to highlight the status bar and distinguish it from the action bar, // as the action bar while in the action mode is colored app_green_dark getActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.app_green_darker)); } // Other stuff... return true; } @Override public void onDestroyActionMode(ActionMode mode) { mActionMode = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); getActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.app_green_dark)); } }Повторное включение полупрозрачной строки состояния при уничтожении
ActionModeпозволяет нарисовать мой навигационный ящик под строкой состояния. Также стоит отметить, чтоActionModeнакладывается на панель действий, поэтому он будет накладываться на навигационный ящик, если он вытащил, когдаActionModeвключен (с помощью прокрутки влево-вправо). Я собираюсь отключить эту функцию, когдаActionModeвключен, чтобы это не смущало пользователей.
Ну, ваше временное решение-вызвать этот код, когда он вам больше всего нужен или когда проблема начинается
if(Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP){ getWindow().setStatusBarColor(Color.BLUE); // or Color.TRANSPARENT or your preferred color }EDIT
Вы пробовали это
// actionMode.getCustomView().setBackgroundColor.(Color.TRANSPARENT);
@Override public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { //but this time you let the actionmode's view change the statusbar's // visibility actionMode.getCustomView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LOW_PROFILE); //or preferred one return true; }Когда ваш
actionModeбудет уничтожен, строка состояния будет восстановлена, так что переопределите это тоже и заново установите цвет строки состояния.Надеюсь, это поможет
У меня была точно такая же проблема, как и у вас. Мне удалось решить ее, используя обходной путь.
- Первое, что я сделал, это убрал
windowTranslucentStatus=trueиз моей темы;- Затем я использовал
getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);, чтобы содержимое заполнило область под строкой состояния.- я задаю
<item name="android:colorPrimaryDark">@color/primary_dark</item>, где primary_dark - это "#51000000". Обратите внимание на альфа-значение для достижения того же trasparency, что windowTranslucent обеспечивает. Поскольку моя панель инструментов синяя, моя строка состояния теперь темно-синяя.Это само по себе не решило проблему. проблема. Когда режим действия активен, строка состояния все еще была черной в моем случае. Но теперь, не используя translucentStatusBar, я могу применить цвета к строке состояния, поэтому я использовал:
@Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { getActivity().getWindow().setStatusBarColor(Color.parseColor("#026592")); return true; }(Обратите внимание, что цвет, который я использовал, не имеет Альфа. Это цвет RGB, который точно соответствует моей темно-синей полупрозрачной строке состояния).
Я столкнулся с той же проблемой некоторое время назад, и мое решение было в onCreateActionMode & onDestroyActionMode установить и восстановить цвет строки состояния.
//onCreateActionMode mStartColor = activity.getWindow().getStatusBarColor(); getWindow().setStatusBarColor(color); //onDestroyActionMode activity.getWindow().setStatusBarColor(mStartColor);Конечно, вам нужно будет проверить, что его на lolipop, прежде чем использовать метод setStatusBarColor, поскольку он недоступен до L.
Дополнительно: если вы используете DrawerLayout, вам также нужно будет установить statusBarColor на нем.
mDrawerLayout.setStatusBarBackground(new ColorDrawable(color));Надеюсь, это поможет!
Просматривая документацию Android на полупрозрачные системные панели
Если вы создаете пользовательскую тему, установите одну из этих тем (тема.Голографический.NoActionBar.TranslucentDecor и тема.Голографический.Свет.NoActionBar.TranslucentDecor) в качестве родительской темы или включить свойства стиля windowTranslucentNavigation и windowTranslucentStatus в вашу тему.
Таким образом, если вы используете библиотеки поддержки, ваш стиль должен расширить некоторые стили AppCompat и используйте windowTranslucentNavigation и windowTranslucentStatus для вашего стиля ActionBarStyle.
Проблема может быть здесь.
<item name="android:background">@color/myapp_green</item> <item name="background">@color/myapp_green</item>"android: background" - это правильный синтаксис, я не думаю, что" background". Зачем вообще нужно дважды указывать цвет фона? Снимите второй, и все будет в порядке. Если нет, то я надеюсь, что мои 2 цента ниже по теме
setBackgroundColorметоды помогут.$0.02
По своему опыту я обнаружил, что время от времениsetBackgroundColor()метод в Android ведет себя странно. Когда это происходит, я используюsetBackground()вместо этого и указываю цвет в рисованной форме:getResources().getDrawable(R.color.xxxx). Я никогда не выяснял, почему это решило подобные проблемы, которые у меня были в прошлом, но я использовал этот обходной путь до сих пор без каких-либо очевидных побочных эффектов. Возможно, это не самое лучшее решение (особенно если вы уже устанавливаете фон для рисования), но оно пригодится, когда больше ничего не работает.
Я получил тот же вопрос и решил его следующим образом
Проблема заключалась в переопределении одного и того же цвета для всех представлений.Но я не могу пойти с
R.color.mycolorиColor.parseColor("#412848")спас меня.
@Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { super.onPrepareActionMode(mode, menu); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { Window w = getActivity().getWindow(); w.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); w.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); } return true; } @Override public void onDestroyActionMode(ActionMode mode) { super.onDestroyActionMode(mode); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { Window w = getActivity().getWindow(); w.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); w.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); } }
Хотя я использовал предыдущие решения ранее, есть больше проблем при добавлении навигационного ящика, если вы хотите, чтобы ящик рисовал за системной панелью, и так много глюков, связанных с установкой и очисткой флагов окна или цвета строки состояния (даже официальное приложение Gmail имеет эти глюки!)
Вот решение, которое я использую сейчас:
Это, очевидно, большой Хак, и он не анимирует точно так же, как контекстная панель действий, но он делает трюк для меня. Реквизит к https://stackoverflow.com/a/38702953/1317564 за то, что придумал эту идею.@Override public void onSupportActionModeStarted(@NonNull ActionMode mode) { super.onSupportActionModeStarted(mode); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // Post this so it ideally happens after the window decor callbacks. new Handler().post(new Runnable() { @Override public void run() { try { final AppCompatDelegate delegate = getDelegate(); final Class clazz = Class.forName("android.support.v7.app.AppCompatDelegateImplV7"); final Field mStatusGuardField = clazz.getDeclaredField("mStatusGuard"); mStatusGuardField.setAccessible(true); final View mStatusGuard = (View) mStatusGuardField.get(delegate); if (mStatusGuard != null) { mStatusGuard.setBackgroundColor(/* Should match your desired status bar color when the action mode is showing, or alternatively you could use Color.TRANSPARENT here and just update the colors through getWindow().setStatusBarColor() below. The key is to avoid the black status guard from appearing. */); } } catch (Exception e) { /* Log or handle as desired. */ } } }); // Also set the status bar color. This is to avoid a momentary frame or // two where the black will still be visible. getWindow().setStatusBarColor(/* Should match your desired status bar color when the action mode is showing. */); } } @Override public void onSupportActionModeFinished(@NonNull ActionMode mode) { super.onSupportActionModeFinished(mode); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // Reset to the theme's colorPrimaryDark. This would normally result in // the black status guard being seen momentarily, but because we set it // to the same color as the action mode background, this intermediate // state is not visible. getWindow().setStatusBarColor(Color.TRANSPARENT); } }Обратите внимание, что это необходимо только в том случае, если вы используете навигационный ящик или иным образом задаете эти атрибуты в своих значениях-v21/theme.xml:
<item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:statusBarColor">@android:color/transparent</item>В противном случае, вероятно, будет работать просто вызвать
setStatusBarColor(...)вonSupportActionModeStarted()иonSupportActionModeFinished(), и это то, что я делал перед добавлением навигационного ящика.
Comments