Android ViewPager erhält die aktuelle Ansicht


74

Ich habe einen ViewPager und möchte die aktuell ausgewählte und sichtbare Ansicht erhalten, keine Position.

  1. getChildAt(getCurrentItem) gibt falsch zurück View
  2. Dies funktioniert nicht immer. Manchmal wird null zurückgegeben, manchmal wird nur die falsche Ansicht zurückgegeben.

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
    
        if (isVisibleToUser == true) { 
            mFocusedListView = ListView; 
        }
    }
    
  3. PageListener auf ViewPagermit getChildAt()auch nicht funktioniert, nicht mir die richtige Ansicht zu geben , jedes Mal.

Wie kann ich die aktuell sichtbare Ansicht erhalten?

View view = MyActivity.mViewPager.getChildAt(MyActivity.mViewPager.getCurrentItem()).getRootView();
ListView listview = (ListView) view.findViewById(R.id.ListViewItems);

Antworten:


132

Ich habe es herausgefunden. Was ich getan habe, war, setTag()alle Views / ListViews mit einem Namen anzurufen und einfach anzurufen findViewWithTag(mytag), mytagum das Tag zu sein.

Leider gibt es keinen anderen Weg, dies zu lösen.


1
Das gibt mir einen Hinweis. Vielen Dank!
Rahstame

7
Ich kann nicht glauben, dass dies die beste Option ist, aber es funktioniert. Ich setze nur den Index als Tag, wenn der Adapter das Element erstellt.
Respektieren Sie den Code

13
+1 zur Absurdität dieser Lösung, aber es ist definitiv die beste. Die eleganteste Form dieses Hacks ist die Verwendung der Position als Tag in PagerAdapter.instantiateView und das Abrufen der Ansicht mit findViewBy (getCurrentItem ()).
Nathanielwolf

ein weiteres +1 @lacas für das Finden dieser Lösung
Addi

3
Bitte sagen Sie mir, dass es fast sechs Jahre später einen besseren Weg gibt!?
Graphentheorie

9

Ich bin gerade auf dasselbe Problem gestoßen und habe es gelöst, indem ich Folgendes verwendet habe:

View view = MyActivity.mViewPager.getFocusedChild();

5
Dies funktioniert nicht immer, manchmal liegt der Fokus an einer anderen Stelle, obwohl gerade eine Ansicht von ViewPager angezeigt wird
Pimp Trizkit

Das mag sein, funktioniert aber, wenn Sie den Fokus auf die Seite anfordern, die sichtbar wird
ZeCodea

1
Es sei denn, ich missverstehe hier etwas. Was meinst du konkret mit "Request Focus"? Denn wenn ich es mViewPager.getChildAt(i).isFocused()für alle Kinder tue , berichtet es falsefür alle Kinder. Das liegt wahrscheinlich daran, dass ich diesen Code in das Optionsmenü einfüge, das Teil der MainActivity ist, wodurch der Fokus vom ViewPager verschoben wird. Daher funktioniert dieser Weg in bestimmten Situationen nicht.
Pimp Trizkit

Ja, dies kann ein Dialogfeld oder ein Toastobjekt sein. Verwenden Sie stattdessen die Methode isVisible ()
CodeToLife

Scheint nicht für AndroidX ViewPager 1.0.0 / Support-Bibliothek ViewPager 28.0.0
Tim Kist

7

Sie können das aktuelle Element abrufen, indem myAdapter.yourListItens.get(myViewPager.getCurrentItem()); Sie von Ihrem Adapter aus auf Ihre Liste der Elemente zugreifen. Wie Sie sehen, kann ViewPager den aktuellen Index des Elements Ihres Adapters abrufen (aktuelle Seite).

Wenn Sie FragmentPagerAdapter verwenden, können Sie folgende Umwandlung durchführen:

FragmentPagerAdapter adapter = (FragmentPagerAdapter)myViewPager.getAdapter();

und Ruf an

adapter.getItem(myViewPager.getCurrentItem());

Das funktioniert sehr gut für mich;)


2
Funktioniert nur, wenn Ihr Adapter FragmentPagerAdapter
Boris Strandjev

22
Beachten Sie, dass getItem()beim Unterklassen immer eine neue Instanz eines Fragments zurückgegeben werden soll Fragment(State)PagerAdapter. Daher ist dies nicht richtig, da nur eine neue Instanz erstellt wird, anstatt die "alte" zurückzugeben.
ComFreek

Der obige Kommentar ist falsch. Direkt aus den Dokumenten: "Geben Sie das Fragment zurück, das einer bestimmten Position zugeordnet ist." Sagt nichts über die Rückgabe eines neuen Fragments.
arbeitete

2
Ihre Antwort gibt das Fragment zurück, aber für mich ist das Fragment leer. adapter.getItem (myViewPager.getCurrentItem ()). getView () gibt null zurück.
arbeitete

7

Ich benutze diese Methode mit android.support.v4.view.ViewPager

