Android Lollipop, пользовательский вид AppCompat ActionBar не занимает всю ширину экрана

97

Итак, я только что обновил свою кодовую базу до Lollipop, и у меня проблемы с панелью действий. Я использую AppCompat и ActionBarActivity и создаю настраиваемое представление. Кажется, что пользовательский вид больше не занимает всю ширину экрана, оставляя тонкую полоску слева

Здание с 19 Как это выглядело раньше

Здание с 21 Как это выглядит сейчас

Это код, который я использую для настройки панели действий. У кого-нибудь есть идеи?

final ActionBar actionBar = getSupportActionBar();
if(actionBar != null) {
    actionBar.setDisplayHomeAsUpEnabled(false);
    actionBar.setDisplayShowHomeEnabled(false);
    actionBar.setDisplayShowTitleEnabled(false);
    actionBar.setDisplayShowCustomEnabled(true);
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
    actionBar.setCustomView(R.layout.action_bar_content_search_custom_view);
    actionBar.setBackgroundDrawable(null);
    // actionBar.setStackedBackgroundDrawable(null);
    TextView title = (TextView) actionBar.getCustomView().findViewById(R.id.action_bar_title);
    title.setText(R.string.youtube);
    ImageView back = (ImageView) actionBar.getCustomView().findViewById(R.id.action_bar_back);
    back.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            finish();
        }
    });
}

редактировать

Удаление пользовательского вида и изменение фона теперь занимает всю ширину. Итак, проблема в том, как мы можем заставить CustomView занимать всю ширину ActionBar?

Стиви Кидекель
источник
Если вы временно закомментируете пользовательские части просмотра, станет ли он лучше? Если нет, я бы склонился к этому, возможно, исходя из вашей темы.
CommonsWare
Я удалил настраиваемый вид и установил его как фон, который можно рисовать для ActionBar, и теперь фон занимает всю ширину
Stevie Kideckel
Вы можете взглянуть на свою активность в представлении иерархии, как с настраиваемым представлением, так и без него, и посмотреть, сможете ли вы определить, какие правила макета смещаются в результате настраиваемого представления. Возможно, это ошибка в новом appcompat-v7.
CommonsWare
Мне кажется, это место, зарезервированное для верха ImageView. Попробуйте отключить его для начала.
Никола Деспотоски
1
Привет, кажется, это хорошее решение, чтобы пользовательский вид занимал всю ширину. Я заметил, что он не расширяется даже при установленном весе макета. см. здесь: stackoverflow.com/a/20794736/581574
ratana

Ответы:

111

Похоже, это вызвано последними изменениями ActionBarв последнем appcompat-v7обновлении. Похоже, что есть значительные изменения в том, как вы должны обрабатывать панели действий.

Я столкнулся с той же проблемой и, прочитав ActionBarдокументацию , и особенно следующую цитату, нашел решение.

Начиная с Android L (уровень API 21), панель действий может быть представлена ​​любым виджетом панели инструментов в макете приложения. Приложение может сигнализировать Activity, какую панель инструментов следует рассматривать как панель действий Activity. Действия, которые используют эту функцию, должны использовать одну из предоставленных тем .NoActionBar, установить для атрибута windowActionBar значение false или иным образом не запрашивать функцию окна.

На мой взгляд, AppCompatтемы были изменены, и, с одной стороны, казалось, что некоторые вещи ломаются, но с другой стороны, обеспечивается гораздо больше гибкости. Я рекомендую выполнить следующие действия:

  1. Используйте .NoActionBarстиль в своей деятельности, как описано в приведенной выше цитате
  2. Добавьте android.support.v7.widget.Toolbarв свой макет Activity
  3. Установите app:contentInsetStart="0dp"атрибут. Это основная проблема с маржей, которую вы описываете в своем вопросе.
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/actionBar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:contentInsetEnd="0dp"
    app:contentInsetStart="0dp" >
</android.support.v7.widget.Toolbar>

Обычно рекомендуется делать это в отдельном файле макета и использовать includeв макете занятия, поэтому вам нужно будет настроить панель инструментов только в одном месте, если она используется в нескольких действиях.

<include layout="@layout/view_action_bar" />
  1. Используйте findViewByIdи setSupportActionBarв своей деятельности, onCreateчтобыsignal to the Activity which Toolbar should be treated as the Activity's action bar
Toolbar actionBar = (Toolbar) findViewById(R.id.actionBar);
setSupportActionBar(actionBar);
  1. Как только вы это сделаете, все добавленные действия onCreateOptionsMenuбудут добавлены на панель инструментов и будут обрабатываться как панель действий активности.
  2. Далее настройте панель инструментов по желанию (добавьте дочерние представления и т. Д.)
Музикант
источник
1
Я пытаюсь использовать панель инструментов с навигационным ящиком, но получаю сообщение об ошибкеError inflating class fragment
Ахмед Наваз
Весь соответствующий код указан в ответе. Похоже, вам следует задать новый вопрос по вашему делу, поскольку это кажется другой проблемой.
Muzikant
Спасибо. Я решил проблему, заменив панель действий на панель инструментов.
Ахмед Наваз,
9
Вы не должны использовать явные имена пакетов в объявлениях пространств имен. Использованиеxmlns:app="http://schemas.android.com/apk/res-auto"
Liminal
1
В этом нет необходимости setCustomView. Просто создайте файл макета с виджетами, которые вы хотите включить в свою панель инструментов (например, добавьте дочерние представления в файл макета, описанный в разделе 3 ответа)
Muzikant
51

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

    getSupportActionBar().setDisplayShowHomeEnabled(false);
    getSupportActionBar().setDisplayShowTitleEnabled(false);
    getSupportActionBar().setBackgroundDrawable(new ColorDrawable(Color.WHITE));
    LayoutInflater mInflater = LayoutInflater.from(this);

    View mCustomView = mInflater.inflate(R.layout.action_bar_home, null);
    getSupportActionBar().setCustomView(mCustomView);
    getSupportActionBar().setDisplayShowCustomEnabled(true);
    Toolbar parent =(Toolbar) mCustomView.getParent();//first get parent toolbar of current action bar 
    parent.setContentInsetsAbsolute(0,0);// set padding programmatically to 0dp

