Die benutzerdefinierte Ansicht von Android Lollipop, AppCompat ActionBar nimmt nicht die gesamte Bildschirmbreite ein

97

Ich habe gerade meine Codebasis auf Lollipop aktualisiert und habe Probleme mit der Aktionsleiste. Ich verwende AppCompat und ActionBarActivity und fülle eine benutzerdefinierte Ansicht auf. Es scheint, dass die benutzerdefinierte Ansicht nicht mehr die gesamte Breite des Bildschirms einnimmt und links einen dünnen Streifen hinterlässt

Gebäude mit 19 So sah es früher aus

Gebäude mit 21 So sieht es jetzt aus

Dies ist der Code, mit dem ich die Aktionsleiste einrichte. Hat jemand irgendwelche Ideen?

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

Bearbeiten

Das Herausnehmen der benutzerdefinierten Ansicht und das Ändern des Hintergrunds nimmt jetzt die gesamte Breite ein. Das Problem ist also, wie kann eine CustomView die gesamte Breite der ActionBar einnehmen?

Stevie Kideckel
quelle
Wenn Sie die benutzerdefinierten Ansichtsteile vorübergehend auskommentieren, verhält es sich dann besser? Wenn nicht, würde ich mich dazu neigen, vielleicht von Ihrem Thema.
CommonsWare
Ich habe die benutzerdefinierte Ansicht entfernt und den Hintergrund als Hintergrund für die ActionBar festgelegt, und der Hintergrund nimmt jetzt die gesamte Breite ein
Stevie Kideckel,
Sie können einen Blick auf Ihre Aktivität in der Hierarchieansicht mit und ohne benutzerdefinierte Ansicht werfen und prüfen, ob Sie feststellen können, welche Layoutregeln sich aufgrund der benutzerdefinierten Ansicht verschieben. Es ist möglich, dass dies ein Fehler in der neuen ist appcompat-v7.
CommonsWare
Sieht für mich so aus, als wäre der Platz reserviert ImageView. Versuchen Sie zunächst, es zu deaktivieren.
Nikola Despotoski
1
Hallo, es scheint, dass dies eine gute Lösung ist, damit die benutzerdefinierte Ansicht die gesamte Breite einnimmt. Ich habe festgestellt, dass es sich nicht ausdehnt, selbst wenn die Layoutgewichte festgelegt sind. siehe hier: stackoverflow.com/a/20794736/581574
ratana

Antworten:

111

Dies scheint auf die letzten Änderungen ActionBarim letzten appcompat-v7Update zurückzuführen zu sein. Es scheint, dass es erhebliche Änderungen im Umgang mit Aktionsleisten gibt.

Ich hatte das gleiche Problem und fand nach dem Lesen der ActionBarDokumentation und insbesondere des folgenden Zitats eine Lösung.

Ab Android L (API-Stufe 21) kann die Aktionsleiste durch ein beliebiges Symbolleisten-Widget im Anwendungslayout dargestellt werden. Die Anwendung kann der Aktivität signalisieren, welche Symbolleiste als Aktionsleiste der Aktivität behandelt werden soll. Aktivitäten, die diese Funktion verwenden, sollten eines der bereitgestellten .NoActionBar-Designs verwenden, das windowActionBar-Attribut auf false setzen oder die Fensterfunktion auf andere Weise nicht anfordern.

So wie ich es sehe, wurden die AppCompatThemen geändert und einerseits schienen einige Dinge zu brechen, andererseits bieten sie viel mehr Flexibilität. Ich empfehle folgende Schritte:

  1. Verwenden Sie .NoActionBarStil in Ihrer Aktivität, wie im obigen Zitat beschrieben
  2. Fügen Sie android.support.v7.widget.ToolbarIhrem Aktivitätslayout ein hinzu
  3. Legen Sie das app:contentInsetStart="0dp"Attribut fest. Dies ist das Hauptproblem mit dem Rand, den Sie in Ihrer Frage beschreiben
<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>

Es wird normalerweise empfohlen, dies in einer separaten Layoutdatei zu tun und includein Ihrem Aktivitätslayout zu verwenden, sodass Sie die Symbolleiste nur an einer Stelle anpassen müssen, wenn Sie sie in mehreren Aktivitäten verwenden

<include layout="@layout/view_action_bar" />
  1. Verwenden Sie findViewByIdund setSupportActionBarin Ihrer Aktivität onCreatezusignal to the Activity which Toolbar should be treated as the Activity's action bar
Toolbar actionBar = (Toolbar) findViewById(R.id.actionBar);
setSupportActionBar(actionBar);
  1. Sobald Sie dies getan haben, werden alle hinzugefügten Aktionen onCreateOptionsMenuzur Symbolleiste hinzugefügt und als Aktivitätsaktionsleiste behandelt.
  2. Passen Sie die Symbolleiste wie gewünscht weiter an (untergeordnete Ansichten hinzufügen usw.)