View getCurrentView(ViewPager viewPager) {
        try {
            final int currentItem = viewPager.getCurrentItem();
            for (int i = 0; i < viewPager.getChildCount(); i++) {
                final View child = viewPager.getChildAt(i);
                final ViewPager.LayoutParams layoutParams = (ViewPager.LayoutParams) child.getLayoutParams();

                Field f = layoutParams.getClass().getDeclaredField("position"); //NoSuchFieldException
                f.setAccessible(true);
                int position = (Integer) f.get(layoutParams); //IllegalAccessException

                if (!layoutParams.isDecor && currentItem == position) {
                    return child;
                }
            }
        } catch (NoSuchFieldException e) {
            Log.e(TAG, e.toString());
        } catch (IllegalArgumentException e) {
            Log.e(TAG, e.toString());
        } catch (IllegalAccessException e) {
            Log.e(TAG, e.toString());
        }
        return null;
    }

Ich danke dir sehr. Es ist genau das, was ich will
Erfan Eghterafi

2

Während meiner Bemühungen, einen Weg zu finden, um Android-Ansichten zu dekorieren, habe ich eine alternative Lösung für das OP-Problem definiert, das ich in meinem Blog dokumentiert habe . Ich verlinke darauf, da der Code ein bisschen zu viel zu sein scheint, um hier alles aufzunehmen.

Die Lösung, die ich vorschlage:

  • hält den Adapter und die Ansicht vollständig getrennt
  • Man kann leicht eine Ansicht mit einem beliebigen Index aus dem Ansichtspager abfragen, und er wird entweder zurückgegeben, nullwenn diese Ansicht derzeit nicht geladen ist, oder der entsprechenden Ansicht.

2

Ich verwende ViewPagerUtils von FabulousFilter :

ViewPagerUtils.getCurrentView(ViewPager viewPager)

Ich verwende diese Methode und kann bestätigen, dass sie funktioniert.
Aleksandar Acić

Dies ist nicht Teil des Core Android SDK. Sie verwenden wahrscheinlich eine Bibliothek eines Drittanbieters. Das ist wahrscheinlich der Grund, warum Sie abgelehnt wurden.
Aeskreis

1
Verwenden Sie diese Bibliothek? github.com/Krupen/FabulousFilter . Diese Bibliothek verfügt über eine ViewPagerUtils-Methode. Es verwendet den Namespace android.support.v4, der sehr verdächtig ist. Sie sollten NIEMALS Android-Namespaces für Ihre Klassen verwenden, da dies zu Verwirrung führen kann (dies ist ein perfektes Beispiel für solche Verwirrung). Es scheint, dass der Autor dies getan hat, um auf paketgeschützte Felder zuzugreifen, was wiederum eine schreckliche Code-Praxis ist. Ich würde diese Methode nicht empfehlen.
Aeskreis

Ich schrieb in der Antwort, dass es die Android Support Library v4 ist. developer.android.com/topic/libraries/support-library
Aleksandar Acić

Der ViewPager ist Teil der Support-Bibliothek, sodass keine zusätzlichen Abhängigkeiten hinzugefügt werden müssen.
Aleksandar Acić

2

Verwenden Sie einen Adapter, der PagerAdapter erweitert, und überschreiben Sie die setPrimaryItem-Methode in Ihrem PagerAdapter.

https://developer.android.com/reference/android/support/v4/view/PagerAdapter.html

class yourPagerAdapter extends PagerAdapter
{
    // .......

    @Override
    public void setPrimaryItem (ViewGroup container, int position, Object object)
    {
        int currentItemOnScreenPosition = position;
        View onScreenView = getChildAt(position);
    }

    // .......

}

2
Beantwortet die ursprüngliche Frage nicht, um die tatsächliche Ansicht zu erhalten. Wenn Sie die Position möchten , können Sie auch getCurrentItem () verwenden .
Tim Kist

Ja. Ich habe vergessen, das zu schreiben, um die Ansicht zu erhalten, die Sie nur verwenden müssen: getChildAt (currentItemOnScreenPosition).
Andrés

Andererseits gibt die Funktion getCurrentItem () nicht die aktuell ausgewählte und sichtbare Ansicht zurück, wie in der ursprünglichen Frage angegeben, gibt getChildAt (getCurrentItem) eine falsche Ansicht zurück. Ich denke, die Funktion getCurrentItem () gibt das Element zurück, das derzeit vom viewPager berechnet wird, und dieses Element ist möglicherweise nicht das gleiche, das derzeit auf dem Bildschirm angezeigt wird
Andrés

1

Versuche dies

 final int position = mViewPager.getCurrentItem();
    Fragment fragment = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.rewards_viewpager + ":"
            + position);

1

Ich musste es allgemeiner machen, also entschied ich mich, die private 'Position' von ViewPager.LayoutParams zu verwenden

        final int childCount = viewPager.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = viewPager.getChildAt(i);
            final ViewPager.LayoutParams lp = (ViewPager.LayoutParams) child.getLayoutParams();
            int position = 0;
            try {
                Field f = lp.getClass().getDeclaredField("position");
                f.setAccessible(true);
                position = f.getInt(lp); //IllegalAccessException
            } catch (NoSuchFieldException | IllegalAccessException ex) {ex.printStackTrace();}
            if (position == viewPager.getCurrentItem()) {
                viewToDraw = child;
            }
        }

