我正在使用兼容性库中的ViewPager。我已经成功地让它显示几个视图,我可以通过页面。

但是,我很难弄清楚如何用一组新的视图更新ViewPager。

我已经尝试了各种各样的事情,比如调用mAdapter.notifyDataSetChanged(), mviewpage .invalidate(),甚至在每次我想使用新的数据列表时创建一个全新的适配器。

没有任何帮助,textviews保持不变,从原始数据。

更新: 我做了一个小测试项目,我几乎能够更新视图。我将在下面粘贴这个类。

然而,似乎没有更新的是第二个视图,“B”仍然存在,它应该在按下更新按钮后显示“Y”。

public class ViewPagerBugActivity extends Activity {

    private ViewPager myViewPager;
    private List<String> data;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        data = new ArrayList<String>();
        data.add("A");
        data.add("B");
        data.add("C");

        myViewPager = (ViewPager) findViewById(R.id.my_view_pager);
        myViewPager.setAdapter(new MyViewPagerAdapter(this, data));

        Button updateButton = (Button) findViewById(R.id.update_button);
        updateButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                updateViewPager();
            }
        });
    }

    private void updateViewPager() {
        data.clear();
        data.add("X");
        data.add("Y");
        data.add("Z");
        myViewPager.getAdapter().notifyDataSetChanged();
    }

    private class MyViewPagerAdapter extends PagerAdapter {

        private List<String> data;
        private Context ctx;

        public MyViewPagerAdapter(Context ctx, List<String> data) {
            this.ctx = ctx;
            this.data = data;
        }

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

        @Override
        public Object instantiateItem(View collection, int position) {
            TextView view = new TextView(ctx);
            view.setText(data.get(position));
            ((ViewPager)collection).addView(view);
            return view;
        }

        @Override
        public void destroyItem(View collection, int position, Object view) {
             ((ViewPager) collection).removeView((View) view);
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }

        @Override
        public Parcelable saveState() {
            return null;
        }

        @Override
        public void restoreState(Parcelable arg0, ClassLoader arg1) {
        }

        @Override
        public void startUpdate(View arg0) {
        }

        @Override
        public void finishUpdate(View arg0) {
        }
    }
}

当前回答

在ViewPager2中,您可以重新初始化适配器,用新的视图刷新页导航列表。viewPager2。adapter = myPagerAdapter

其他回答

对我有用的是重写finishUpdate方法,它在转换结束时被调用,并在那里执行notifyDataSetChanged():

public class MyPagerAdapter extends FragmentPagerAdapter {
    ...
    @Override
    public void finishUpdate(ViewGroup container) {
        super.finishUpdate(container);
        this.notifyDataSetChanged();
    }
    ...
}

我发现这个问题的决定很有趣。 我们可以使用FragmentStatePagerAdapter (android.support.v4.app.FragmentStatePagerAdapter),而不是使用FragmentPagerAdapter将所有片段保存在内存中,当我们每次选择fragment时,它都会重新加载fragment。

两个适配器的实现是相同的。我们只需要在extend FragmentStatePagerAdapter上修改extend FragmentPagerAdapter

经过几个小时的挫折,同时尝试所有上述解决方案来克服这个问题,也尝试了其他类似问题的许多解决方案,比如这个,这个,这些都失败了,我解决了这个问题,并使ViewPager破坏旧的片段,并用新的片段填充分页器。我解决的问题如下:

1)使ViewPager类扩展FragmentPagerAdapter,如下:

 public class myPagerAdapter extends FragmentPagerAdapter {

2)为存储标题和片段的ViewPager创建一个Item,如下所示:

public class PagerItem {
private String mTitle;
private Fragment mFragment;


public PagerItem(String mTitle, Fragment mFragment) {
    this.mTitle = mTitle;
    this.mFragment = mFragment;
}
public String getTitle() {
    return mTitle;
}
public Fragment getFragment() {
    return mFragment;
}
public void setTitle(String mTitle) {
    this.mTitle = mTitle;
}

public void setFragment(Fragment mFragment) {
    this.mFragment = mFragment;
}

}

3)让ViewPager的构造函数把我的FragmentManager实例存储在我的类中,如下所示:

private FragmentManager mFragmentManager;
private ArrayList<PagerItem> mPagerItems;

public MyPagerAdapter(FragmentManager fragmentManager, ArrayList<PagerItem> pagerItems) {
    super(fragmentManager);
    mFragmentManager = fragmentManager;
    mPagerItems = pagerItems;
}

4)创建一个方法,通过直接从fragmentManager本身删除之前的所有片段,用新数据重新设置适配器数据,使适配器再次从新列表中设置新片段,如下所示:

public void setPagerItems(ArrayList<PagerItem> pagerItems) {
    if (mPagerItems != null)
        for (int i = 0; i < mPagerItems.size(); i++) {
            mFragmentManager.beginTransaction().remove(mPagerItems.get(i).getFragment()).commit();
        }
    mPagerItems = pagerItems;
}

5)从容器Activity或Fragment中,不要用新的数据重新初始化适配器。使用setPagerItems方法设置新数据,如下所示:

ArrayList<PagerItem> pagerItems = new ArrayList<PagerItem>();
pagerItems.add(new PagerItem("Fragment1", new MyFragment1()));
pagerItems.add(new PagerItem("Fragment2", new MyFragment2()));

mPagerAdapter.setPagerItems(pagerItems);
mPagerAdapter.notifyDataSetChanged();

我希望这能有所帮助。

我实际上使用notifyDataSetChanged()在ViewPager和CirclePageIndicator和之后,我调用destroyDrawingCache()在ViewPager和它的工作。其他的解决方法对我都不起作用。

ViewPager不是为支持动态视图更改而设计的。

我已经确认了这一点,同时寻找与此相关的另一个bug https://issuetracker.google.com/issues/36956111,特别是https://issuetracker.google.com/issues/36956111#comment56

这个问题有点老了,但是谷歌最近用ViewPager2解决了这个问题。 它将允许用标准的解决方案取代手工的(不需要维护并且可能有bug的)解决方案。它还可以防止像某些回答那样不必要地重新创建视图。

对于ViewPager2的例子,您可以查看https://github.com/googlesamples/android-viewpager2

如果您想使用ViewPager2,您需要在构建中添加以下依赖项。Gradle文件:

  dependencies {
     implementation 'androidx.viewpager2:viewpager2:1.0.0-beta02'
  }

然后你可以替换你的ViewPager在你的xml文件:

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

在那之后,你需要在你的活动中用ViewPager2替换ViewPager

ViewPager2需要一个RecyclerView。适配器,或者FragmentStateAdapter,在你的例子中,它可以是RecyclerView。适配器

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {

    private Context context;
    private ArrayList<String> arrayList = new ArrayList<>();

    public MyAdapter(Context context, ArrayList<String> arrayList) {
        this.context = context;
        this.arrayList = arrayList;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        holder.tvName.setText(arrayList.get(position));
    }

    @Override
    public int getItemCount() {
        return arrayList.size();
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {
        TextView tvName;

        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            tvName = itemView.findViewById(R.id.tvName);
        }
    }
} 

在使用TabLayout的情况下,你可以使用TabLayoutMediator:

        TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(tabLayout, viewPager, true, new TabLayoutMediator.OnConfigureTabCallback() {
            @Override
            public void onConfigureTab(@NotNull TabLayout.Tab tab, int position) {
                // configure your tab here
                tab.setText(tabs.get(position).getTitle());
            }
        });

        tabLayoutMediator.attach();

然后,您将能够通过修改适配器的数据并调用notifyDataSetChanged方法来刷新视图