我正在用viewpager2和FragmentStateAdapter制作一个文件选择页面。在其中一个页面中,我显示了所有挂载的存储设备,我希望在这些设备上点击查看内容,但希望内容位于另一个片段上。
我想用viewpager最后一页中的另一个替换片段。但是使用下面的代码,页面只是刷新,并且不会创建新的片段,因为createFragment
不会被调用。
我的PagerAdapter
public static class PagerAdapter extends FragmentStateAdapter {
private Fragment mFragmentAtPos0;
private final FragmentManager mFragmentManager;
private final FirstPageListener listener = new FirstPageListener();
public final class FirstPageListener implements
FirstPageFragmentListener {
public void onSwitchToNextFragment() {
mFragmentManager.beginTransaction().remove(mFragmentAtPos0)
.commit();
if (mFragmentAtPos0 instanceof FilesandFolder_Others_MainPage){
mFragmentAtPos0 = new FileExplorer(listener);
}else{ // Instance of NextFragment
mFragmentAtPos0 = new FilesandFolder_Others_MainPage(listener);
}
notifyDataSetChanged();
}
public void onSwitchToNextFragment(Bundle bundle) {
// mFragmentManager.beginTransaction().remove(mFragmentAtPos0)
// .commit();
if (mFragmentAtPos0 instanceof FilesandFolder_Others_MainPage){
mFragmentAtPos0 = new FileExplorer(listener);
mFragmentAtPos0.setArguments(bundle);
}else{ // Instance of NextFragment
mFragmentAtPos0 = new FilesandFolder_Others_MainPage(listener);
mFragmentAtPos0.setArguments(bundle);
}
notifyDataSetChanged();
// notifyItemChanged(getItemPosition(mFragmentAtPos0));
}
}
// @Override
// public void onBindViewHolder(@NonNull FragmentViewHolder holder, int position, @NonNull List<Object> payloads) {
// super.onBindViewHolder(holder, position, payloads);
// if (position == getItemPosition(mFragmentAtPos0)) {
//
// Fragment f = mFragmentManager.findFragmentByTag("f" + holder.getItemId());
// if (f != null) {
// mFragmentManager.beginTransaction().replace(holder.getItemId(), )
// }
// }
// }
private int getItemPosition(Fragment mFragmentAtPos0) {
for (int i = 0; i < getItemCount(); i++){
if (createFragment(i).equals(mFragmentAtPos0)){
return i;
}
}
return -1;
}
public PagerAdapter(FragmentActivity fm) {
super(fm);
mFragmentManager = fm.getSupportFragmentManager();
mFragmentAtPos0 = new FilesandFolder_Others_MainPage(listener);
}
@NonNull
@Override
public Fragment createFragment(int position) {
switch (position){
case 0:
return new AppSelectionFragment();
case 1:
return new Photos();
case 2:
return new VideoGalleryFragment();
case 3:
return new Gallery();
default:
return mFragmentAtPos0;
}
}
@Override
public int getItemCount() {
return 5;
}
}
下面是我想要替换为另一个片段的片段的构造函数:
private static FileSelection.PagerAdapter.FirstPageListener pageFragmentListener;
public FilesandFolder_Others_MainPage() {
}
public FilesandFolder_Others_MainPage(FileSelection.PagerAdapter.FirstPageListener firstPageFragmentListener) {
pageFragmentListener = firstPageFragmentListener;
}
在点击视图时,应该调用以下代码:
Bundle bundle = new Bundle();
bundle.putString("PATH", volumes.get(position).path);
pageFragmentListener.onSwitchToNextFragment(bundle);
我已经搜索了所有的堆栈溢出,但从来没有看到一个正确的答案与Viewpager2和FragmentStateAdapter,因为似乎每个人都在使用Viewpager.
我试图实现这一点:- FragmentStateAdapter for ViewPager2 notifyItemChanged not working as expected
但无法理解如何编辑我的代码。请帮助提前感谢!
发布于 2020-08-26 13:28:02
也有同样的问题,这就是我发现的:
FragmentStateAdapter
有onBindViewHolder(holder, position, payloads)
方法,你可以重写它(与onBindViewHolder(holder, position)
不同,它是最终的)。此方法在您调用notify
方法时调用,对于notifyItemChanged()
、notifyItemRangeChanged()
方法,您可以访问片段并手动更新它。
下面是访问该片段的代码:
public void onBindViewHolder(@NonNull FragmentViewHolder holder, int position, @NonNull List<Object> payloads) {
String tag = "f" + holder.getItemId();
Fragment fragment = fragmentManager.findFragmentByTag(tag);
if (fragment != null) {
//manual update fragment
} else {
// fragment might be null, if it`s call of notifyDatasetChanged()
// which is updates whole list, not specific fragment
super.onBindViewHolder(holder, position, payloads);
}
}
FragmentStateAdapter
被"f" + holder.getItemId()
标记了他的片段,这就是它工作的原因。
你也可以使用DiffUtil
,这是更好的方式。解决这个问题的Here is good example,以及最后的一些链接,以便更好地理解ViewPager2
。
发布于 2021-01-31 01:52:40
我今天也遇到了同样的问题,我想我会在这里分享我的解决方案。我的解决方案不是拦截onBindViewHolder()
,而是简单地替换旧的片段:
OldFragment.instance.containerId?.let {
replace(it, NewFragment.instance)
}
更具体地说:
我的应用程序有一个包含两个片段的ViewPager2。我们称它们为MainFragment
和DetailFragment
。在MainFragment
中单击按钮时,我想用SecondMainFragment
替换它。同样的行为反之亦然:SecondMainFragment
中的按钮点击会用MainFragment
替换它自己。
class CustomFragmentStateAdapter(
private val fragmentActivity: FragmentActivity
) : FragmentStateAdapter(fragmentActivity) {
var displaySecondMainFragment: Boolean = false
set(value) {
if (field != value) {
switchFragments(replaceWithSecondMainFragment = value)
}
field = value
}
private fun switchFragments(replaceWithSecondMainFragment: Boolean) {
fragmentActivity.supportFragmentManager.commit {
if (replaceWithSecondMainFragment) {
MainFragment.instance.containerId?.let {
replace(it, SecondMainFragment.instance)
}
} else {
SecondMainFragment.instance.containerId?.let {
replace(it, MainFragment.instance)
}
}
}
}
// Standard adapter overrides
override fun getItemCount(): Int = 2
override fun createFragment(position: Int): Fragment = when (position) {
0 -> if (displaySecondMainFragment) SecondMainFragment.instance else MainFragment.instance
else -> DetailFragment.instance
}
}
使用此扩展属性来获取片段所在容器的id:
inline val Fragment.containerId: Int?
get() = (view?.parent as? ViewGroup?)?.id
最后,我只需要做这样的事情:
button.setOnClickListener {
customFragmentStateAdapter.displaySecondMainFragment = true // Or false for the other way
}
发布于 2021-11-18 13:15:36
您可以重写这两个方法
override fun getItemId(position: Int): Long {
// generate new id
return getItem(position).hashCode().toLong()
}
override fun containsItem(itemId: Long): Boolean {
// false if item is changed
return dataList.find { it.hashCode().toLong() == itemId } != null
}
https://stackoverflow.com/questions/62880883
复制相似问题