如何使用viewpager2和fragmentstateadapter动态添加和删除片段?

huangapple go评论82阅读模式
英文:

How do I dynamically add and delete fragments with viewpager2 and fragmentstateadapter?

问题

以下是您提供的代码的翻译部分:

所以我一直在尝试在我的应用程序中动态添加和删除片段已经几个月了我最近迁移到了viewpager2和fragmentstateadapter但没有成功我的目标是完全删除特定位置的一个片段但有能力在列表末尾添加一个新的片段而不带有先前的数据然而当我这样做时应用程序会复制片段这是我的适配器代码

package com.dc.shark_reel_t5.ui.main;

import android.content.Intent;
import android.content.Context;
import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.Lifecycle;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager2.adapter.FragmentStateAdapter;

import com.dc.shark_reel_t5.R;

import java.util.ArrayList;

/**
 * 返回与选项卡/标签/页面之一对应的片段的[FragmentPagerAdapter]。
 */
public class SectionsPagerAdapter extends FragmentStateAdapter {

    private FragmentManager mFragmentManager;
    private FragmentTransaction currTransaction = null;
    private int count = 0;
    private ArrayList<String> mTitles = new ArrayList<String>();
    private ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
    private ArrayList<Integer> mFragmentIDs = new ArrayList<Integer>();

    public SectionsPagerAdapter(FragmentManager fm, Lifecycle lc) {
        super(fm, lc);
        mFragmentManager = fm;
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        return mFragments.get(position);
    }

    @Nullable
    public CharSequence getPageTitle(int position) { return (CharSequence) mTitles.get(position); }

    public String getTitle(int position) {
        return mTitles.get(position);
    }

    //动态(运行时)方法:

    //在调用时,在UI的列表末尾添加一个钩子(尚未更改后端变量)
    public void addHookFrag(){
        mTitles.add("Hook " + (mFragments.size() + 1));
        PlaceholderFragment currFrag = PlaceholderFragment.newInstance(mFragments.size() + 1);
        mFragmentIDs.add(currFrag.getId());
        mFragments.add(currFrag);
        notifyItemInserted(mFragments.size()-1);
    }

    public void delHookFrag(int position){
        mFragments.remove(position);
        mFragmentIDs.remove(position);
        notifyDataSetChanged();
    }

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

    @Override
    public long getItemId(int position){
        if(position >= getItemCount() || position < 0)
            return RecyclerView.NO_ID;

        return mFragmentIDs.get(position);
    }

    @Override
    public boolean containsItem(long itemId){
        return mFragmentIDs.contains((int)itemId);
    }
}

请注意,我已经将代码中的HTML实体(如&quot;)翻译为正常的引号。如果您需要更多帮助或有其他问题,请随时提问。

英文:

so I've been trying to dynamically add and delete fragments from my application for months now. I recently migrated over to viewpager2 and fragmentstateadapter but to no avail. My goal is to delete a fragment at a specific location completely, but have the ability to add a new fragment to the end of the list with no previous data. When I do this however, the application duplicates fragments. Here is my adapter code:

