Obtener la instancia actual de Fragment en el visor


210

A continuación se muestra mi código que tiene 3 Fragment classescada uno incrustado con cada una de las 3 pestañas ViewPager. Tengo una opción de menú. Como se muestra en onOptionsItemSelected(), al seleccionar una opción, necesito actualizar el fragmento que está visible actualmente. Para actualizar eso, tengo que llamar a un método que está en la clase de fragmento. ¿Alguien puede sugerir cómo llamar a ese método?

public class MainActivity  extends ActionBarActivity {

     ViewPager ViewPager;
     TabsAdapter TabsAdapter;

     @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            ViewPager = new ViewPager(this);
            ViewPager.setId(R.id.pager);
            setContentView(ViewPager);

            final ActionBar bar = getSupportActionBar();

            bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

            //Attaching the Tabs to the fragment classes and setting the tab title.
            TabsAdapter = new TabsAdapter(this, ViewPager);
            TabsAdapter.addTab(bar.newTab().setText("FragmentClass1"),
                    FragmentClass1.class, null);
            TabsAdapter.addTab(bar.newTab().setText("FragmentClass2"),
              FragmentClass2.class, null);
            TabsAdapter.addTab(bar.newTab().setText("FragmentClass3"),
              FragmentClass3.class, null);


            if (savedInstanceState != null) {
                bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
            }

        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {

            switch (item.getItemId()) {

            case R.id.addText:

           **// Here I need to call the method which exists in the currently visible Fragment class**

                    return true;

            }

            return super.onOptionsItemSelected(item);
        }


     @Override
     protected void onSaveInstanceState(Bundle outState) {
      super.onSaveInstanceState(outState);
            outState.putInt("tab", getSupportActionBar().getSelectedNavigationIndex());

     }

     public static class TabsAdapter extends FragmentPagerAdapter
      implements ActionBar.TabListener, ViewPager.OnPageChangeListener {

      private final Context mContext;
            private final ActionBar mActionBar;
            private final ViewPager mViewPager;
            private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();

            static final class TabInfo {
                private final Class<?> clss;
                private final Bundle args;

                TabInfo(Class<?> _class, Bundle _args) {
                    clss = _class;
                    args = _args;
                }
            }

      public TabsAdapter(ActionBarActivity activity, ViewPager pager) {
       super(activity.getSupportFragmentManager());
                mContext = activity;
                mActionBar = activity.getSupportActionBar();
                mViewPager = pager;
                mViewPager.setAdapter(this);
                mViewPager.setOnPageChangeListener(this);
            }

      public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
                TabInfo info = new TabInfo(clss, args);
                tab.setTag(info);
                tab.setTabListener(this);
                mTabs.add(info);
                mActionBar.addTab(tab);
                notifyDataSetChanged();

            }

      @Override
      public void onPageScrollStateChanged(int state) {
       // TODO Auto-generated method stub

      }

      @Override
      public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
       // TODO Auto-generated method stub

      }

      @Override
      public void onPageSelected(int position) {
       // TODO Auto-generated method stub
       mActionBar.setSelectedNavigationItem(position);
      }

      @Override
      public void onTabReselected(Tab tab, FragmentTransaction ft) {
       // TODO Auto-generated method stub

      }

      @Override
      public void onTabSelected(Tab tab, FragmentTransaction ft) {
       Object tag = tab.getTag();
                for (int i=0; i<mTabs.size(); i++) {
                    if (mTabs.get(i) == tag) {
                        mViewPager.setCurrentItem(i);

                    }
                }

                tabPosition = tab.getPosition();
      }

      @Override
      public void onTabUnselected(Tab tab, FragmentTransaction ft) {
       // TODO Auto-generated method stub

      }

      @Override
      public Fragment getItem(int position) {
       TabInfo info = mTabs.get(position);
                return Fragment.instantiate(mContext, info.clss.getName(), info.args);
      }

      @Override
      public int getCount() {
       return mTabs.size();
      }

     }

    }

