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?

Stevie Kideckel
źródło
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.)
Muzikant
źródło
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.

Amrut Bidri
źródło
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>
GDA
źródło
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.

Justin
źródło
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ę

user330844
źródło
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

Lew
źródło
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;

Salman Anjum
źródło
0

Napisz te dwie linie w dodatku do swojego kodu

Toolbar toolbar=(Toolbar)viewActionBar.getParent();
toolbar.setContentInsetsAbsolute(0,0);
Anisuzzaman Babla
źródło