Muzikant
quelle
1
Ich versuche, die Symbolleiste mit der Navigationsleiste zu verwenden, erhalte jedoch eine FehlermeldungError inflating class fragment
Ahmed Nawaz
Der gesamte relevante Code wird in der Antwort geteilt. Sieht so aus, als sollten Sie eine neue Frage für Ihren Fall stellen, da dies ein anderes Problem zu sein scheint.
Muzikant
Vielen Dank. Ich habe das Problem gelöst, indem ich die Aktionsleiste durch die Symbolleiste ersetzt habe.
Ahmed Nawaz
9
Sie sollten keine expliziten Paketnamen in den Namespace-Deklarationen verwenden. Verwendungxmlns:app="http://schemas.android.com/apk/res-auto"
Liminal
1
Es besteht keine Notwendigkeit für setCustomView. Erstellen Sie einfach eine Layoutdatei mit den Widgets, die Sie in Ihre Symbolleiste aufnehmen möchten (z. B. fügen Sie der in Abschnitt 3 der Antwort beschriebenen Layoutdatei
untergeordnete
51

Anstatt so viel zu arbeiten, wie von Muzikant erwähnt, und diese Antwort zu mögen

    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

Sie müssen nur die letzten beiden Codezeilen hinzufügen, um Ihr Problem zu lösen.

Ich hoffe, das könnte Ihnen und anderen helfen.

UPDATE: Nachdem ich einige Nachforschungen angestellt hatte, stellte ich fest, dass diese Lösung in einigen Fällen nicht funktioniert. Der linke Seitenabstand (HOME oder BACK) wird damit entfernt, aber der rechte Seitenabstand (MENU) bleibt unverändert. Nachfolgend finden Sie die Lösung in diesen Fällen.

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

Fügen Sie diese vier Zeilen zum obigen Code hinzu, sodass der rechte Seitenabstand auch von der Unterstützungsaktionsleiste entfernt wird.

Amrut Bidri
quelle
Vielen Dank! Vielen Dank! Die letzten 2 Zeilen waren genau das, wonach ich gesucht habe!
Digitalmidges
Wo fügen wir diese Zeilen hinzu? Nach dem Symbolleisten-Teil?
Zen
1
@summers ja füge sie sofort nach dem Symbolleistencode hinzu.
Amrut Bidri
31

Ich denke, das kann man auch in Stilen machen. Versuche dies. habe es auf kitkat getestet

<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
quelle
1
Diese Antwort ist falsch: android: contentInsetStart erfordert API-Level 21 (aktuelle min ist 14)
mr.boyfox
Aber Redewendung sehr gut! Sie müssen den Schreibstil für API 21 und alte Versionen separat schreiben.
Mr. Boyfox
Dies ist die richtige Antwort, um den linken Rand zu entfernen, wenn Sie weiterhin die Standardaktionsleiste verwenden.
Tooroop
Das funktioniert in der Tat! Mit der neuesten Version der Support-Bibliothek müssen Sie die Attribute meiner Meinung nach nicht zweimal deklarieren (die Android-Attribute sind nicht erforderlich).
BoD
Ich habe nach diesem Problem gesucht und als ich Ihre Antwort gefunden habe, sehe ich, dass ich es bereits positiv bewertet habe! Also zweimal danke.
user1732313
8

Keine der anderen Antworten hat bei mir funktioniert, daher habe ich mir die tatsächlichen AppCompat v7-Stile angesehen, die hier zu finden sind .

Wenn Sie sich den Base.Widget.AppCompat.ActionBar-Stil ansehen, hat er:

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

Natürlich müssen wir diese Eigenschaften nur in unserem eigenen Aktionsleistenstil überschreiben:

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

Das hat bei mir super geklappt, hoffe es hilft auch anderen.

Justin
quelle
Ja, wie in der ausgewählten Antwort angegeben, sind die Attribute contentInsetStart und contentInsetEnd der ActionBar / Symbolleiste der Schlüssel. Es ist gültig, Ihren eigenen Stil zu definieren, aber Sie können sie auch auf 0dp für die Attribute der Symbolleiste in Ihrer XML setzen
Stevie Kideckel
1

Nachdem ich meinen Kopf gegen den Monitor geschlagen hatte, funktionierte dies für mich

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

Das getCustomView (). GetParent () hat den Trick gemacht

user330844
quelle
0

Ich bin heute auch auf dieses Problem gestoßen, dann habe ich herausgefunden, dass ich res/values-v21/styles.xmlin meinem Projekt etwas habe, das automatisch von Android Studio generiert wurde, und das ist die Ursache.

Warum?

Weil mein res/values-v21/styles.xmlInhalt war:

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

Und mein res/values/styles.xmlenthielt so etwas wie:

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

Als ich dann meine App auf Lollipop ausführte, res/values-v21/styles.xmlwurde die verwendet, und das verursachte genau das Problem, das OP hatte. Also bin ich zu einem einfachen Fix gekommen, der nur löscht:

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

im res/values-v21/styles.xml

Löwe
quelle
0

auf den Punkt:

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

Stellen Sie sicher, dass Sie die richtige Symbolleiste importieren - android.support.v7.widget.Toolbar;

Salman Anjum
quelle
0

Schreiben Sie diese beiden Zeilen zusätzlich mit Ihrem Code

Toolbar toolbar=(Toolbar)viewActionBar.getParent();
toolbar.setContentInsetsAbsolute(0,0);
Anisuzzaman Babla
quelle