Supongamos que a continuación se muestra la clase de fragmento con el método al updateList()que quiero llamar:

 public class FragmentClass1{

    ArrayList<String> originalData;


    @Override
         public View onCreateView(LayoutInflater inflater, ViewGroup container,
           Bundle savedInstanceState) {

          View fragmentView = inflater.inflate(R.layout.frag1, container, false);

          originalData = getOriginalDataFromDB();

          return fragmentView;

         }


    public void updateList(String text)
    {
       originalData.add(text);
       //Here I could do other UI part that need to added
    }
}

¿Qué método de fragmento quieres llamar?
Biraj Zalavadia

@BirajZalavadia Mi propio método definido, que tiene un parámetro y utiliza las variables de instancia de esa clase de fragmentos que ya se han inicializado al crear una vista incluso.
Rick

1
¿Puedes dar el nombre de clase de tus fragmentos que están en el visor?
Biraj Zalavadia


La forma más sencilla de acceder a los fragmentos visibles sería a través de stackoverflow.com/questions/7379165/… , mire las dos respuestas principales.
Luksprog

Respuestas:


205

Al seleccionar una opción, necesito actualizar el fragmento que está visible actualmente.

Una manera simple de hacer esto es usar un truco relacionado con la FragmentPagerAdapterimplementación:

case R.id.addText:
     Fragment page = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":" + ViewPager.getCurrentItem());
     // based on the current position you can then cast the page to the correct 
     // class and call the method:
     if (ViewPager.getCurrentItem() == 0 && page != null) {
          ((FragmentClass1)page).updateList("new item");     
     } 
return true;

Reconsidere su convención de nomenclatura variable, usando como nombre de la variable el nombre de la clase es muy confuso (así que no ViewPager ViewPager, use ViewPager mPagerpor ejemplo).


23
¿Es esa etiqueta de fragmento a prueba de futuro, si la API cambia?
Maarten

77
@Maarten No, es solo un truco común que se ha utilizado desde que apareció el adaptador (y su código fuente estaba disponible), aún no ha cambiado. Si desea algo más confiable, necesitará usar otras opciones, la más notable anulando el instantiateItem()método y obteniendo referencias a los fragmentos adecuados usted mismo.
Luksprog

55
Después de horas de frustración y de consultar las páginas directamente desde el mAdapter.getItem(position), increíble ... Al menos ahora sé que los otros 8512 ensayos no funcionaron. Gracias
Diolor

29
Tenga en cuenta que esto no funciona si usa FragmentStatePagerAdapter en lugar de FragmentPagerAdapter.
Shawn Lauzon

3
@ShawnLauzon El FragmentStatePagerAdapter tiene una implementación diferente, en su caso llama a su método instantiateItem () para obtener los fragmentos visibles.
Luksprog

155
    public class MyPagerAdapter extends FragmentPagerAdapter {
        private Fragment mCurrentFragment;

        public Fragment getCurrentFragment() {
            return mCurrentFragment;
        }
//...    
        @Override
        public void setPrimaryItem(ViewGroup container, int position, Object object) {
            if (getCurrentFragment() != object) {
                mCurrentFragment = ((Fragment) object);
            }
            super.setPrimaryItem(container, position, object);
        }
    }

29
Google debería proporcionar FragmentPageAdapter.getCurrentPrimaryItem () devolviendo mCurrentPrimaryItem.
eugene

1
También utilizo esta técnica. También defino un PagerFragment con métodos onPageSelected/ onPageDeselectedy hago que todos mis fragmentos de buscapersonas lo extiendan. Luego setPrimaryitempuede llamar a estos métodos de manera apropiada cuando el usuario pase a una nueva página. Esto significa que puede implementar una estrategia más perezosa para cargar datos en páginas que ni siquiera se muestran. Sin embargo, debe tener en cuenta que durante la transición de la página se ve mejor si la página siguiente ya está llena de datos, por lo que la carga diferida de todos los datos onPageSelectedpuede no ser ideal.
JHH

3
¿Por qué la ifdeclaración? Fragment solo llama al equalsmétodo del objeto, que es una comparación superficial. Entonces, ¿por qué no simplemente siempre llamar mCurrentFragment = ((Fragment) object);?
Overclover

