Android Lollipop, niestandardowy widok AppCompat ActionBar nie zajmuje całej szerokości ekranu


97

Właśnie zaktualizowałem moją bazę kodu do Lollipopa i mam problemy z paskiem akcji. Używam AppCompat i ActionBarActivity oraz napompowania widoku niestandardowego. Wygląda na to, że niestandardowy widok nie zajmuje już całej szerokości ekranu, pozostawiając cienki pasek po lewej stronie

Budynek z 19 Tak jak kiedyś wyglądało

Budynek z 21 Tak to wygląda teraz

To jest kod, którego używam do ustawienia paska akcji. Czy ktoś ma jakieś pomysły?

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

Edytować

Usunięcie widoku niestandardowego i zmiana tła zajmuje teraz całą szerokość. Problem w tym, w jaki sposób możemy sprawić, by CustomView zajmował całą szerokość ActionBar?


Jeśli tymczasowo zakomentujesz części widoku niestandardowego, czy zachowują się lepiej? Jeśli nie, skłaniam się ku temu, być może z twojego motywu.
CommonsWare

Usunąłem niestandardowy widok i ustawiłem jego tło jako tło, które można rysować na pasku akcji, a tło zajmuje teraz całą szerokość
Stevie Kideckel

Możesz zerknąć na swoją aktywność w widoku hierarchii, zarówno z widokiem niestandardowym, jak i bez niego, i sprawdzić, czy możesz określić, które reguły układu zmieniają się w wyniku widoku niestandardowego. Możliwe, że jest to błąd w nowym appcompat-v7.
CommonsWare

Wygląda na to, że to miejsce zarezerwowane dla góry ImageView. Spróbuj go wyłączyć na początek.
Nikola Despotoski

1
Cześć, wydaje się, że to dobre rozwiązanie, aby niestandardowy widok zajmował całą szerokość. Doświadczyłem, że nie rozwijał się, nawet przy ustawionych wagach układu. patrz tutaj: stackoverflow.com/a/20794736/581574
ratana

Odpowiedzi:


111

Wygląda na to, że jest to spowodowane ostatnimi zmianami ActionBarw ostatniej appcompat-v7aktualizacji. Wygląda na to, że zaszły znaczące zmiany w sposobie obsługi pasków akcji.

Napotkałem ten sam problem i po przeczytaniu ActionBardokumentacji , a zwłaszcza poniższego cytatu znalazłem rozwiązanie.

Począwszy od systemu Android L (poziom API 21), pasek akcji może być reprezentowany przez dowolny widżet paska narzędzi w układzie aplikacji. Aplikacja może zasygnalizować działaniu, który pasek narzędzi należy traktować jako pasek akcji działania. Działania korzystające z tej funkcji powinny korzystać z jednego z dostarczonych motywów .NoActionBar, ustawić atrybut windowActionBar na false lub w inny sposób nie żądać funkcji okna.

Sposób, w jaki to widzę, AppCompatzmienił się temat i z jednej strony wydawał się zepsuć kilka rzeczy, z drugiej zapewniał dużo większą elastyczność. Polecam następujące kroki:

  1. Użyj .NoActionBarstylu w swojej działalności, jak opisano w powyższym cytacie
  2. Dodaj android.support.v7.widget.Toolbardo swojego układu działania
  3. Ustaw app:contentInsetStart="0dp"atrybut. To jest główny problem związany z marginesem, który opisujesz w swoim pytaniu
<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>

Zwykle zaleca się zrobienie tego w oddzielnym pliku układu i użycie includew układzie działania, więc wystarczy dostosować pasek narzędzi w jednym miejscu, jeśli jest używany w wielu działaniach

<include layout="@layout/view_action_bar" />
  1. Użyj findViewByIdi setSupportActionBarw swojej aktywności, onCreateabysignal to the Activity which Toolbar should be treated as the Activity's action bar
Toolbar actionBar = (Toolbar) findViewById(R.id.actionBar);
setSupportActionBar(actionBar);
  1. Gdy to zrobisz, wszystkie dodane akcje onCreateOptionsMenuzostaną dodane do paska narzędzi i będą traktowane jako pasek działań.
  2. Dalsze dostosowywanie paska narzędzi według potrzeb (dodawanie widoków podrzędnych itp.)

1
Próbuję użyć paska narzędzi Toolbar z szufladą nawigacji, ale pojawia się błądError inflating class fragment
Ahmed Nawaz

Cały odpowiedni kod jest udostępniony w odpowiedzi. Wygląda na to, że powinieneś rozpocząć nowe pytanie w swojej sprawie, ponieważ wydaje się, że to inny problem.
Muzikant

