从ViewPager更新Fragment

63

我有一个带有ViewPagerActivity。我还有一个Dialog,将检索一个包含用户将选择的某些项的列表。现在,我应该如何更新Fragment,以便于这个Fragment附加新视图来显示这些项?

这是我的ViewPager适配器:

public static class MyAdapter extends FragmentPagerAdapter {
    public MyAdapter(FragmentManager fm) {
        super(fm);
    }

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

    @Override
    public android.support.v4.app.Fragment getItem(int position) {
        switch (position) {
        case 0:
            return new Fragment1();

        default:
            return null;
        }
    }
}

现在,这里是Fragment

public class Fragment1 extends Fragment{

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onActivityCreated(savedInstanceState);
}

@Override
public void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
}

@Override
public ViewGroup onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    ViewGroup view = (ViewGroup)inflater.inflate(R.layout.screen1, container, false);
    }
    return view;
}

}

这是我想用来向我的Fragment中添加项目的方法。

private void addItem() {

    // Instantiate a new "row" view.

    final ViewGroup[] newViews = new ViewGroup[selectedItems.length];


    for(int i = 0; i < selectedItems.length; i++){
        newViews[i] = (ViewGroup) LayoutInflater.from(this).inflate(
                    R.layout.animated_layout_item, mContainerView, false);

        // Set the text in each new row.
        ((TextView) newViews[i].findViewById(android.R.id.text1)).setText(selectedItems[i]);

        // Because mContainerView has android:animateLayoutChanges set to true,
        // adding this view is automatically animated.

            mContainerView.addView(newViews[i], 0);


        // Set a click listener for the "X" button in the row that will remove the row.
        OnClickListener listener = new MyAddItemListener(newViews[i], mContainerView, this);
        newViews[i].findViewById(R.id.delete_button).setOnClickListener(listener);

    }


}

在Fragment1的onCreateView方法中,为什么要写"ViewGroup view = view = "? - MiStr
这是个打错字,请让我来更正。谢谢你注意到了它。 - Luis Lavieri
https://github.com/pchauhan/RefreshFragementViewPager - Parag Chauhan
15个回答

139

从ViewPager更新片段

你需要实现getItemPosition(Object obj)方法。

当你调用时,将会调用这个方法。

notifyDataSetChanged()

在你的ViewPagerAdaper上。隐式地,这个方法返回POSITION_UNCHANGED的值,意思是:

"Fragment在它应该呆的地方,所以不要更改任何东西。"

所以如果你需要更新Fragment,你可以这样做:

  • 始终从getItemPosition()方法中返回POSITION_NONE。这意味着:"Fragment必须总是被重新创建"
  • 您可以创建一些update()方法来更新您的Fragment(Fragment将处理更新本身)

第二种方法的示例:

public interface Updateable {
   public void update();
}


public class MyFragment extends Fragment implements Updateable {

   ...

   public void update() {
     // do your stuff
   }
}

在 FragmentPagerAdapter 中,你可以像这样做:

@Override
public int getItemPosition(Object object) {
   MyFragment f = (MyFragment ) object;
   if (f != null) {
      f.update();
   }
  return super.getItemPosition(object);
}

如果你选择第一种方法,它可能会看起来像这样:

@Override
public int getItemPosition(Object object) {
   return POSITION_NONE;
}

注意:值得考虑选择哪种方法。


4
你应该这样调用: yourPager.getAdapter().notifyDataSetChanged() - Simon Dorociak
谢谢@Sajmon,但是我调用它时会抛出空指针异常,你认为可能是什么原因呢? - Luis Lavieri
2
很好。经过艰苦努力,终于成功了。谢谢伙计。问题出在我的“mContainerView”上; 它没被正确地实例化。 - Luis Lavieri
2
+1 表示 @Override public int getItemPosition(Object object) { return POSITION_NONE; } - Emre Koç
1
我在FragmentPagerAdapter中有5个片段。我尝试了两种解决方案,但都没有起作用,因为每次我滑动时MyFragment都会被多次调用。如果有人找到解决方案,请帮忙。 - piyush poriya
显示剩余15条评论

33

我有时会遇到问题,在这种情况下,要始终避免使用FragmentPagerAdapter,改用FragmentStatePagerAdapter。

对我很有帮助,希望对你也有用。


1
谢谢 :) 我可以使用这个适配器创建动态选项卡。 - busetekin

15

我按照Sajmon的答案实现了一个应用程序演示,供其他搜索此问题的人使用。

您可以在GitHub上访问源代码。

输入图像描述


14

在你的PagerAdapter中覆盖getItemPosition方法。

@Override
public int getItemPosition(Object object) {
// POSITION_NONE makes it possible to reload the PagerAdapter
return POSITION_NONE;
}

在此之后,像下面这样添加viewPager.getAdapter().notifyDataSetChanged();这行代码。

viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        }

        @Override
        public void onPageSelected(int position) {
            viewPager.getAdapter().notifyDataSetChanged();
        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });

应该可以工作。


2
它可以工作,但在选项卡之间切换时,用户界面开始变得缓慢。谢谢。 - InfZero

5
你可以通过两种不同的方式更新片段, 第一种方式 像@Sajmon一样
你需要实现getItemPosition(Object obj)方法。
当你调用这个方法时,会调用这个方法。
notifyDataSetChanged()

你可以在 Github 找到一个示例,并在这篇文章中获取更多信息。

enter image description here

第二种方法

我更新 viewpager 中的 fragment 的方式是使用 instantiateItem() 方法中实例化的任何视图的 setTag() 方法。所以当你想要改变数据或使需要的视图无效时,你可以在 ViewPager 上调用 findViewWithTag() 方法来检索先前实例化的视图并修改 / 使用它,而不必每次想要更新一些值时删除 / 创建新视图。

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Object object = super.instantiateItem(container, position);
    if (object instanceof Fragment) {
        Fragment fragment = (Fragment) object;
        String tag = fragment.getTag();
        mFragmentTags.put(position, tag);
    }
    return object;
}

public Fragment getFragment(int position) {
    Fragment fragment = null;
    String tag = mFragmentTags.get(position);
    if (tag != null) {
        fragment = mFragmentManager.findFragmentByTag(tag);
    }
    return fragment;
}

您可以在Github上找到一个示例,或在此文章中获取更多信息:

enter image description here


4

在片段中覆盖方法非常简单:

@Override

public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);

    if(isVisibleToUser){
        actionView();
    }
    else{
        //no
    }      
}

目前这个答案已经过时了,请查看Simon的答案,那个更正确。 - luke cross

3

原回答不易理解,因此提供了简单的解决方法。经过长时间的努力后,找到了可行的解决方案。

只需通知您的适配器,它会出奇迹般地运作。

参考代码

 void setAdapter(int position) {
        PagerAdapter pagerAdapter = new PagerAdapter(getSupportFragmentManager());
        viewPager.setAdapter(pagerAdapter);
        // when notify then set manually current position.
        viewPager.setCurrentItem(position);
        pagerAdapter.notifyDataSetChanged();
    }

当您设置适配器并希望刷新UI时,请调用此代码。

在您的片段中添加此代码以进行刷新

((YourActivityName) getContext()).setAdapter(selectedTabPosition);

使用 instanceof 进行类型转换。

此代码仅为帮助寻找解决方案的人而共享。


2

一种非常简单但有效的解决方案是使用setUserVisibleHint()方法来更新片段视图。当片段将要对用户可见时,该方法将被调用。在那里,您可以更新视图(setText()setVisibility()等)。

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);

    if(isVisibleToUser){
       //Write your code to be executed when it is visible to user
    }
}

在我的情况下它起作用了,希望它能够帮到你!


2
如果您使用Kotlin,可以执行以下操作:
1. 首先,您应该创建一个“接口”,并在您的“片段”中实现它。
interface RefreshData {
    fun refresh()
}

class YourFragment : Fragment(), RefreshData {
    ...
    override fun refresh() {
        //do what you want
    }
}

2. 下一步 是将 OnPageChangeListener 添加到您的 ViewPager 中。

viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
    override fun onPageScrollStateChanged(state: Int) { }

    override fun onPageSelected(position: Int) {
        viewPagerAdapter.notifyDataSetChanged()
        viewPager.currentItem = position
    }

    override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { }
})

3. 重写 Adapter 中的 getItemPosition

override fun getItemPosition(obj: Any): Int {
    if (obj is RefreshData) {
        obj.refresh()
    }
    return super.getItemPosition(obj)
}

2
我在ViewPager中有4个Fragment,但我想每次用户点击位于ViewPager位置0的“FavoriteFragment”时仅更新此Fragment。 但是,上述所有代码都没有帮助我重新加载所需的单个Fragment。 因此,我尝试了以下方法,并且成功了:
在我的FavoriteFragment中,我重写了onResume()函数。Original Answer翻译成"最初的回答"。
@Override
    public void onResume() {
        super.onResume();
        updateUI(); // code to update the UI in the fragment
    }

在托管viewPager的Activity中,重写addOnPageChangeListener()并添加以下代码: "最初的回答"
mViewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                super.onPageSelected(position);

                if(position == 0) { // 0 = the first fragment in the ViewPager, in this case, the fragment i want to refresh its UI
                    FavoritesFragment fragment = (FavoritesFragment) mViewPager.getAdapter().instantiateItem(mViewPager, position); 
                    fragment.onResume(); // here i call the onResume of the fragment, where i have the method updateUI() to update its UI
                    mViewPager.getAdapter().notifyDataSetChanged();
                }
            }
        });

对我来说,它非常完美,可以刷新/重新加载我想要的片段。

原始答案: "最初的回答"


感谢分享解决方案 :) - Daxesh Vekariya

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接