我正在使用兼容性库中的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) {
        }
    }
}

当前回答

所有这些答案对我都不起作用。

唯一对我有用的是,我必须再次将适配器设置为viewpager,然后它将刷新内容。

removeView(int pos)在我的PagerAdaper

public void removeView(int index) {
       imageFileNames.remove(index);
       notifyDataSetChanged();
}

无论我在哪里删除文件,我都必须这样做

imagePagerAdapter.removeView(currentPosition);
viewPager.setAdapter(imagePagerAdapter);

编辑:

下面的方法是有效的,你可以使用下面的方法。

public void updateView(int pos){
      viewPager.setAdapter(null);
      imagePagerAdapter =new ImagePagerAdapter(YOUR_CONTEXT,YOUR_CONTENT);
      viewPager.setAdapter(imagePagerAdapter);
      viewPager.setCurrentItem(pos);
}

用你的上下文替换你的YOUR_CONTEXT,用你的内容名称替换你的内容,即更新列表或其他东西。

其他回答

我知道我迟到了,但还是能帮到别人。我只是扩展了接受的答案,我也添加了评论。

答案本身说明它是低效的

为了让它只在需要时刷新,你可以这样做

private boolean refresh;

public void refreshAdapter() {
    refresh = true;
    notifyDataSetChanged();
}

@Override
public int getItemPosition(@NonNull Object object) {
    if (refresh) {
        refresh = false;
        return POSITION_NONE;
    } else {
        return super.getItemPosition(object);
    }
}

下面的代码对我有用。

创建一个扩展FragmentPagerAdapter类的类,如下所示。