intentado y funciona bien, solo lanza el getCurrentFragment () al Fragmento específico que debería
PhilipJ

113

En primer lugar, realice un seguimiento de todas las páginas de fragmentos "activos". En este caso, realiza un seguimiento de las páginas de fragmentos en el FragmentStatePagerAdapter, que es utilizado por ViewPager.

@Override
public Fragment getItem(int index) {
    Fragment myFragment = MyFragment.newInstance();
    mPageReferenceMap.put(index, myFragment);
    return myFragment;
}

Para evitar mantener una referencia a las páginas de fragmentos "inactivos", debe implementar el método destroyItem (...) de FragmentStatePagerAdapter:

@Override
public void destroyItem (ViewGroup container, int position, Object object) {
    super.destroyItem(container, position, object);
    mPageReferenceMap.remove(position);
}

y cuando necesite acceder a la página actualmente visible, llame a:

int index = mViewPager.getCurrentItem();
MyAdapter adapter = ((MyAdapter)mViewPager.getAdapter());
MyFragment fragment = adapter.getFragment(index);

Donde el método getFragment (int) de MyAdapter se ve así:

public MyFragment getFragment(int key) {
    return mPageReferenceMap.get(key);
}

Espero que pueda ayudar!


¿Puedes explicarlo claramente? ¿Dónde necesito mantener esta clase FragmentStatePagerAdapter en mi código? Por cierto, tengo 3 clases de fragmentos, no solo MyFragmentClass.
Rick

77
Aún mejor si actualiza mPageReferenceMap en instantiateItem en lugar de getItem porque también funciona después del cambio de orientación. '@Override public Object instantiateItem (ViewGroup container, int position) {Fragment fragment = (Fragment) Super.instantiateItem (container, position); mPageReferenceMap.put (posición, fragmento); fragmento de retorno; } '
pmellaaho

¿De qué tipo es mPageReferenceMap?
DoruAdryan

10
¡Esta respuesta es realmente mala! No debe mantener el caché de un ViewPager manualmente, ya que lo maneja solo. ViewPager decide cuándo se debe asignar o no un fragmento, qué hacer una pausa y cuándo, mantener una referencia en cada fragmento agregará una sobrecarga inútil y no está optimizado para la memoria.
Livio

3
Intenté este enfoque pero desafortunadamente no funciona cuando se recrea la actividad. En Android N y versiones posteriores, puede ver esto cuando usa la función de ventanas múltiples. Cuando su aplicación esté abierta, mantenga presionado el botón 'recientes' (el cuadrado). La actividad y el fragmento se recrean a partir de savedInstanceState, el adaptador se vuelve a crear (por lo que mPageReferenceMap ahora está vacío), pero getItem no se vuelve a llamar. El mapa permanece vacío, por lo que adapter.getFragment (index) se bloqueará.
Martin Konicek

102

Esta es la única forma en que no obtengo NullPointerException para las variables de instancia de esas clases de fragmentos en particular. Esto podría ser útil para otros que se atascaron en lo mismo. En onOptionsItemSelected (), codifiqué la siguiente manera:

if(viewPager.getCurrentItem() == 0) {
    FragmentClass1 frag1 = (FragmentClass1)viewPager
                            .getAdapter()
                            .instantiateItem(viewPager, viewPager.getCurrentItem());
    frag1.updateList(text); 
} else if(viewPager.getCurrentItem() == 1) {
    FragmentClass2 frag2 = (FragRecentApps)viewPager
                            .getAdapter()
                            .instantiateItem(viewPager, viewPager.getCurrentItem());
    frag2.updateList(text);
}

3
Creo que esta es la respuesta más correcta: alinear con el diseño de FragmentStatePagerAdaptersin anular ningún código. De hecho, debería ser tan simple como una función solo regresar viewPager.getAdapter().instantiateItem(viewPager, viewPager.getCurrentItem()).
John Pang

39

