Как динамически добавлять и удалять фрагменты с помощью viewpager2 и 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;

/**
 * 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<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);
    }

    //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("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);
    }

}

Спасибо.


person JagidEdge    schedule 10.08.2020    source источник
comment
Попробуйте это stackoverflow.com/a/66932869/10053046   -  person Mihae Kheel    schedule 03.04.2021


Ответы (2)


Я разработал решение. Оказывается, идентификатор, который передается в containsItem, получен от getItemID, поэтому вся система полагается на то, что программист придумает метод создания уникальных идентификаторов. Я использовал счетчик, потому что единственное, что должно различать фрагменты, — это хронологический порядок, который в данном случае увеличивается линейно. Вот соответствующие атрибуты моего адаптера, которые мне помогли:

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);
    }

...

}

Я не показываю его здесь, но я управляю списком идентификаторов фрагментов. При добавлении нового фрагмента я увеличиваю idGen и добавляю увеличенное значение в список. При удалении я удаляю идентификатор и фрагмент из соответствующих списков, а также обновляю номер раздела всех затронутых фрагментов (это легко сделать с помощью метода установки в вашем классе фрагментов). Удачи всем с этой проблемой, у меня это заняло достаточно времени!

person JagidEdge    schedule 11.08.2020
comment
почему ты не показал это здесь? - person Ahmed Awadallah; 15.03.2021

В приведенном ниже коде есть FragmentStateAdapter. Viewpager2 использует представление recycler для повторного использования представлений. Вы можете добавить новую страницу в список данных и использовать метод notifyDataSetChanged или notifyItemInserted, чтобы добавить новую страницу в окно просмотра. Точно так же notifyItemRemoved можно использовать для динамического удаления страницы с позиции и настройки окна просмотра.

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
        }
}}
person user3455150    schedule 10.08.2020
comment
Есть ли способ преобразовать это в исходный код Java? я котлин еще не выучил - person JagidEdge; 10.08.2020
comment
Также это не влияет на удаление или добавление. - person JagidEdge; 10.08.2020