package com.dc.shark_reel_t5.ui.main;
import android.content.Intent;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.Lifecycle;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import com.dc.shark_reel_t5.R;
import java.util.ArrayList;
/**
* A [FragmentPagerAdapter] that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentStateAdapter {
private FragmentManager mFragmentManager;
private FragmentTransaction currTransaction = null;
private int count = 0;
private ArrayList&lt;String&gt; mTitles = new ArrayList&lt;String&gt;();
private ArrayList&lt;Fragment&gt; mFragments = new ArrayList&lt;Fragment&gt;();
private ArrayList&lt;Integer&gt; mFragmentIDs = new ArrayList&lt;Integer&gt;();
public SectionsPagerAdapter(FragmentManager fm, Lifecycle lc) {
super(fm, lc);
mFragmentManager = fm;
}
@NonNull
@Override
public Fragment createFragment(int position) {
return mFragments.get(position);
}
@Nullable
public CharSequence getPageTitle(int position) { return (CharSequence) mTitles.get(position); }
public String getTitle(int position) {
return mTitles.get(position);
}
//Dynamic(runtime) methods:
//On call: adds a hook to the end of the list in UI(DOES NOT CHANGE BACK END VARIABLES YET)
public void addHookFrag(){
mTitles.add(&quot;Hook &quot; + (mFragments.size() + 1));
PlaceholderFragment currFrag = PlaceholderFragment.newInstance(mFragments.size() + 1);
mFragmentIDs.add(currFrag.getId());
mFragments.add(currFrag);
notifyItemInserted(mFragments.size()-1);
}
public void delHookFrag(int position){
mFragments.remove(position);
mFragmentIDs.remove(position);
notifyDataSetChanged();
}
@Override
public int getItemCount() {
return mFragments.size();
}
@Override
public long getItemId(int position){
if(position &gt;= getItemCount() || position &lt; 0)
return RecyclerView.NO_ID;
return mFragmentIDs.get(position);
}
@Override
public boolean containsItem(long itemId){
return mFragmentIDs.contains((int)itemId);
}
}

Thanks.

答案1

得分: 4

我开发了一个解决方案。原来传递给containsItem的ID来自getItemID,因此整个系统依赖程序员提出创建唯一ID的方法。我使用了一个计数器,因为唯一应该区分这些片段的唯一因素是时间顺序,在这种情况下是线性增加的。以下是帮助我的适配器的相关属性:

public class SectionsPagerAdapter extends FragmentStateAdapter {

...

    private int idGen = 0;

    @Override
    public long getItemId(int position) {
        return (long)mFragmentIDs.get(position);
    }

    @Override
    public boolean containsItem(long itemId) {
        return mFragmentIDs.contains((int)itemId);
    }

...

}

我没有在这里展示,但我管理了一个片段ID列表。当添加新的片段时,我递增idGen并将递增的值添加到列表中。当删除时,我从各自的列表中删除ID和片段,同时更新所有受影响的片段的部分编号(在您的片段类中使用setter方法轻松完成)。祝大家解决这个问题好运,花了我足够长的时间!

英文:

I developed a solution. It turns out the ID that is passed to containsItem is from getItemID, so the whole system relies on the programmer to come up with a method for creating unique IDs. I used a counter, because the only thing that should differentiate the fragments is chronological order, which in this case increases linearly. Here are the pertinent attributes of my adapter that helped me:

public class SectionsPagerAdapter extends FragmentStateAdapter {
...
private int idGen = 0;
@Override
public long getItemId(int position) {
return (long)mFragmentIDs.get(position);
}
@Override
public boolean containsItem(long itemId) {
return mFragmentIDs.contains((int)itemId);
}
...
}

I do not show it here, but I manage a list of Fragment IDs. When adding a new fragment, I increment idGen and add the incremented value to the list. When deleting, I remove the ID and the fragment from their respective lists, as well as updating the section number of all effected fragments(easily done with a setter method in your fragment class). Good luck to all with this problem, took me long enough!

答案2

得分: 0

以下是翻译好的内容:

以下的代码中使用了 FragmentStateAdapter。Viewpager2 使用 RecyclerView 来重用视图。您可以向数据列表添加一个新页面,然后使用 notifyDataSetChanged 或 notifyItemInserted 方法将新页面添加到 ViewPager 中。同样,notifyItemRemoved 可以用于动态从某个位置删除页面并调整 ViewPager。

class StoriesPagerAdapter(fragment: Fragment, var dataList: MutableList<Content> = mutableListOf()) : FragmentStateAdapter(fragment) {
    override fun getItemCount(): Int {
        return dataList.size
    }

    override fun createFragment(position: Int): Fragment {
        return StoryViewFragment.newInstance(dataList[position], position)
    }

    companion object {
        var currentItem = 0
            get() = field
            set(value) {
                field = value
            }
    }
}
英文:

> The below code has the FragmentStateAdapter. Viewpager2 uses recycler view to reuse the views. You can add a new page to the data list and use notifyDataSetChanged or notifyItemInserted method to add a new page to the viewpager. Likewise notifyItemRemoved can be used to dynamically remove a page from the position and adjust the viewpager

class StoriesPagerAdapter(fragment: Fragment, var dataList:MutableList&lt;Content&gt; = mutableListOf()) : FragmentStateAdapter(fragment) {
override fun getItemCount(): Int {
return dataList.size
}
override fun createFragment(position: Int): Fragment {
return StoryViewFragment.newInstance(dataList[position], position)
}
companion object {
var currentItem = 0
get() = field
set(value) {
field = value
}
}}

huangapple
  • 本文由 发表于 2020年8月11日 01:25:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/63345065.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定