FragmentStatePagerAdapter tiene un método público con el nombre instantiateItem que devuelve su fragmento en función de los valores de parámetros especificados, este método tiene dos parámetros ViewGroup (ViewPager) y posición.

public Object instantiateItem(ViewGroup container, int position);

Usó este método para obtener el fragmento de la posición especificada,

Fragment fragment = (Fragment) adaper.instantiateItem(mViewPager, position);

55
Pero esto no devuelve el fragmento actual ya instanciado, sino uno nuevo, ¿no? Así se llama "instanciar" ...
Ixx

1
@Ixx No, no crea un nuevo fragmento. Creo que el nombre del método es incorrecto aquí.
errores suceden el

15

Sé que es demasiado tarde, pero tengo formas muy simples de hacerlo,

// para fragmento en posición 0

((mFragment) viewPager.getAdapter().instantiateItem(viewPager, 0)).yourMethod();

10

Aquí hay muchas respuestas que realmente no abordan el hecho básico de que realmente NO HAY MANERA de hacer esto de manera predecible, y de una manera que no resulte en que te dispares en el pie en algún momento en el futuro.

FragmentStatePagerAdapteres la única clase que sabe cómo acceder de manera confiable a los fragmentos que son rastreados por FragmentManager- cualquier intento de tratar de adivinar la identificación o etiqueta del fragmento no es confiable a largo plazo. Y los intentos de rastrear las instancias manualmente probablemente no funcionarán bien cuando se guarde / restaure el estado, ya que es FragmentStatePagerAdapterposible que no se invoquen las devoluciones de llamada cuando se restaura el estado.

Casi lo único que he podido hacer es copiar el código FragmentStatePagerAdaptery agregar un método que devuelve el fragmento, dada una posición ( mFragments.get(pos)). Tenga en cuenta que este método supone que el fragmento está realmente disponible (es decir, era visible en algún momento).

Si eres particularmente aventurero, puedes usar la reflexión para acceder a los elementos de la mFragmentslista privada , pero luego volvemos al punto de partida (no se garantiza que el nombre de la lista permanezca igual).


1
para tratar con "no funciona bien cuando el estado se guarda / restaura", anulo el método saveState (). Para que el localizador no guarde ningún fragmento cuando la actividad está en pausa. funciona.
AntoineP

2
Eso solo se suma al mosaico, sin solucionar el problema subyacente. No estoy argumentando que no funciona, solo que no es una buena implementación.
Melllvar

8
getSupportFragmentManager().getFragments().get(viewPager.getCurrentItem());

Transmita la instancia recuperada de la línea anterior al fragmento con el que desea trabajar. Funciona perfectamente bien.

viewPager

es la instancia del localizador que gestiona los fragmentos.


Esto solo funciona si todas las páginas se cargan como Fragmento. Cuando hay, por ejemplo, un tablayout con muchas pestañas / páginas, no todas se cargan, por lo que esto podría generar una excepción indexoutofbounce.
progNewbie

@progNewbie sí, eso necesitará un código de solución adicional.
Gaurav Pangam

La respuesta de @progNewbie Evgeny a continuación manejaría esa situación, creo
Gaurav Pangam

7

Al seleccionar una opción, necesito actualizar el fragmento que está visible actualmente.

Para obtener una referencia al fragmento visible actualmente, suponga que tiene una referencia a ViewPageras mPager. Luego, los siguientes pasos obtendrán una referencia a currentFragment:

  1. PageAdapter adapter = mPager.getAdapter();
  2. int fragmentIndex = mPager.getCurrentItem();
  3. FragmentStatePagerAdapter fspa = (FragmentStatePagerAdapter)adapter;
  4. Fragment currentFragment = fspa.getItem(fragmentIndex);

El único elenco utilizado en la línea 3 suele ser válido. FragmentStatePagerAdapteres un adaptador útil para un ViewPager.


7

La mejor manera de hacerlo es simplemente llamar a CallingFragmentName fragment = (CallingFragmentName) viewPager .getAdapter () .instantiateItem (viewPager, viewPager.getCurrentItem ()); Volverá a crear una instancia de su Fragmento de llamada, de modo que no arrojará una excepción de puntero nulo y llamará a cualquier método de ese fragmento.