1

Wenn Sie nicht viele Seiten haben und sicher anwenden können, setOffscreenPageLimit(N-1) wobei N die Gesamtzahl der Seiten ist, ohne zu viel Speicher zu verschwenden, können Sie Folgendes tun:

public Object instantiateItem(final ViewGroup container, final int position) {      
    CustomHomeView RL = new CustomHomeView(context);
    if (position==0){
        container.setId(R.id.home_container);} ...rest of code

Dann ist hier Code, um auf Ihre Seite zuzugreifen

((ViewGroup)pager.findViewById(R.id.home_container)).getChildAt(pager.getCurrentItem()).setBackgroundColor(Color.BLUE);

Wenn Sie möchten, können Sie eine Methode für den Zugriff auf eine Seite einrichten

RelativeLayout getPageAt(int index){
    RelativeLayout rl =  ((RelativeLayout)((ViewGroup)pager.findViewById(R.id.home_container)).getChildAt(index));
    return rl;
}

2
getChildAt(pager.getCurrentItem())macht nicht was du willst Zum Beispiel kann ViewPager 1000 Seiten haben, aber nur 5 Kinder, sodass Sie keine Grenzen mehr haben, wenn das aktuelle Element die letzte Seite ist.
Fdermishin

@fdermishin Dies ist wahr, es sei denn, Sie haben die Option 'setOffscreenPageLimit (N-1)', wobei N die Anzahl der Seiten ist. Dies wird jedoch nicht empfohlen, wenn Sie viele Seiten haben, da dies eine unnötige Speicherverschwendung sein kann
Michael Kern

0

Ist das Ihre erste Aktivität auf dem Bildschirm oder haben Sie bereits einige übereinander gelegt?

Versuche dies:

findViewById(android.R.id.content).getRootView()

oder nur:

findViewById(android.R.id.content) 

auch je nachdem was du willst versuchen:

((ViewGroup)findViewById(android.R.id.content)).getChildAt(0)

erste twoo gib mir nur die TAB 0 Artikel, die ganze Zeit, und den dritten Code geben Sie mir eine null
Lacas

versuchte das? this.findViewById (android.R.id.content) .getRootView () Vielleicht sollten Sie weitere Informationen zu Ihren Aktivitäten und zum Aufbau und Wechsel zwischen ihnen geben.
SunnySonic

Keiner dieser Vorschläge wird funktionieren. Die dritte Seite erhält eine Seite im Pager, jedoch nicht die mittlere Ansicht, sondern eine Seite links, und das OP wollte die zentrierte / aktuelle Seite.
Tim Kist

0

Sie können das Fragment nach System-Tag finden. Es ist Arbeit für mich. Ich habe es in OnMeasureFunktion verwendet.

id - viewPager ID

position - Fragment, das Sie erhalten möchten

Wichtig! Sie erhalten dieses Fragment, wenn Ihr Fragment im Adapter erstellt wurde. Sie müssen also nullify supportedFragmentManager.findFragmentByTag("android:switcher:" + id + ":" + position)aktivieren

Sie können Ansicht wie folgt erhalten:

supportedFragmentManager.findFragmentByTag("android:switcher:" + id + ":" + position).view

Sie sollten im Adapter kein benutzerdefiniertes Tag angeben


0
viewpager.getChildAt(0)

Dies gibt immer meine aktuell ausgewählte Ansicht zurück. Das hat bei mir funktioniert, aber ich weiß nicht wie.


-3

Bei sorgfältiger Prüfung werden von ViewPager höchstens 3 Ansichten gespeichert. Sie können die aktuelle Ansicht ganz einfach über abrufen

view     = MyActivity.mViewPager.getChildAt(1);

1
Das funktioniert nicht. Was ist, wenn der Viewpager seine erste oder letzte Seite anzeigt? Was ist, wenn es mehr als eine Offscreen-Seite gibt?
foo64

1
False, Sie können ViewPager so einstellen, dass mehr als 3 Ansichten mitsetOffscreenPageLimit(int)
zyamys

-3

Bitte prüfen Sie das

((ViewGroup))mViewPager.getChildAt(MyActivity.mViewPager.getCurrentItem()));

Andernfalls überprüfen Sie diesen Link .


funktioniert nicht, dies bekommt nicht die Ansicht, die traurig sichtbar ist, und manchmal bekommen null
lacas

3
Das funktioniert nicht. Der Bereich von getChildAt()unterscheidet sich vom Bereich von getCurrentItem(). Wenn Ihr ViewPager beispielsweise 20 Elemente und 1 Offscreen-Seite anzeigt getChildAt(), beträgt der Bereich 0-2, während getCurrentItem()der Bereich 0-19 beträgt. Sie würden meistens Null-Rückgabewerte erhalten.
foo64
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.