Cambio de la imagen de fondo del fragmento actual en viewpager
Tengo 4 fragmentos en un viewpager. Y FragmentStatePagerAdapter dentro de la actividad donde está mi viewpager. El método newInstance () de FragmentStatePagerAdapter toma como ID de diseño de parámetros, por lo que cada fragmento tiene su propio diseño:
ViewPager pager; public class MainActivity extends FragmentActivity{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); pager = (ViewPager) findViewById(R.id.viewPager); pager.setAdapter(new MyPagerAdapter(getSupportFragmentManager()));} private static class MyPagerAdapter extends FragmentStatePagerAdapter { FragmentManager fm; SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>(); public MyPagerAdapter(FragmentManager fm) { super(fm); this.fm = fm; } @Override public Fragment getItem(int pos) { if(pos!=0){ pos = pos%4; } Fragment frag; switch(pos) { case 0: frag = FirstFragment.newInstance(R.layout.fire_room_wall1); return frag; case 1: frag = FirstFragment.newInstance(R.layout.fire_room_wall2); return frag; case 2: frag = FirstFragment.newInstance(R.layout.fire_room_wall3); return frag; case 3: frag = FirstFragment.newInstance(R.layout.fire_room_wall3); return frag; default: return FirstFragment.newInstance(R.layout.fire_room_wall1); } } @Override public int getCount() { return 444444; } @Override public Object instantiateItem(ViewGroup container, int position) { Fragment fragment = (Fragment) super.instantiateItem(container, position); registeredFragments.put(position, fragment); return fragment; } @Override public void destroyItem(ViewGroup container, int position, Object object) { registeredFragments.remove(position); super.destroyItem(container, position, object); } public Fragment getRegisteredFragment(int position) { return registeredFragments.get(position); } } }
Aquí está FirstFragment:
- ListFragment no vuelve a mostrar datos al llamar desde FragmentStatePagerAdapter
- ¿Cómo evitar recrear Fragment en ViewPager?
- Fragmento en ViewPager en Fragmento no se vuelve a cargar en el cambio de orientación
- ViewPager con diferentes adaptadores para retrato y paisaje
- El fragmento ya no existe para la clave f0: index 1
public class FirstFragment extends Fragment{ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { int layout = getArguments().getInt("layout"); View v = inflater.inflate(layout, container, false); return v; } public static FirstFragment newInstance(int layout) { FirstFragment f = new FirstFragment(); Bundle b = new Bundle(); b.putInt("layout", layout); f.setArguments(b); return f; } }
Y activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/viewPager" android:layout_width="fill_parent" android:layout_height="fill_parent" /> <com.example.viewpagerfragement.CustomView android:id="@+id/customView" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </FrameLayout> </RelativeLayout>
y uno de los parámetros newInstance fire_room_wall1.xml:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:background="@drawable/wall_nobrainjar" android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/first" >
// algunas otras vistas de niños
<ImageView android:id="@+id/zoomed_image" android:layout_width="fill_parent" android:layout_height="fill_parent" android:visibility="gone"/>
// algunas otras vistas de niños
</RelativeLayout>
Ahora, en algún momento de mi programa, quiero cambiar la imagen de fondo del diseño del fragmento actual. Y traté de hacerlo así:
int i = pager.getCurrentItem(); Fragment page = ((MyPagerAdapter)pager.getAdapter()).getRegisteredFragment(i); ((BitmapDrawable)page.getView().getBackground()).getBitmap().recycle(); page.getView().setBackgroundResource(R.drawable.wall3_nopaperball);
Pero la línea " ((BitmapDrawable)page.getView().getBackground()).getBitmap().recycle();
" devuelve NullPointerException porque page.getView().getBackground()
es null. ¿Qué estoy haciendo mal o cómo puedo cambiar la imagen de fondo? PS por alguna razón el tipo page.getView () es NoSaveStateFrameLayout, no RelativeLayout como uno esperaría
- Comunicación entre Fragmentos en ViewPager
- ViewPager no se actualiza con FragmentStatePagerAdapter
- FragmentStatePageAdapter: Múltiples elementos visibles al mismo tiempo - ¿Cómo centrar una página específica?
- FragmentPagerAdapter y FragmentStatePagerAdapter
- Ver Pager Crash Null Pointer Excepción debido a navegar de nuevo al fragmento antiguo - Android
- FragmentStatePagerAdapter OutOfMemoryError
- Cargar sólo un fragmento en ViewPager
- Android setUserVisibleHint nunca se llama?
Solución:–
en realidad su problema es que está reciclando bitmap es decir, que está liberando ese mapa de bits y los datos de píxeles así, obviamente obtendrá el nulo.!
Ya se menciona en los documentos api de Android: –
Sólo tienes que hacer esto:
int i = pager.getCurrentItem(); Fragment page = ((MyPagerAdapter)pager.getAdapter()).getRegisteredFragment(i); Bitmap bitmapNeedTobeRecycled = ((BitmapDrawable)page.getView().getBackground()).getBitmap() page.getView().setBackgroundResource(R.drawable.wall3_nopaperball); bitmapNeedTobeRecycled.recycle();
Funciona entonces .. Disfrute ..!
En primer lugar, no guarde una lista de fragmentos en su adaptador. Los adaptadores de buscapersonas deben ser servidos con datos a través de un método personalizado y luego su getItem()
debe usarlo para crear Fragmentos. En lugar de aleatorizar los diseños en getItem()
hacerlo en su lista de artículos (ver código a continuación) antes de pasarlo al adaptador. No anule el destroyItem()
initialiseItem()
o destroyItem()
. Además, no tiene que mantener referencia a FragmentManager
. Puede implementar su adaptador de esta manera:
Cree una clase personalizada que contenga sus datos.
public class MyItem { private int layout; private int bitmap; public MyItem(layout, bitmap) { this.layout = layout; this.bitmap = bitmap; } //implement getters and setters }
Siguiente implementar adaptador como este:
public static class MyPagerAdapter extends FragmentStatePagerAdapter { private List<MyItem> items = new ArrayList<MyItem>(0); public void setItems(List<MyItem> items) { this.items = items; } @Override public Fragment getItem(int pos) { MyItem item = items.get(pos); return FirstFragment.newInstance(item.getLayout(), item.getBitmap()); } @Override public int getCount() { return items.size(); } public void updateItemBitmap(int position, int bitmap) { MyItem myItem = items.get(position); myItem.setBitmap(bitmap); notifyDataSetChanged(); } @Override public int getItemPosition(Object object) { return POSITION_NONE; } }
Luego, en el método getItem()
, inicializa los fragmentos basados en esos datos. A continuación, cree el método para actualizar los elementos que está actualizando la posición proporcionada y, a continuación, invalidar el adaptador. No olvide implementar getItemPosition()
, hace que ViewPager invalide todos los elementos, también aquellos que ya están creados.
Por último, puede actualizarlo en su actividad de la siguiente manera:
int i = pager.getCurrentItem(); ((MyPagerAdapter)pager.getAdapter()).updateItemBitmap(i,R.drawable.wall3_nopaperball);
La implementación de su fragmento se vería así:
public class FirstFragment extends Fragment{ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { int layout = getArguments().getInt("layout"); int bitmap = getArguments().getInt("bitmap"); View v = inflater.inflate(layout, container, false); v.setBackgroundResource(bitmap); return v; } public static FirstFragment newInstance(int layout, int bitmap) { FirstFragment f = new FirstFragment(); Bundle b = new Bundle(); b.putInt("layout", layout); b.putInt("bitmap",bitmap); f.setArguments(b); return f; } }
- Llamar a startIntentSenderForResult de Fragment (sin usar la actividad existente) (Android Billing v3)
- Uso de fragmentos del cajón de navegación para superponer la actividad