6

Fragmento actual:

Esto funciona si creó un proyecto con la plantilla de la barra de pestañas Fragmentos.

Fragment f = mSectionsPagerAdapter.getItem(mViewPager.getCurrentItem());

Tenga en cuenta que esto funciona con la implementación de plantilla de actividad con pestañas predeterminada.


30
Esto depende de su implementación de getItem (): puede devolver una nueva instancia del fragmento, que probablemente no sea lo que desea.
Tom

Así es como lo haces. si todavía tiene la configuración predeterminada cuando crea un proyecto tabor con fragmentos. ninguno tenía esta solución. así que pensé que ayudaría
hasan

3

He usado lo siguiente:

 int index = vpPager.getCurrentItem();
 MyPagerAdapter adapter = ((MyPagerAdapter)vpPager.getAdapter());
 MyFragment suraVersesFragment = (MyFragment)adapter.getRegisteredFragment(index);

1
Esto se basa en una implementación de buscapersonas personalizada de la respuesta que se encuentra aquí: stackoverflow.com/questions/8785221/…
Tom Redman

1
Esto es exactamente lo que estaba tratando de hacer, pero sin saber qué métodos anular, habría desperdiciado horas, ¡gracias!
Bron Davies

2

FragmentStatePagerAdaptertiene una variable de instancia privada llamada mCurrentPrimaryItemde tipo Fragment. Uno solo puede preguntarse por qué los desarrolladores de Android no le proporcionaron un getter. Esta variable se instancia en el setPrimaryItem()método. Por lo tanto, anule este método de tal manera que obtenga la referencia a esta variable. Simplemente terminé declarando el mío mCurrentPrimaryItemy copiando el contenido de setPrimaryItem()mi anulación.

En su implementación de FragmentStatePagerAdapter:

private Fragment mCurrentPrimaryItem = null;

@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
    Fragment fragment = (Fragment)object;
    if (fragment != mCurrentPrimaryItem) {
        if (mCurrentPrimaryItem != null) {
            mCurrentPrimaryItem.setMenuVisibility(false);
            mCurrentPrimaryItem.setUserVisibleHint(false);
        }
        if (fragment != null) {
            fragment.setMenuVisibility(true);
            fragment.setUserVisibleHint(true);
        }
        mCurrentPrimaryItem = fragment;
    }
}

public TasksListFragment getCurrentFragment() {
    return (YourFragment) mCurrentPrimaryItem;
}

2

Se puede definir el PagerAdaptercomo esto, entonces usted será capaz de obtener ninguna Fragmenten ViewPager.

private class PagerAdapter extends FragmentPagerAdapter {
    private final List<Fragment> mFragmentList = new ArrayList<>();

    public PagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

    @Override
    public int getCount() {
        return mFragmentList.size();
    }

    public void addFragment(Fragment fragment) {
        mFragmentList.add(fragment);
    }
}

Para obtener la corriente Fragment

Fragment currentFragment = mPagerAdapter.getItem(mViewPager.getCurrentItem());

2

Cuando usamos viewPager, una buena forma de acceder a la instancia de fragmento en actividad es instantiateItem (viewpager, index). // index- index of fragment del cual quieres instancia.

por ejemplo, estoy accediendo a la instancia de fragmento de 1 index-

Fragment fragment = (Fragment) viewPageradapter.instantiateItem(viewPager, 1);

if (fragment != null && fragment instanceof MyFragment) {      
 ((MyFragment) fragment).callYourFunction();

}

2

En mi implementación anterior, almacené una lista de Fragmentos secundarios para poder acceder a ellos más tarde, pero resultó ser una implementación incorrecta que causó grandes pérdidas de memoria.

Termino usando el instantiateItem(...)método para obtener el Fragmento actual:

val currentFragment = adapter?.instantiateItem(viewPager, viewPager.currentItem)

O para obtener cualquier otro Fragmento en posición:

val position = 0
val myFirstFragment: MyFragment? = (adapter?.instantiateItem(viewPager, position) as? MyFragment)

De la documentación :

Crea la página para el puesto dado. El adaptador es responsable de agregar la vista al contenedor que se proporciona aquí, aunque solo debe asegurarse de que esto se haga cuando regrese de finishUpdate (ViewGroup).


Corto y limpio, gracias
JimmyFlash

1

Tuve el mismo problema y lo resolví usando este código.

MyFragment fragment = (MyFragment) thisActivity.getFragmentManager().findFragmentById(R.id.container);

Simplemente reemplace el nombre MyFragment con el nombre de su fragmento y agregue la identificación de su contenedor de fragmentos.


1

Esto es más a prueba de futuro que la respuesta aceptada:

public class MyFragmentPagerAdapter extends FragmentPagerAdapter {

    /* ------------------------------------------------------------------------------------------ */
    // region Private attributes :

    private Context _context;
    private FragmentManager _fragmentManager;
    private Map<Integer, String> _fragmentsTags = new HashMap<>();

    // endregion
    /* ------------------------------------------------------------------------------------------ */



    /* ------------------------------------------------------------------------------------------ */
    // region Constructor :

    public MyFragmentPagerAdapter(Context context, FragmentManager fragmentManager) {

        super(fragmentManager);

        _context = context;
        _fragmentManager = fragmentManager;
    }

    // endregion
    /* ------------------------------------------------------------------------------------------ */



    /* ------------------------------------------------------------------------------------------ */
    // region FragmentPagerAdapter methods :

    @Override
    public int getCount() { return 2; }

    @Override
    public Fragment getItem(int position) {

        if(_fragmentsTags.containsKey(position)) {

            return _fragmentManager.findFragmentByTag(_fragmentsTags.get(position));
        }
        else {

            switch (position) {

                case 0 : { return Fragment.instantiate(_context, Tab1Fragment.class.getName()); }
                case 1 : { return Fragment.instantiate(_context, Tab2Fragment.class.getName()); }
            }
        }

        return null;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {

        // Instantiate the fragment and get its tag :
        Fragment result = (Fragment) super.instantiateItem(container, position);
        _fragmentsTags.put(position, result.getTag());

        return result;
    }

    // endregion
    /* ------------------------------------------------------------------------------------------ */
}

Deberías usar WeakHashMap en su lugar.
Prakash Nadar

1

El escenario en cuestión es mejor atendido por cada Fragmento agregando sus propios elementos de menú y manejando directamente onOptionsItemSelected (), como se describe en la documentación oficial . Es mejor evitar los trucos indocumentados.


Esta respuesta podría usar más detalles sobre cómo hacerlo realmente. ¿Cómo resuelve el ViewPagerproblema agregar un elemento de menú ?
Suragch

El problema de @Suragch ViewPager existe si los eventos del menú se manejan dentro de la Actividad que aloja fragmentos y no existe si los eventos se manejan dentro del propio fragmento. El enlace muestra cómo un fragmento puede agregar sus propios elementos de menú.
Y2i

1

Después de leer todos los comentarios y respuestas, voy a explicar una solución óptima para este problema. La mejor opción es la solución de @ rik, por lo que mi mejora se basa en la suya.

En lugar de tener que preguntar a cada FragmentClass como

if(FragmentClass1){
   ...
if(FragmentClass2){
   ...
}

Cree su propia interfaz y haga que los fragmentos de su hijo la implementen, algo así como

public interface MyChildFragment {
    void updateView(int position);
}

Luego, puede hacer algo como esto para iniciar y actualizar sus fragmentos internos.

Fragment childFragment = (Fragment) mViewPagerDetailsAdapter.instantiateItem(mViewPager,mViewPager.getCurrentItem());

if (childFragment != null) {
   ((MyChildFragment) childFragment).updateView();
}

PD Tenga cuidado donde coloca ese código, si llama a insatiateItem antes de que el sistema realmente lo cree, el savedInstanceStatefragmento de su hijo será nulo para ello

public void onCreate(@Nullable Bundle savedInstanceState){
      super(savedInstanceState)
}

Bloqueará tu aplicación.

Buena suerte


1

Basado en lo que respondió @chahat jain:

"Cuando usamos viewPager, una buena forma de acceder a la instancia de fragmento en actividad es instantiateItem (viewpager, index). // index- index of fragment of cuya instancia desea".

Si quieres hacer eso en Kotlin

val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 0) as Fragment
                if ( fragment is YourFragmentFragment)
                 {
                    //DO somthign 
                 }

0 a la instancia de fragmento de 0

// ================================================ ========================= // // ##################### ######## Ejemplo de usos ################################# // // == ================================================== ===================== //

Aquí hay un ejemplo completo para obtener una visión más perdida sobre

aquí está mi veiewPager en el archivo .xml