public class Adapter extends FragmentPagerAdapter {

private int tabCount;
private Activity mActivity;
private Map<Integer, String> mFragmentTags;
private FragmentManager mFragmentManager;
private int container_id;
private ViewGroup container;
private List<Object> object;

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

public Adapter(FragmentManager fm, int numberOfTabs , Activity mA) {
    super(fm);
    mActivity = mA;
    mFragmentManager = fm;
    object = new ArrayList<>();
    mFragmentTags = new HashMap<Integer, String>();
    this.tabCount = numberOfTabs;
}

@Override
public Fragment getItem(int position) {
    switch (position) {
        case 0:
            return Fragment0.newInstance(mActivity);
        case 1:
            return Fragment1.newInstance(mActivity);
        case 2:
            return Fragment2.newInstance(mActivity);
        default:
            return null;
    }}


@Override
public Object instantiateItem(ViewGroup container, int position) {
    Object object = super.instantiateItem(container, position);
    if (object instanceof Fragment) {
        Log.e("Already defined","Yes");
        Fragment fragment = (Fragment) object;
        String tag = fragment.getTag();
        Log.e("Fragment Tag","" + position + ", " + tag);
        mFragmentTags.put(position, tag);
    }else{
        Log.e("Already defined","No");
    }
    container_id = container.getId();
    this.container = container;
    if(position == 0){
        this.object.add(0,object);
    }else if(position == 1){
        this.object.add(1,object);
    }else if(position == 2){
        this.object.add(2,object);
    }
    return object;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    super.destroyItem(container, position, object);
    if (object instanceof Fragment) {
        Log.e("Removed" , String.valueOf(position));
    }
}

@Override
public int getItemPosition (Object object)
{   int index = 0;
    if(this.object.get(0) == object){
        index = 0;
    }else if(this.object.get(1) == object){
        index = 1;
    }else if(this.object.get(2) == object){
        index = 2;
    }else{
        index = -1;
    }
    Log.e("Index" , "..................." + String.valueOf(index));
    if (index == -1)
        return POSITION_NONE;
    else
        return index;
}

public String getFragmentTag(int pos){
    return "android:switcher:"+R.id.pager+":"+pos;
}

public void NotifyDataChange(){
    this.notifyDataSetChanged();
}

public int getcontainerId(){
    return container_id;
}

public ViewGroup getContainer(){
    return this.container;
}

public List<Object> getObject(){
    return this.object;
}

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

然后在您创建的每个Fragment中,创建一个updateFragment方法。在这个方法中,您可以更改片段中需要更改的内容。例如,在我的例子中,Fragment0包含了一个GLSurfaceView,它显示了一个基于.ply文件路径的3d对象,所以在我的updateFragment方法中,我改变了这个ply文件的路径。

然后创建一个ViewPager实例,

viewPager = (ViewPager) findViewById(R.id.pager);

和一个Adpater实例,

adapter = new Adapter(getSupportFragmentManager(), 3, this);

然后这样做,

viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(1);

然后在类内部初始化了上面的Adapter类并创建了一个viewPager,每次你想要更新你的一个片段(在我们的例子中是Fragment0)时,使用以下方法:

adapter.NotifyDataChange();

adapter.destroyItem(adapter.getContainer(), 0, adapter.getObject().get(0)); // destroys page 0 in the viewPager.

fragment0 = (Fragment0) getSupportFragmentManager().findFragmentByTag(adapter.getFragmentTag(0)); // Gets fragment instance used on page 0.

fragment0.updateFragment() method which include the updates on this fragment

adapter.instantiateItem(adapter.getContainer(), 0); // re-initialize page 0.

这个解决方案是基于Alvaro Luis Bustamante提出的技术。

所有这些答案对我都不起作用。

唯一对我有用的是,我必须再次将适配器设置为viewpager,然后它将刷新内容。

removeView(int pos)在我的PagerAdaper

public void removeView(int index) {
       imageFileNames.remove(index);
       notifyDataSetChanged();
}

无论我在哪里删除文件,我都必须这样做

imagePagerAdapter.removeView(currentPosition);
viewPager.setAdapter(imagePagerAdapter);

编辑:

下面的方法是有效的,你可以使用下面的方法。

public void updateView(int pos){
      viewPager.setAdapter(null);
      imagePagerAdapter =new ImagePagerAdapter(YOUR_CONTEXT,YOUR_CONTENT);
      viewPager.setAdapter(imagePagerAdapter);
      viewPager.setCurrentItem(pos);
}

用你的上下文替换你的YOUR_CONTEXT,用你的内容名称替换你的内容,即更新列表或其他东西。

我认为PagerAdapter中没有任何类型的错误。问题是,理解它是如何工作的有点复杂。看看这里解释的解决方案,从我的角度来看,有一个误解,因此实例化视图的使用很差。

在过去的几天里,我一直在使用PagerAdapter和ViewPager,我发现了以下内容:

PagerAdapter上的notifyDataSetChanged()方法只会通知ViewPager底层页面已经更改。例如,如果您动态地创建/删除页面(从列表中添加或删除项目),ViewPager应该负责这些。在这种情况下,我认为ViewPager决定是否应该使用getItemPosition()和getCount()方法删除或实例化一个新视图。

我认为ViewPager,在notifyDataSetChanged()调用后,它的子视图和检查他们的位置与getItemPosition()。如果对于子视图,该方法返回POSITION_NONE, ViewPager会认为该视图已被删除,并调用destroyItem()方法删除该视图。

通过这种方式,如果您只想更新页面的内容,覆盖getItemPosition()以总是返回POSITION_NONE是完全错误的,因为每次调用notifyDatasetChanged()时,以前创建的视图将被销毁,而新的视图将被创建。对于一些textview来说,这似乎没有什么问题,但是当你有复杂的视图时,比如从数据库中填充的listview,这可能是一个真正的问题和资源浪费。

So there are several approaches to efficiently change the content of a view without having to remove and instantiate the view again. It depends on the problem you want to solve. My approach is to use the setTag() method for any instantiated view in the instantiateItem() method. So when you want to change the data or invalidate the view that you need, you can call the findViewWithTag() method on the ViewPager to retrieve the previously instantiated view and modify/use it as you want without having to delete/create a new view each time you want to update some value.

例如,假设您有100个带有100个textview的页面,并且您只想定期更新一个值。使用前面解释的方法,这意味着您在每次更新时删除并实例化100个textview。这没有道理……

在我的情况下,在我的Viewpager中有一个textView,在mainActivity中单击按钮,我想改变textView的颜色并更新pagerAdapter。在按钮上单击“我在SharedPreference中保存了颜色”,并更新pagerAdapter,它可以更新从共享首选项中获取的颜色。我用下面的方式更新viewPager视图。

btn_purple.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int color = ContextCompat.getColor(mContext, R.color.colorPrimaryDark2);
                editor.putInt("sahittoFontColor", color);
                editor.apply();
                toNotifyDatasetChanged();
            }
        });

现在更新方法:

 private  void  toNotifyDatasetChanged (){
        if(viewPager!=null&& pagerAdapter!=null) {
            viewPager.setAdapter(null);
            viewPager.setAdapter(pagerAdapter);
           
        }

    }

我的pagerAdapter是:

pagerAdapter = new  Sahitto_ViewPagerAdapter (mContext, filenameParameter, 30, lineList);
                        viewPager.setAdapter(pagerAdapter);

并且在instantiateItem was(在PagerAdapter中):

    SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(mContext);
    int   bnfntcolor=settings.getInt("sahittoFontColor", 0);
if (bnfntcolor!=0){
    textView.setTextColor(bnfntcolor);
}

因此,当我点击按钮,颜色立即改变在pagerAdapter的Textview。

快乐的编码。