Подтвердить что ты не робот

При использовании 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, поэтому он существует в моем макете (т.е. ящик навигации рисует поверх него).

Все работает отлично, за исключением того, что в одном из моих действий у меня есть режим multi-select с 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, оба без успеха.

Update:

Интересно, имеет ли это какое-то отношение к лаконичному способу настройки фона строки состояния. Все мои классы активности происходят из 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 open, and opens it if
   * it 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 для корректного распознавания.

4b9b3361

Ответ 1

Я пишу здесь ответ, потому что, хотя другие решения были полезны, никто из них точно не ответил на вопрос. Я смог узнать, что вызов 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
  1. Внутри класса NavigationDrawerActivity в методе onCreate() я выполняю следующее (спасибо @Tinadm для этой части ответа): getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);

  2. Внутри моего класса, который представляет 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, поэтому он не путает пользователей.

Ответ 2

Хорошо, ваше временное решение вызывает этот код, когда вам это больше всего нужно или когда проблема начинается.

if(Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP){
    getWindow().setStatusBarColor(Color.BLUE); 
    // or Color.TRANSPARENT or your preferred color
}

ИЗМЕНИТЬ

Вы пробовали это

// actionMode.getCustomView().setBackgroundColor.(Color.TRANSPARENT);

@Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {    
    //but this time you let the actionmode view change the statusbar's
    // visibility
    actionMode.getCustomView().setSystemUiVisibility(
        View.SYSTEM_UI_FLAG_LOW_PROFILE); //or preferred one
    return true;
}

когда ваш actionMode будет уничтожен, строка состояния будет восстановлена, поэтому переопределите это и снова установите цвет statusBar.

надеюсь, что это поможет

Ответ 3

У меня была точно такая же проблема, как и вы. Мне удалось решить его с помощью обходного пути.

  • Первое, что я сделал, это удалить 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". Обратите внимание на значение alpha для достижения той же прозрачности, что и windowTranslucent. Поскольку моя панель инструментов синяя, моя строка состояния теперь синяя.
  • Это само по себе не решило проблему. Когда режим действия активен, в моем случае строка состояния была еще черной. Но теперь, не используя translucentStatusBar, я могу применить цвета к своей строке состояния, поэтому я использовал:

    @Override
    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
        getActivity().getWindow().setStatusBarColor(Color.parseColor("#026592"));
        return true;
    }
    

(Обратите внимание, что цвет, который я использовал, не имеет альфы. Это цвет RGB точно соответствует моей синей полупрозрачной строке состояния).

Ответ 4

Я столкнулся с той же проблемой некоторое время назад, и моя резолюция заключалась в том, что в onCreateActionMode и onDestroyActionMode установлен и восстанавливается цвет статусной панели.

//onCreateActionMode
mStartColor =  activity.getWindow().getStatusBarColor();
getWindow().setStatusBarColor(color);

//onDestroyActionMode
activity.getWindow().setStatusBarColor(mStartColor);

Конечно, вам нужно проверить его на lolipop перед использованием метода setStatusBarColor как его недоступного pre L.

Дополнительно: если вы используете DrawerLayout, вам также нужно установить statusBarColor.

mDrawerLayout.setStatusBarBackground(new ColorDrawable(color));

Надеюсь, что это поможет!

Ответ 5

Просмотр документации Android на Прозрачные системные панели

Если вы создаете настраиваемую тему, установите одну из этих тем (Theme.Holo.NoActionBar.TranslucentDecor и Theme.Holo.Light.NoActionBar.TranslucentDecor) в качестве родительской темы или включите свойства стиля windowTranslucentNavigation и windowTranslucentStatus в своем тема.

Итак, если вы используете библиотеки поддержки, ваш стиль должен расширить некоторые стили AppCompat и использовать как windowTranslucentNavigation, так и windowTranslucentStatus на вашем ActionBarStyle.

Ответ 6

Проблема может быть здесь.

<item name="android:background">@color/myapp_green</item>
<item name="background">@color/myapp_green</item>

"android: background" - это правильный синтаксис, я не думаю, что "фон" есть. Почему вам нужно указать цвет фона дважды? Удалите второй, и все должно быть хорошо. Если нет, то, надеюсь, мои 2 цента ниже по теме setBackgroundColor помогают.

$0.02

По моему опыту, я обнаружил, что время от времени метод setBackgroundColor() в Android ведет себя странно. Когда это произойдет, вместо этого я использую setBackground() и задаю цвет в выпадающей форме: getResources().getDrawable(R.color.xxxx). Я никогда не узнал, почему это разрешило подобные проблемы, которые у меня были в прошлом, но я использовал этот обходной путь до сих пор без каких-либо очевидных побочных эффектов. Это может быть не лучшее решение (особенно если вы уже устанавливаете фоновый рисунок), но это пригодится, когда ничего больше не работает.

Ответ 7

У меня такая же проблема, и я решил ее следующим образом

Проблема заключалась в переопределении одного цвета для всех представлений. Но я не смог с R.color.mycolor и Color.parseColor("#412848") сохранить меня.

Ответ 8

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

Ответ 9

В то время как раньше я использовал предыдущие решения, есть дополнительные проблемы при добавлении ящика навигации, если вы хотите, чтобы ящик рисовал за системной панелью, и так много сбоев, связанных с установкой и очисткой флагов окна или цветом строки состояния ( даже официальное приложение Gmail имеет эти сбои!)

Здесь решение, которое я использую сейчас:

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

Это, очевидно, большой взлом, и он не оживляет точно так же, как это делает контекстная панель действий, но это делает трюк для меня. Подтверждает fooobar.com/info/219947/..., чтобы придумать эту идею.

Обратите внимание, что это необходимо только в том случае, если вы используете ящик для навигации или иначе эти атрибуты установлены в ваших значениях-v21/theme.xml:

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

В противном случае, вероятно, будет работать только вызов setStatusBarColor(...) в onSupportActionModeStarted() и onSupportActionModeFinished(), и это то, что я делал перед добавлением переносного ящика навигации.