Вам нужно добавить только последние две строки кода, чтобы решить вашу проблему.

Я надеюсь, что это может помочь вам и всем остальным.

ОБНОВЛЕНИЕ: Проведя некоторое исследование, я обнаружил, что это решение в некоторых случаях не работает. При этом будет удален левый зазор (HOME или BACK), а правый зазор (MENU) останется как есть. Ниже приводится решение в этих случаях.

View v = getSupportActionBar().getCustomView();
LayoutParams lp = v.getLayoutParams();
lp.width = LayoutParams.MATCH_PARENT;
v.setLayoutParams(lp);

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

Амрут Бидри
источник
Спасибо! Спасибо! последние 2 строки были тем, что я искал!
digitalmidges
Куда мы добавляем эти строки? После части панели инструментов?
Zen
1
@summers да добавить их сразу после кода панели инструментов.
Амрут Бидри,
31

Я думаю, вы также можете сделать это в стилях. попробуй это. протестировал это на kitkat

<style name="AppTheme" parent="Theme.AppCompat">
  <item name="toolbarStyle">@style/AppThemeToolbar</item>
</style>

<style name="AppThemeToolbar" parent="Widget.AppCompat.Toolbar" >
  <item name="contentInsetStart">0dp</item>
</style>
GDA
источник
1
Этот ответ неверен: android: contentInsetStart требует уровня API 21 (текущий минимум 14)
mr.boyfox
Но идиома очень хороша! Вам нужно писать стиль отдельно для api 21 и старых версий.
mr.boyfox
Это правильный ответ для удаления левого поля, если вы все еще используете панель действий по умолчанию.
Tooroop
Это действительно работает! С последней версией библиотеки поддержки, я думаю, вам не нужно объявлять атрибуты дважды (android: не нужны).
Совет директоров
Я искал эту проблему, и когда я нашел ваш ответ, я понял, что уже проголосовал за него! Так что спасибо дважды.
user1732313
8

Ни один из других ответов не помог мне, поэтому я взглянул на фактические стили AppCompat v7, найденные здесь .

Если вы посмотрите на стиль Base.Widget.AppCompat.ActionBar, он имеет:

<item name="contentInsetStart">@dimen/abc_action_bar_content_inset_material</item>
<item name="contentInsetEnd">@dimen/abc_action_bar_content_inset_material</item>

Очевидно, нам просто нужно переопределить эти свойства в нашем собственном стиле панели действий:

<style name="ActionBar" parent="@style/Base.Widget.AppCompat.ActionBar">
        <item name="contentInsetStart">0dp</item>
        <item name="contentInsetEnd">0dp</item>
</style>

Это отлично сработало для меня, надеюсь, это поможет и другим.

Джастин
источник
Да, как указано в выбранном ответе, ключом являются атрибуты contentInsetStart и contentInsetEnd ActionBar / Toolbar. Допустимо определить свой собственный стиль, но вы также можете установить для них значение 0dp в атрибутах Панели инструментов в вашем xml
Стиви Кидекель,
1

После долгих ударов головой о монитор это сработало для меня.

 Toolbar toolbar = (Toolbar) actionBar.getCustomView().getParent();
        toolbar.setContentInsetStartWithNavigation(0);
        toolbar.setContentInsetEndWithActions(0);
        toolbar.setContentInsetsAbsolute(0, 0);
        toolbar.setPadding(0, 0, 0, 0);

GetCustomView (). GetParent () - вот что помогло

user330844
источник
0

Я только что столкнулся с этой проблемой сегодня, потом я узнал, что у меня res/values-v21/styles.xml внутри моего проекта, который был автоматически сгенерирован Android Studio, и это причина.

Зачем?

Потому что мой res/values-v21/styles.xmlконтент был:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="BaseAppTheme" parent="android:Theme.Material.Light">
    </style>
</resources>

А в моем res/values/styles.xmlсодержалось что-то вроде:

<style name="BaseAppTheme" parent="android:Theme.Holo.Light">
    <!-- Customize your theme here. -->
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:soundEffectsEnabled">false</item>
</style>

Затем, когда я запустил свое приложение на Lollipop, он res/values-v21/styles.xmlбыл использован, и это вызвало ту же проблему, что и у OP. Итак, я пришел к простому исправлению - просто удалил:

    <style name="BaseAppTheme" parent="android:Theme.Material.Light">
    </style>

в res/values-v21/styles.xml

Лео
источник
0

к точке:

 ActionBar actionBar = getSupportActionBar();
                actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
                actionBar.setCustomView(R.layout.actionbar_layout);
                Toolbar toolbar = (Toolbar) actionBar.getCustomView().getParent();
                    toolbar.setContentInsetsAbsolute(0, 0);
                    toolbar.setPadding(0, 0, 0, 0);

убедитесь, что импортируете правильную панель инструментов - android.support.v7.widget.Toolbar;

Салман Анджум
источник
0

Напишите эти две строки вместе со своим кодом

Toolbar toolbar=(Toolbar)viewActionBar.getParent();
toolbar.setContentInsetsAbsolute(0,0);
Анисуцзаман Бабла
источник