This question already has answers here:
Why `PagerAdapter::notifyDataSetChanged` is not updating the View?
(43 answers)
Closed 10 years ago.
I am using ViewPager to allow user to swipe between its views. Is there a way how to force this ViewPager to reload/re-instantiate its views in case that they are no longer valid or needs to be refreshed? I tried to call notifyDataSetChanged() on its adapter but this does not invoke instantiateItem() method again.
EDIT
Here is the class that extends from ViewPager and its adapter definision. Bellow is the refresh() method that I call when I want to force to refresh items.
public class DayFlipper extends ViewPager {
public class FlipperAdapter extends PagerAdapter {
#Override
public int getCount() {
return DayFlipper.DAY_HISTORY;
}
#Override
public void startUpdate(View container) {
}
#Override
public Object instantiateItem(View container, int position) {
Log.d(TAG, "instantiateItem(): " + position);
Date d = DateHelper.getBot();
for (int i = 0; i < position; i++) {
d = DateHelper.getTomorrow(d);
}
d = DateHelper.normalize(d);
CubbiesView cv = new CubbiesView(mContext);
cv.setLifeDate(d);
((ViewPager) container).addView(cv, 0);
// add map
cv.setCubbieMap(mMap);
cv.initEntries(d);
return cv;
}
#Override
public void destroyItem(View container, int position, Object object) {
((ViewPager) container).removeView((CubbiesView) object);
}
#Override
public void finishUpdate(View container) {
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == ((CubbiesView) object);
}
#Override
public Parcelable saveState() {
return null;
}
#Override
public void restoreState(Parcelable state, ClassLoader loader) {
}
}
...
public void refresh() {
getAdapter().notifyDataSetChanged();
}
}
Had the same problem. For me it worked to call
viewPage.setAdapter( adapter );
again which caused reinstantiating the pages again.
I have found a solution. It is just a workaround to my problem but currently the only solution.
ViewPager PagerAdapter not updating the View
public int getItemPosition(Object object) {
return POSITION_NONE;
}
Does anyone know whether this is a bug or not?
public class DayFlipper extends ViewPager {
private Flipperadapter adapter;
public class FlipperAdapter extends PagerAdapter {
#Override
public int getCount() {
return DayFlipper.DAY_HISTORY;
}
#Override
public void startUpdate(View container) {
}
#Override
public Object instantiateItem(View container, int position) {
Log.d(TAG, "instantiateItem(): " + position);
Date d = DateHelper.getBot();
for (int i = 0; i < position; i++) {
d = DateHelper.getTomorrow(d);
}
d = DateHelper.normalize(d);
CubbiesView cv = new CubbiesView(mContext);
cv.setLifeDate(d);
((ViewPager) container).addView(cv, 0);
// add map
cv.setCubbieMap(mMap);
cv.initEntries(d);
adpter = FlipperAdapter.this;
return cv;
}
#Override
public void destroyItem(View container, int position, Object object) {
((ViewPager) container).removeView((CubbiesView) object);
}
#Override
public void finishUpdate(View container) {
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == ((CubbiesView) object);
}
#Override
public Parcelable saveState() {
return null;
}
#Override
public void restoreState(Parcelable state, ClassLoader loader) {
}
}
...
public void refresh() {
adapter().notifyDataSetChanged();
}
}
try this.
Related
Good morning,
I have a Fragment which its layout has a ViewPager, I provide a custom PageAdapter to show two child layouts. One layout is to fill with personal data and another layout is to fill with Address data by the user. On my fragment I want to retrieve both layouts data and fill a object Pessoa(Person) with an attribute Endereco (Address). So far my ViewPager is working and both layout are displayed, however when I try to get the fields on both layouts, either on onCreateView or onResume fragment's method, using :
viewpager.getChildAt(0).findViewById(R.id.txt1)
I got an NullPointerException, but if I add an OnPageChangeListener this works, I not sure if it's the best approach. Is There a best place to retrieve a reference to the viewpager child's layout?
Ps. I don't want to use two other Fragments in order to display each of the layouts.
PageAdapter
public class ViewPagerCadastroPessoaAdapter extends PagerAdapter {
private Context context;
private int[] views = {R.layout.layout_cadastro_dados_pessoais,R.layout.layout_cadastro_endereco };
public ViewPagerCadastroPessoaAdapter(Context context) {
this.context = context;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
LayoutInflater inflater = LayoutInflater.from(this.context);
View layout = inflater.inflate(views[position], container, false);
container.addView(layout, position);
return layout;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position){
case 0:
return "Dados Pessoais";
case 1:
return "Endereço";
}
return super.getPageTitle(position);
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}}
ViewPager's holder Fragment
public class CadastroPessoaFragment extends Fragment {
private ViewPager viewPagerCadastroPessoa;
private TabLayout tabLayoutCadastroPessoa;
public CadastroPessoaFragment() {
}
public static CadastroPessoaFragment newInstance() {
return new CadastroPessoaFragment();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_cadastro_pessoa, container, false);
tabLayoutCadastroPessoa = root.findViewById(R.id.tabLayoutCadastroPessoa);
viewPagerCadastroPessoa = root.findViewById(R.id.viewPagerCadastroPessoa);
viewPagerCadastroPessoa.setOffscreenPageLimit(2);
viewPagerCadastroPessoa.setAdapter(new ViewPagerCadastroPessoaAdapter(getContext()));
tabLayoutCadastroPessoa.setupWithViewPager(viewPagerCadastroPessoa);
int cor = ContextCompat.getColor(getContext(), android.R.color.white);
tabLayoutCadastroPessoa.setTabTextColors(cor, cor);
//get a null pointer
viewPagerCadastroPessoa.getChildAt(0).findViewById(R.id.txt1);
viewPagerCadastroPessoa.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
//works fine
viewPagerCadastroPessoa.getChildAt(0).findViewById(R.id.txt1);
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
return root;
}
#Override
public void onResume() {
super.onResume();
//get a null pointer
viewPagerCadastroPessoa.getChildAt(0).findViewById(R.id.txt1);
}
}
Thank you all in advance
UPDATE
According with
Anton Malyshev answer
The way Viewpager creates its pages is kind of "unsynchronized", so I used the following approach to solve my problem:
On my custom adapter I definied an interface with a single method onViewPagerReady(), as my Viewpager will always have only two pages, inside instantiateItem I check when position is 1 (once position starts with 0), if position == 1 I call the method onViewPagerReady that my fragment viewpager's holder implements, so inside this method I retrieve the layout of viewpager's children
public class ViewPagerCadastroPessoaAdapter extends PagerAdapter {
public interface ViewPagerObserver{
void onViewPagerReady();
}
private Context context;
private int[] views = {R.layout.layout_cadastro_dados_pessoais,R.layout.layout_cadastro_endereco };
private ViewPagerObserver observer;
public ViewPagerCadastroPessoaAdapter(Context context, ViewPagerObserver observer) {
this.context = context;
this.observer = observer;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
LayoutInflater inflater = LayoutInflater.from(this.context);
View layout = inflater.inflate(views[position], container, false);
container.addView(layout, position);
if(position == 1){
observer.onViewPagerReady();
}
return layout;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position){
case 0:
return "Dados Pessoais";
case 1:
return "Endereço";
}
return super.getPageTitle(position);
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}
Fragment Viewpager's Holder
#Override
public void onViewPagerReady() {
View rootCadastroDadosPessoais = viewPagerCadastroPessoa.getChildAt(0);
View rootCadastroEnderecos =viewPagerCadastroPessoa.getChildAt(1);
}
Thank you all.
Just wait until viewPagerCadastroPessoa.getChildCount() will be greater than 0. The pages in ViewPager are not created yet in onResume (they are created asynchronously).
I have an image view. I want to touch the image and drag it to left or right. When the image is dragged to the left, the new image should appear from the array. When i drag it to right it should be saved in another activity. How can i possibly do this, if somebody could guide me to a tutorial or example. Thank-you
You can use ViewPager and PageAdapter.
protected class ImagePagerAdapter extends PagerAdapter {
public ImagePagerAdapter() {
}
#Override
public int getCount() {
return getImages().size();
}
#Override
public boolean isViewFromObject(View view, Object o) {
return view == o;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
LayoutInflater inflater = (LayoutInflater) container.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.image_page_view, null);
String url = getImages().get(position);
if (url != null) {
ImageLoader.getInstance().displayImage(url, (ImageView) view.findViewById(R.id.image_page_view));
}
container.addView(view, 0);
return view;
}
}
...
imagePager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int i, float v, int i2) {
}
#Override
public void onPageSelected(int i) {
//logic to open activity or other action..;
}
#Override
public void onPageScrollStateChanged(int i) {
}
});
...
imagePager.setAdapter(new ImagePagerAdapter());
I made an app which has 100 pages and change through swipe, but I want to add "Go to page" option so I can go to the specific page easily.
public class ViewPagerExampleActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_viewpager_example);
ExtendedViewPager mViewPager = (ExtendedViewPager) findViewById(R.id.view_pager);
mViewPager.setAdapter(new TouchImageAdapter());
}
static class TouchImageAdapter extends PagerAdapter {
private static int[] images = { R.drawable.page3, R.drawable.page4,
R.drawable.page5, R.drawable.page6, R.drawable.page7,
R.drawable.page8, R.drawable.page9, R.drawable.page10, R.drawable.page11,
R.drawable.page12, R.drawable.page13, R.drawable.page14,
R.drawable.page15, R.drawable.page16, R.drawable.page17,
R.drawable.page18, R.drawable.page19, R.drawable.page20, R.drawable.page21,
R.drawable.page22, R.drawable.page23, R.drawable.page24,
R.drawable.page25, R.drawable.page26, R.drawable.page27,
R.drawable.page28, R.drawable.page29, R.drawable.page30,
R.drawable.page31, R.drawable.page32, R.drawable.page33, R.drawable.page34,
R.drawable.page35, R.drawable.page36, R.drawable.page37,
R.drawable.page38, R.drawable.page39, R.drawable.page40, R.drawable.page41,
R.drawable.page42, R.drawable.page43, R.drawable.page44,
R.drawable.page45, R.drawable.page46, R.drawable.page47,
R.drawable.page48, R.drawable.page49, R.drawable.page50, R.drawable.page51,
R.drawable.page52, R.drawable.page53, R.drawable.page54,
R.drawable.page55, R.drawable.page56, R.drawable.page57,
R.drawable.page58, R.drawable.page59, R.drawable.page60, R.drawable.page61,
R.drawable.page62, R.drawable.page63, R.drawable.page64,
R.drawable.page65, R.drawable.page66, R.drawable.page67,
R.drawable.page68, R.drawable.page69, R.drawable.page70, R.drawable.page71,
R.drawable.page72, R.drawable.page73, R.drawable.page74 };
#Override
public int getCount() {
return images.length;
}
#Override
public View instantiateItem(ViewGroup container, int position) {
TouchImageView img = new TouchImageView(container.getContext());
img.setImageResource(images[position]);
container.addView(img, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
return img;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}
#Override
public void onResume() {
super.onResume();
}
#Override
protected void onPause() {
super.onPause();
}
long lastPress;
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
super.onBackPressed();
if (interstitial.isLoaded())
interstitial.show();
}
}
To switch the ViewPager to a specific page, you just need to call setCurrentItem().
I`m trying to implement ImageGallery on Android. I use AndroidTouchGallery library. In MainActyvity I have list of images and by clicking on them open AndroidTouchGallery. Everything work, but when open the image gallery starts with the first one.
There need to set the image position, in which to start. In this stage I have a problem. Maybe someone how to make it.
int pos ; //Picture Position
UrlPagerAdapter pagerAdapter = new UrlPagerAdapter(Full_Image_Activity.this, ArrayImgBig);
mViewPager = (GalleryViewPager)findViewById(R.id.viewer);
mViewPager.setOffscreenPageLimit(3);
mViewPager.setAdapter(pagerAdapter);
The code of UrlPageAdapter. I try to set the position in setPrimaryItem, but it still open the first image.
/**
Class wraps URLs to adapter, then it instantiates {#link UrlTouchImageView} objects to paging up through them.
*/
public class UrlPagerAdapter extends BasePagerAdapter {
public UrlPagerAdapter(Context context, List<String> resources)
{
super(context, resources);
}
#Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
((GalleryViewPager)container).mCurrentView = ((UrlTouchImageView)object).getImageView();
}
#Override
public Object instantiateItem(ViewGroup collection, int position){
final UrlTouchImageView iv = new UrlTouchImageView(mContext);
iv.setUrl(mResources.get(position));
iv.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
collection.addView(iv, 0);
return iv;
}
}
BasePagerAdapter
/**
Class wraps URLs to adapter, then it instantiates <b>UrlTouchImageView</b> objects to paging up through them.
*/
public class BasePagerAdapter extends PagerAdapter {
protected final List<String> mResources;
protected final Context mContext;
protected int mCurrentPosition = -1;
protected OnItemChangeListener mOnItemChangeListener;
public BasePagerAdapter()
{
mResources = null;
mContext = null;
}
public BasePagerAdapter(Context context, List<String> resources)
{
this.mResources = resources;
this.mContext = context;
}
#Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
if (mCurrentPosition == position) return;
GalleryViewPager galleryContainer = ((GalleryViewPager)container);
if (galleryContainer.mCurrentView != null) galleryContainer.mCurrentView.resetScale();
mCurrentPosition = position;
if (mOnItemChangeListener != null) mOnItemChangeListener.onItemChange(mCurrentPosition);
}
#Override
public void destroyItem(ViewGroup collection, int position, Object view){
collection.removeView((View) view);
}
#Override
public int getCount()
{
return mResources.size();
}
#Override
public boolean isViewFromObject(View view, Object object){
return view.equals(object);
}
#Override
public void finishUpdate(ViewGroup arg0){
}
#Override
public void restoreState(Parcelable arg0, ClassLoader arg1){
}
#Override
public Parcelable saveState(){
return null;
}
#Override
public void startUpdate(ViewGroup arg0) { }
public int getCurrentPosition() { return mCurrentPosition; }
public void setOnItemChangeListener(OnItemChangeListener listener) { mOnItemChangeListener = listener; }
public static interface OnItemChangeListener
{
public void onItemChange(int currentPosition);
}
}
Olso I have some other queston.
*is the "setPrimaryItem" set up the main Item(Image) witch is open first?
*is the "instantiateItem" initialise every item from the array, whitch is shows?
I made it by this:
mViewPager = (GalleryViewPager)findViewById(R.id.viewer);
mViewPager.setOffscreenPageLimit(3);
mViewPager.setAdapter(pagerAdapter);
//set position
mViewPager.setCurrentItem(pos);
I have ViewPager with one page and Tab's. In AsyncTask i load data, and update ViewPager, but nothing change. In LogCat i checked, i have needed data.
MainClass.java
mViewPager = (ViewPager) findViewById(R.id.cinema_view_pager);
mTabPager = new TabPager("Загрузка");
mViewPager.setAdapter(mTabPager);
LoadCinema cinema = new LoadCinema(this,0);
cinema.execute();
TabPager(Adapter).class
public class TabPager extends PagerAdapter{
private String message = "";
public TabPager(String msg){
message = msg;
}
#Override
public int getCount() {
return 1;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view.equals(object);
}
public void update(String msg){
message = msg;
notifyDataSetChanged();
}
#Override
public View instantiateItem(View container, int position){
View v = getLayoutInflater().inflate(R.layout.cinema_layout, null);
TextView text = (TextView) v.findViewById(R.id.textView1);
text.setText(message+"Message" +"");
((ViewPager) container).addView(v);
return v;
}
public void destroyItem(View container, int position, Object object) {
((ViewPager) container).removeView((View) object);
}
}
LoadCinema.class
public void onPostExecute(List<CinemaCategory> result){
super.onPostExecute(result);
CinemaCategory cat = result.get(page);
cinema.mTabPager.update(cat.getDescription());
}
I tryed with three pages, and when i swype to last page, i haved data and then swype to first page view pager updated.
Now i have Answer, Thank's to this post
To adapter need add this code
public int getItemPosition(Object object) {
return POSITION_NONE;
}
Consider using FragmentStatePagerAdapter instead of PagerAdapter
public class TabPager extends FragmentStatePagerAdapter {
...
}