Navegación anterior separada para un buscador de vistas con pestañas en Android
Lo que quiero.
En un contexto de menú deslizante de pestaña, quiero reemplazar un fragmento por otro dentro de una pestaña y mantener el menú de pestañas y también la pestaña actual. Cuando se desliza a otra pestaña y vuelve a la original, quiero que se muestre el último fragmento.
- ¿Cómo aplicar span de fila en tablelayout?
- intento androide no activar
- Understading ART / Dalvik compilación correctamente
- No se puede implementar Parcelable porque no puedo hacer que el campo CREATOR esté estático
- Experiencia con Vaadin touchkit
Por ejemplo, tengo tab_a
con Fragment_1
, tab_b
con Fragment_4
y tab_c
con Fragment_7
. Ahora quiero un botón en Fragment_1
que me abre Fragment_2
, pero quiero poder deslizar a los fragmentos de la tab_b
y tab_c
. Y cuando vuelva a tab_a, Fragment_2
debe ser mostrado.
MainActivity | | ContainerFragment | | |_ _ _ Tab A | |_ _ _ Fragment 1 | | | |_ _ _ Fragment 2 | | | |_ _ _ Fragment 3 | | | |_ _ _ ... | |_ _ _ Tab B | |_ _ _ Fragment 4 | | | |_ _ _ Fragment 5 | | | |_ _ _ Fragment 6 | | | |_ _ _ ... | |_ _ _ Tab C | |_ _ _ Fragment 7 | | | |_ _ _ Fragment 8 | | | |_ _ _ Fragment 8 | | | |_ _ _ ...
Mi actividad principal actual.
Xml
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.design.widget.TabLayout android:id="@+id/tabs" android:layout_width="match_parent" android:layout_height="wrap_content" app:tabMode="fixed" app:tabGravity="fill"/> </android.support.design.widget.AppBarLayout> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> </android.support.design.widget.CoordinatorLayout>
Código
public class MainActivity extends AppCompatActivity { private TabLayout tabLayout; private final static int[] tabIcons = { R.drawable.ic_tab_a, R.drawable.ic_tab_b, R.drawable.ic_tab_c }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager); setupViewPager(viewPager); tabLayout = (TabLayout) findViewById(R.id.tabs); tabLayout.setupWithViewPager(viewPager); setupTabIcons(); } private void setupTabIcons() { tabLayout.getTabAt(0).setIcon(tabIcons[0]); tabLayout.getTabAt(1).setIcon(tabIcons[1]); tabLayout.getTabAt(2).setIcon(tabIcons[2]); } private void setupViewPager(ViewPager viewPager) { ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager()); adapter.addFrag(new Fragment1()); adapter.addFrag(new Fragment4()); adapter.addFrag(new Fragment7()); viewPager.setAdapter(adapter); } class ViewPagerAdapter extends FragmentPagerAdapter { private final List<Fragment> mFragmentList = new ArrayList<>(); ViewPagerAdapter(FragmentManager manager) { super(manager); } @Override public Fragment getItem(int position) { return mFragmentList.get(position); } @Override public int getCount() { return mFragmentList.size(); } void addFrag(Fragment fragment) { mFragmentList.add(fragment); } } }
Fragmentos
Xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:background="@android:color/holo_blue_light" android:id="@+id/fragment_1" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="myContext"> <Button android:text="Go to next Fragment" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_centerHorizontal="true" android:id="@+id/button_nextFrag" /> <FrameLayout android:id="@+id/tab1_container" android:layout_width="match_parent" android:layout_height="match_parent"/> </RelativeLayout>
Código
public class Fragment1 extends Fragment { private void goNextFragment() { FragmentTransaction trans = getFragmentManager().beginTransaction(); trans.replace(R.id.tab1_container, new Fragment2()); trans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); trans.addToBackStack(null); trans.commit(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment. View root = inflater.inflate(R.layout.fragment_1, container, false); // Go to next Fragment Button. final Button nextFrag = (Button) root.findViewById(R.id.button_nextFrag); nextFrag .setOnClickListener(new View.OnClickListener() { public void onClick(View v) { goNextFragment(); } }); return root; } }
Editar:
Tengo algunas soluciones, pero ninguna es perfecta. Si pongo un Framelayaout en MainActivity, Fragment_1
se reemplaza correctamente a Fragment_2
, pero también está en tab_b
y tab_c
. Si FrameLayout está en Fragment_1
, puedo deslizar las otras pestañas correctamente, pero el reemplazo no es bueno, porque Fragment_2
está abierto, pero Fragment_1
también está allí.
- ¿Cómo analizar json array con múltiples objetos por gson?
- Android: CountDownTimer salta el último onTick ()!
- ¿Qué está haciendo Eclipse cuando dice que está actualizando índices?
- Impresión POS / ESC Apex3 image SOS
- Aviary para Android - Cómo forzar la imagen de la cosecha usando editor.launch
- Mi aplicación Android se bloquea aunque estoy captando la excepción que dice está causando el fallo
- Cómo crear un JSONObject de objetos? Androide
- Buscar punto de intersección de tres círculos programáticamente
Puede usar un ViewPager
junto con un TabLayout
.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> <android.support.design.widget.TabLayout android:id="@+id/tablayout" android:layout_width="match_parent" android:layout_height="wrap_content"/> </LinearLayout>
A continuación, cree una clase que extienda FragmentStatePagerAdapter
para inicializar ViewPager
con su Fragment
inicial s:
public class CustomPagerAdapter extends FragmentStatePagerAdapter { private final List<String> tabTitles = new ArrayList<String>() {{ add("Fragment 1"); add("Fragment 4"); add("Fragment 7"); }}; private List<Fragment> tabs = new ArrayList<>(); public CustomPagerAdapter(FragmentManager fragmentManager) { super(fragmentManager); initializeTabs(); } private void initializeTabs() { tabs.add(HostFragment.newInstance(new Fragment1())); tabs.add(HostFragment.newInstance(new Fragment4())); tabs.add(HostFragment.newInstance(new Fragment7())); } @Override public Fragment getItem(int position) { return tabs.get(position); } @Override public int getCount() { return tabs.size(); } @Override public CharSequence getPageTitle(int position) { return tabTitles.get(position); } }
Los fragmentos que contienen el contenido real deben ser envueltos por un HostFragment
, que utiliza su FragmentManager
hijo para reemplazar el fragmento actual por uno nuevo si desea navegar, o para hacer estallar el último fragmento de la pila de fragmentos. Llame a su replaceFragment
para navegar:
public class HostFragment extends BackStackFragment { private Fragment fragment; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); View view = inflater.inflate(R.layout.host_fragment, container, false); if (fragment != null) { replaceFragment(fragment, false); } return view; } public void replaceFragment(Fragment fragment, boolean addToBackstack) { if (addToBackstack) { getChildFragmentManager().beginTransaction().replace(R.id.hosted_fragment, fragment).addToBackStack(null).commit(); } else { getChildFragmentManager().beginTransaction().replace(R.id.hosted_fragment, fragment).commit(); } } public static HostFragment newInstance(Fragment fragment) { HostFragment hostFragment = new HostFragment(); hostFragment.fragment = fragment; return hostFragment; } }
El HostFragment debe extender la clase abstracta BackstackFragment
public abstract class BackStackFragment extends Fragment { public static boolean handleBackPressed(FragmentManager fm) { if(fm.getFragments() != null){ for(Fragment frag : fm.getFragments()){ if(frag != null && frag.isVisible() && frag instanceof BackStackFragment){ if(((BackStackFragment)frag).onBackPressed()){ return true; } } } } return false; } protected boolean onBackPressed() { FragmentManager fm = getChildFragmentManager(); if(handleBackPressed(fm)){ return true; } else if(getUserVisibleHint() && fm.getBackStackEntryCount() > 0){ fm.popBackStack(); return true; } return false; } }
Alambre todo en la MainActivity
:
public class MainActivity extends AppCompatActivity { private CustomPagerAdapter customPagerAdapter; private ViewPager viewPager; private TabLayout tabLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); viewPager = (ViewPager) findViewById(R.id.viewpager); tabLayout = (TabLayout) findViewById(R.id.tablayout); customPagerAdapter = new CustomPagerAdapter(getSupportFragmentManager()); // 2 is enough for us; increase if you have more tabs! viewPager.setOffscreenPageLimit(2); viewPager.setAdapter(customPagerAdapter); tabLayout.setupWithViewPager(viewPager); } @Override public void onBackPressed() { if(!BackStackFragment.handleBackPressed(getSupportFragmentManager())){ super.onBackPressed(); } } public void openNextFragment() { HostFragment hostFragment = (HostFragment) customPagerAdapter.getItem(viewPager.getCurrentItem()); // your logic to change the fragments... } }
Esta solución no es ciertamente perfecta pero consigue el trabajo hecho. Leer más fluff sobre ello en mi blog en el tema.
Basado en lo que usted explicó Implemente lo siguiente:
1- En su actividad, cree sus Tabs
y ViewPager
:
mPager = (ViewPager) findViewById(R.id.vp_pager); mPager.setOffscreenPageLimit(3); PagerAdapter mAdapter = new PagerAdapter(getSupportFragmentManager(), getContext()); mPager.setAdapter(mAdapter); //tab.setupWithViewPager(mPager);
2- En cada ViewPager
crear ViewPager
(Supongo que quieres pestañas dentro de las tabs
si no necesitas que las pestañas las eliminen). La implementación de cada fragment
sería algo como:
ViewPager mPager = (ViewPager) rootView.findViewById(R.id.vp_pager); mPager.setOffscreenPageLimit(3); CategoryAdapter mAdapter = new CategoryAdapter(getChildFragmentManager());//make sure this ChildFragmentManager mPager.setAdapter(mAdapter);
También en fragmento crear un botón que cuando haga clic va a otro fragmento:
button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mPager.setCurrentItem(1); // go to second fragment } });
El resultado final sería algo como seguir y cuando Si vas a las pestañas de inicio y luego vuelve a la pestaña de categoría que su posición de Fragment
no se ha cambiado.
Dos puntos que debe recordar:
- Set
mPager.setOffscreenPageLimit(3);
Si no quieres destruir tu fragmento - En fragmento interno pase
getChildFragmentManager()
lugar deFragmentManager()
Si no necesitas ViewPager
Inner Y solo quieres cargar una instancia de Fragment a tiempo aquí es otra opción:
1- Haga el primer artículo de la manera anterior.
2- En tu fragmento xml ponemos FrameContainer y cargamos tu fragmento dentro de él:
CategoryResultFragment f = CategoryResultFragment.newInstance(); getFragmentManager().beginTransaction() .replace(R.id.frame_result_container, f) .commit();
Editar: Este no es el mejor enfoque, pero creo que resolver su problema:
1- Crear un campo estático en su MainActivity
como sigue:
static String[] type = new String[3];
2- Cuando llame a onClick en su fragmento, actualice String
valor String
en MainActivity
.
public static update currentType(int pos,String type);
El primer valor es la posición ViewPager, el segundo valor es el tipo de fragmento interno (por ejemplo: fragment_d);
3- En su ViewPager
@Override public Fragment getItem(int position) { switch (position) { case 0: // first tab if(type[position] == "fragment_d") return new Fragment_D(); else return new Fragment_B(); } }
Puede cambiar fragmentos dentro del fragmento de página. Por ejemplo, TAB_A implementa la lógica de escoger el fragmento 1 o 2, y mostrar el fragmento escogido dentro. La jerarquía se ve así:
ViewPager -> TAB_A -> fragmento 1 o 2 (que se muestra dentro de TAB_A).
También debe utilizar getChildFragmentManager () para administrar fragmentos dentro de TAB_A.
- ¿Alguna experiencia con Android NDK?
- Android: ellipsize end – Caracteres adicionales después de la elipse