   ...
    <android.support.v4.view.ViewPager
                android:id="@+id/mv_viewpager"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_margin="5dp"/>
    ...

Y la actividad de casa donde inserto la pestaña

...
import kotlinx.android.synthetic.main.movie_tab.*

class HomeActivity : AppCompatActivity() {

    lateinit var  adapter:HomeTabPagerAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
       ...
    }



    override fun onCreateOptionsMenu(menu: Menu) :Boolean{
            ...

        mSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
          ...

            override fun onQueryTextChange(newText: String): Boolean {

                if (mv_viewpager.currentItem  ==0)
                {
                    val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 0) as Fragment
                    if ( fragment is ListMoviesFragment)
                        fragment.onQueryTextChange(newText)
                }
                else
                {
                    val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 1) as Fragment
                    if ( fragment is ListShowFragment)
                        fragment.onQueryTextChange(newText)
                }
                return true
            }
        })
        return super.onCreateOptionsMenu(menu)
    }
        ...

}

0

En mi actividad tengo:

int currentPage = 0;//start at the first tab
private SparseArray<Fragment> fragments;//list off fragments
viewPager.setOnPageChangeListener(new OnPageChangeListener() {

@Override
public void onPageSelected(int pos) {
        currentPage = pos;//update current page
}

@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {}
@Override
public void onPageScrollStateChanged(int arg0) {}
});



@Override
public void onAttachFragment(Fragment fragment) {
    super.onAttachFragment(fragment);
    if(fragment instanceof Fragment1)
        fragments.put(0, fragment);
    if(fragment instanceof Fragment2)
        fragments.put(2, fragment);
    if(fragment instanceof Fragment3)
        fragments.put(3, fragment);
    if(fragment instanceof Fragment4)
        fragments.put(4, fragment);
}

Then I have the following method for getting the current fragment

public Fragment getCurrentFragment() {
    return fragments.get(currentPage);
}

0
final ViewPager.OnPageChangeListener onPageChangeListener =
    new ViewPager.OnPageChangeListener() {
      @Override public void onPageSelected(int position) {
        switch (position) {
          case 0:
            FragmentClass1 frag1 =
                (FragmentClass1) viewPager.getAdapter()
                    .instantiateItem(viewPager, viewPager.getCurrentItem());
            frag1.updateList("Custom text");
            break;
          case 1:
            break;
          case 2:
            break;
        }
      }

      @Override
      public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

      }

      @Override public void onPageScrollStateChanged(int state) {
      }
    };


 viewPager.addOnPageChangeListener(onPageChangeListener);

viewPager.setAdapter(adapter);


viewPager.post(new Runnable() {
  @Override public void run() {
    onPageChangeListener.onPageSelected(viewPager.getCurrentItem());
  }
});

A veces, el fragmento puede enviar un objeto nulo, por lo que puede ejecutar un nuevo Runnable para resolver el problema en la primera carga.

Gracias rick


Agregue un texto que explique por qué este código resolvería el problema del OP. Además, dada la cantidad de otras respuestas que existen, explique por qué esta respuesta es mejor que las que ya se dieron. Ayuda a otros a entender.
APC

0

