NavigationView Header-Layout abrufen / finden

171

In meiner Navigationsansicht habe ich ein Header-Layout mit der ID 'viewId' mit aktiven Schaltflächen. Um diese Schaltflächen einzurichten, gehe ich in den Aktivitäten wie folgt vor onPostCreate:

final View panel = findViewById(R.id.viewId);
panel.setOnClickListener(new View.OnClickListener() {
... setup goes here ...
});

Mit der Android-Unterstützungsbibliothek der neuen Version ( 23.1.0 ) kann die Ansicht nicht gefunden werden und gibt null zurück. Mit früheren Versionen hat es gut funktioniert. Ist es ein Fehler oder verwende ich diese Funktion falsch? Wenn ja, wie kann man auf das Header-Layout zugreifen und ihm Verhalten hinzufügen?

khusrav
quelle

Antworten:

429

In Version 23.1.0 NavigationViewwird ein RecyclerView(anstelle des vorherigen ListView) verwendet, und der Header wird als eines dieser Elemente hinzugefügt. Dies bedeutet, dass es nicht sofort zum Anrufen verfügbar ist findViewById()- ein Layout-Pass ist erforderlich, bevor er an das angehängt wird NavigationView.

Für Version 23.1.1 der Support-Bibliothek können Sie jetzt einen Verweis auf die Header-Ansicht abrufen , indem Sie getHeaderView():

View headerLayout = navigationView.getHeaderView(0); // 0-index header

Dies hat den Vorteil, dass Header bearbeitet werden, die über XML und Code hinzugefügt wurden.

Wenn Sie gemäß dem zugehörigen Fehler immer noch 23.1.0 verwenden, können Sie den Header im Code aufblasen und Folgendes verwenden findViewById():

View headerLayout = 
    navigationView.inflateHeaderView(R.layout.navigation_header);
panel = headerLayout.findViewById(R.id.viewId);
// panel won't be null

Bis Sie zu 23.1.1 wechseln.

ianhanniballake
quelle
1
Vielen Dank für die schnelle Hilfe, wird die Problemumgehung verwenden. Die dedizierte Methode scheint der richtige Weg zu sein, die Hoffnung wird es in zukünftigen Versionen geben.
Khusrav
2
@ AlexanderFarber - der Code, den ich gepostet habe, funktioniert zurück zu API 7
ianhanniballake
4
Ich ziehe es vor, Bibliotheken herunterzustufen. Das Einführen eines Fehlers ist wie eine Signatur von Google. Wenn die neue Version einen Fehler hat, hat Google diese neue Version veröffentlicht
BamsBamx
1
@GFPF - Wenn Sie aufrufen inflateHeaderView, wird die Ansicht für Sie in der richtigen Ebene RecyclerViewmit dem richtigen übergeordneten Element angehängt - etwas, das Sie extern nicht tun können NavigationView.
Ianhanniballake
1
@RmK - danke, ich habe aktualisiert, um die neuen APIs zu berücksichtigen, die in 23.1.1 hinzugefügt wurden, um über XML hinzugefügte Header abzurufen (da die vorherige Problemumgehung nur mit über Code hinzugefügten Headern funktioniert hat).
Ianhanniballake
142

Mit der Version 23.1.1 der Design-Support-Bibliothek können Sie jetzt verwenden

NavigationView navigationView = (NavigationView) findViewById(R.id.your_nav_view_id);
View header = navigationView.getHeaderView(0)
TextView text = (TextView) header.findViewById(R.id.textView);
Francois Dermu
quelle
Sie können auch verwenden, navigationView.getHeaderCount()wenn Sie aus irgendeinem Grund mehr als einen Header haben.
Francois Dermu
13

So habe ich es gemacht ButterKnifeund es funktioniert für mich.

protected static class HeaderViewHolder {

    @BindView(R.id.button)
    Button button;

    HeaderViewHolder(View view) {
        ButterKnife.bind(this, view);
    }
}

und verwenden Sie dann diesen Ansichtshalter wie folgt:

View header = navigationView.getHeaderView(0);
headerViewHolder = new HeaderViewHolder(header);
Wahib Ul Haq
quelle
2
Dies ist perfekt, wenn Sie die View-bezogene Logik aus Ihrer Aktivität entfernen möchten. Großartige Idee!
Amouly
2
Es funktioniert perfekt mit ButterKnife, danke Bruder.
Rajesh Naddy
8

Für mich war das die gleiche Situation mit 23.1.0, nach dem Update wird die Nullzeiger-Ausnahme. In diesem Fall NavigatorViewsieht das so aus:

<android.support.design.widget.NavigationView
  android:id="@+id/navigation_view"
  android:layout_height="match_parent"
  android:layout_width="wrap_content"
  android:layout_gravity="start"
  android:fitsSystemWindows="true"
  app:headerLayout="@layout/nav_header"
  app:menu="@menu/menu_nav"/>

Ich habe den Lösungsvorschlag von ianhanniballake ausprobiert, aber er funktioniert nicht. Dann habe ich mit dem Satz aufgeblasen:

LayoutInflater.from(getContext()).inflate(R.layout.nav_header, mNavigationView);

Danach kann ich anhand der ID alle im nav_heardLayout definierten Ansichten finden .

Campino
quelle
3
NavigationView navigationView = findViewById(R.id.your_nav_view);
View header = navigationView.getHeaderView(0);
TextView textUsername = header.findViewById(R.id.textView);
textUsername.setText("you text here ");
Indrit Saveta
quelle
Hallo und willkommen bei Stack Overflow! Bitte fügen Sie einen Text hinzu, der erklärt, wie dies die oben gestellte Frage löst. Vielen Dank!
Jonathan
0

In Kotlin @Francois Dermu Code sei wie

val navigationView : NavigationView = findViewById(R.id.your_nav_view_id);
val header = navigationView.getHeaderView(0)
val textView = header.findViewById<TextView>(R.id.textView)
Alex
quelle
0

Kotlin-Version.

val navView: NavigationView = findViewById(R.id.nav_view)       
// set User Name
val headerView: View = navView.getHeaderView(0)
headerView.txtUserName.text = "User Name Goes here"
Qadir Hussain
quelle