Dzięki. Rozwiązałem problem, zastępując pasek akcji paskiem narzędzi Toolbar.
Ahmed Nawaz

9
Nie należy używać jawnych nazw pakietów w deklaracjach przestrzeni nazw. Użytkowaniexmlns:app="http://schemas.android.com/apk/res-auto"
Liminal

1
Nie ma takiej potrzeby setCustomView. Po prostu zbuduj plik układu z widżetami, które chcesz dołączyć do paska narzędzi (np. Dodaj widoki potomne do pliku układu opisanego w sekcji 3 odpowiedzi)
Muzikant

51

Zamiast wykonywać tyle pracy, o czym wspomniał Muzikant i polubić tę odpowiedź

    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

Aby rozwiązać problem, musisz dodać tylko ostatnie dwie linie kodu.

Mam nadzieję, że to pomoże tobie i komukolwiek innemu.

AKTUALIZACJA: Po przeprowadzeniu pewnych badań stwierdziłem, że to rozwiązanie w niektórych przypadkach nie zadziała. Luka po lewej stronie (HOME lub BACK) zostanie usunięta, ale szczelina po prawej stronie (MENU) pozostanie bez zmian. Poniżej znajduje się rozwiązanie w takich przypadkach.

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

Dodaj te cztery wiersze do powyższego kodu, tak aby prawy boczny odstęp został również usunięty z paska akcji wsparcia.


dzięki! dzięki! ostatnie 2 wiersze były tym, czego szukałem!
digitalmidges

Gdzie dodajemy te linie? Po części paska narzędzi?
Zen

1
@summers tak, dodaj je natychmiast po kodzie paska narzędzi.
Amrut Bidri

31

Myślę, że możesz to również zrobić w stylach. Spróbuj tego. przetestowałem to na KitKacie

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

1
Ta odpowiedź jest nieprawidłowa: android: contentInsetStart wymaga interfejsu API na poziomie 21 (obecny min to 14)
mr.boyfox

Ale idiom bardzo dobry! Musisz osobno napisać styl dla API 21 i starszych wersji.
mr.boyfox,

To jest poprawna odpowiedź, aby usunąć lewy margines, jeśli nadal używasz domyślnego paska akcji.
Tooroop

To rzeczywiście działa! Myślę, że w najnowszej wersji biblioteki obsługi nie trzeba deklarować atrybutów dwa razy (android: one nie są konieczne).
BoD

Szukałem tego problemu i kiedy znalazłem twoją odpowiedź, widzę, że już na to zagłosowałem! Dziękuję dwa razy.
user1732313

8

Żadna z innych odpowiedzi nie działała dla mnie, więc przyjrzałem się rzeczywistym stylom AppCompat v7, które znajdziesz tutaj .

Jeśli spojrzysz na styl Base.Widget.AppCompat.ActionBar, ma:

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

Więc oczywiście musimy po prostu zastąpić te właściwości naszym własnym stylem paska akcji:

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

To zadziałało świetnie dla mnie, mam nadzieję, że pomoże też innym.


Tak, jak stwierdza wybrana odpowiedź, kluczem są atrybuty contentInsetStart i contentInsetEnd paska ActionBar / Toolbar. Możesz zdefiniować swój własny styl, ale możesz także ustawić je na 0dp w atrybutach paska narzędzi w swoim xml
Stevie Kideckel

1

Po wielu uderzeniach głową w monitor, to zadziałało

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

GetCustomView (). GetParent () jest tym, co załatwiło sprawę


0

Właśnie dzisiaj napotkałem ten problem, a potem dowiedziałem się, że mam res/values-v21/styles.xml wewnątrz projekt, który został wygenerowany automatycznie przez Android Studio i to jest przyczyna.

Czemu?

Ponieważ moja res/values-v21/styles.xmlzawartość to:

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

A mój res/values/styles.xmlzawierał coś takiego:

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

Następnie, kiedy uruchomiłem moją aplikację na Lollipop, res/values-v21/styles.xmlzostał użyty, co spowodowało dokładny problem, który miał OP. Więc doszedłem do prostej poprawki, która polega na usunięciu:

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

w res/values-v21/styles.xml


0

do momentu:

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

upewnij się, że importujesz odpowiedni pasek narzędzi - android.support.v7.widget.Toolbar;


0

Napisz te dwie linie w dodatku do swojego kodu

Toolbar toolbar=(Toolbar)viewActionBar.getParent();
toolbar.setContentInsetsAbsolute(0,0);
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.