Anule setPrimaryItem de su FragmentPagerAdapter: el objeto es el fragmento visible:

 @Override
        public void setPrimaryItem(ViewGroup container, int position, Object object) {
            if (mCurrentFragment != object) {
                mCurrentFragment = (LeggiCapitoloFragment) object;
            }
            super.setPrimaryItem(container, position, object);
        }

0

Simplemente obtenga el elemento actual del buscapersonas y luego solicite a su adaptador el fragmento de esa posición.

 int currentItem = viewPager.getCurrentItem();
    Fragment item = mPagerAdapter.getItem(currentItem);
    if (null != item && item.isVisible()) {
       //do whatever want to do with fragment after doing type checking
        return;
    }

3
¿Qué pasa si getItemcrea una nueva instancia
Prakash Nadar

0

Para obtener el fragmento actual: obtenga una posición en ViewPager en public void onPageSelected (posición int final) , y luego

public PlaceholderFragment getFragmentByPosition(Integer pos){
    for(Fragment f:getChildFragmentManager().getFragments()){
        if(f.getId()==R.viewpager && f.getArguments().getInt("SECTNUM") - 1 == pos) {
            return (PlaceholderFragment) f;
        }
    }
    return null;
}

SECTNUM: argumento de posición asignado en el marcador de posición estático público newInstance (int sectionNumber); de fragmento

getChildFragmentManager () o getFragmentManager () - depende de cómo se creó SectionsPagerAdapter


0

Puede implementar un BroadcastReceiver en el Fragmento y enviar una intención desde cualquier lugar. El receptor del fragmento puede escuchar la acción específica e invocar el método de la instancia.

Una advertencia es asegurarse de que el componente Ver ya esté instanciado y (y para algunas operaciones, como desplazar una lista, ListView ya debe estar renderizado).


0

Este es el truco más simple:

fun getCurrentFragment(): Fragment? {
    return if (count == 0) null
    else instantiateItem(view_pager, view_pager.currentItem) as? Fragment
}

(código kotlin)

Solo llame instantiateItem(viewPager, viewPager.getCurrentItem()y envíelo Fragment. Su artículo ya estaría instanciado. Para asegurarse de que puede agregar un cheque para getCount.

Funciona con ambos FragmentPagerAdaptery FragmentStatePagerAdapter!


0

Si su buscapersonas está dentro de un Fragmento, use esto:

private fun getPagerCurrentFragment(): Fragment? {
    return childFragmentManager.findFragmentByTag("android:switcher:${R.id.myViewPagerId}:${myViewPager.currentItem}")
}

¿Dónde R.id.myViewPagerIdestá la identificación de su ViewPager dentro del diseño xml?


Esto solo funciona con FragmentPageAdapter normal y no con FragmentStatePageAdapter.
progNewbie

0

Puede declarar una matriz de fragmentos como fragmentos de registro

class DashboardPagerAdapter(fm: FragmentManager?) : FragmentStatePagerAdapter(fm!!) {
    // CURRENT FRAGMENT
    val registeredFragments = SparseArray<Fragment>()

    override fun instantiateItem(container: ViewGroup, position: Int): Any {
        val fragment = super.instantiateItem(container, position) as Fragment
        registeredFragments.put(position, fragment)
        return fragment
    }

    override fun getItem(position: Int): Fragment {
        return when (position) {
            0 -> HomeFragment.newInstance()
            1 -> ConverterDashboardFragment.newInstance()
            2 -> CartFragment.newInstance()
            3 -> CustomerSupportFragment.newInstance()
            4 -> ProfileFragment.newInstance()
            else -> ProfileFragment.newInstance()
        }
    }

    override fun getCount(): Int {
        return 5
    }

}

Entonces puedes usarlo como

adapter?.let {
    val cartFragment = it.registeredFragments[2] as CartFragment?
    cartFragment?.myCartApi(true)
}

Si decide ir por ese camino, también debe implementar destroyItem () y eliminar la instancia destruida de los fragmentos registrados, de lo contrario, tendrá una pérdida de memoria.
dephinera

Eso es un buen consejo. Puede hacer una edición en la respuesta.
Hamza Khan

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.