Comment faire pour supprimer un onglet avec actionbar, viewpager, et de multiples fragments?
-
11-12-2019 - |
Question
Je suis en utilisant le code que j'ai trouvé ici.
public class ActionBarTabs extends SherlockFragmentActivity {
CustomViewPager mViewPager;
TabsAdapter mTabsAdapter;
TextView tabCenter;
TextView tabText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
mViewPager = new CustomViewPager(this);
mViewPager.setId(R.id.pager);
setContentView(mViewPager);
ActionBar bar = getSupportActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter.addTab(bar.newTab().setText("Home"),
ToolKitFragment.class, null);
mTabsAdapter.addTab(bar.newTab().setText("FujiSan"),
FujiFragment.class, null);
}
public static class TabsAdapter extends FragmentPagerAdapter implements
ActionBar.TabListener, ViewPager.OnPageChangeListener {
private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo {
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
public TabsAdapter(SherlockFragmentActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getSupportActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();
}
@Override
public int getCount() {
return mTabs.size();
}
@Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(),
info.args);
}
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i = 0; i < mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
}
@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
}
}
Je suis en train de le modifier, de sorte que je peux supprimer les onglets de façon dynamique.J'ai essayé par tout simplement la création de cette fonction:
public void removeTab(ActionBar.Tab tab) {
mTabs.remove(tab);
mActionBar.removeTab(tab);
notifyDataSetChanged();
}
Mais j'obtiens toujours un indexoutofboundsexception.Quelqu'un sait-il une bonne façon de le faire?
MODIFIER
En changeant ma méthode:
public void removeTab(ActionBar.Tab tab) {
mTabs.remove(tab.getTag());
mActionBar.removeTab(tab);
notifyDataSetChanged();
}
J'ai pu réussir à supprimer des onglets.Cependant, quand je supprime un onglet qui n'EST PAS celle de l'extrême droite, la vue (ou fragment?) qui a été associée à l'onglet ne va pas loin.Au lieu de cela, il semble être associée avec le deuxième plus haut de l'onglet.Par exemple, si j'ai supprimé l'onglet 0, tab 0 de vue se déplace vers l'onglet 1.Si je supprime l'onglet avec les ID les plus élevés puis sur l'onglet et afficher en aller correctement, mais ensuite, revenez quand j'ajoute un nouvel onglet.
C'est comme si il y a une liste de fragments de quelque part qui est associé avec les onglets et la suppression de l'onglet ne pas supprimer le fragment.Quelqu'un aurait-il une idée de ce qui cause cela?
EDIT2
J'ai essayé de supprimer les fragments avec:
Fragment fragmentToRemove = getItem(tab.getPosition());
destroyItem(mViewPager, tab.getPosition(), fragmentToRemove);
et aussi
Fragment fragmentToRemove = getItem(tab.getPosition());
FragmentTransaction fragmentTransaction = mActivity
.getSupportFragmentManager().beginTransaction();
fragmentTransaction.remove(fragmentToRemove);
fragmentTransaction.commit();
Mais aucune n'a fonctionné jusqu'ici.
La solution
obtenu!
public void removeTab(ActionBar.Tab tab) {
mTabs.remove(tab.getTag());
mActionBar.removeTab(tab);
notifyDataSetChanged();
}
et remplacement destructitem
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
// TODO Auto-generated method stub
super.destroyItem(container, position, object);
FragmentManager manager = ((Fragment) object).getFragmentManager();
FragmentTransaction trans = manager.beginTransaction();
trans.remove((Fragment) object);
trans.commit();
}
fonctionne parfaitement !!!
Autres conseils
Je viens de découvrir aujourd'hui que le vrai truc à soutenir l'insertion ou la suppression des onglets est à remplacer FragmentPagerAdapter.getItemPosition()
:
@Override
public int getItemPosition(Object object) {
Fragment fragment = (Fragment) object;
for (int i = 0; i < tabInfos.size(); i++) {
if (tabInfos.get(i).clss == fragment.getClass()) {
return i;
}
}
// The tab must have been removed
return POSITION_NONE;
}
getItemPosition()
sera appelé par le ViewPager
après avoir appelé notifyDataSetChanged()
(après l'ajout/la suppression des tabulations).L' ViewPager
essaie de resynchroniser son cache avec cet adaptateur.Il appelle getItemPosition()
pour chaque "objet" (Fragment) qu'il détient, et nous dire quelle est la position de ce Fragment est de.Si aucune correspondance n'est trouvée, c'est parce que nous avons supprimé cet onglet, donc retour POSITION_NONE
.
J'ai aussi trouvé qu'il est important de remplacer FragmentPagerAdapter.getItemId()
si vous insérez ou supprimer des onglets, parce que les Fragments seront changements de positions de gauche et de droite.Cette méthode est appelée par FragmentPagerAdapter.instantiateItem()
et est ajouté à un nom (Chaîne de caractères) pour l'élément.Il utilise ce nom pour rechercher une pré-existant Fragment avec un nom correspondant (si il y en a un) sinon instancier un nouveau.Voici un code:
@Override
public long getItemId(int position) {
TabInfo info = tabInfos.get(position);
// The default hashCode() implementation is based on memory address, which will be unique
int hash = info.clss.hashCode();
return hash;
}
OK - Celui-ci a mangé mon déjeuner pendant 2 semaines.Je n'ai pas trouvé que ce qui précède a travaillé pour moi du tout comme indiqué.J'utilise Android Studio 3.5.1 au cas où cela importe.
Que suit est mon code de fragmentpageradapter dans son intégralité.Il contient la plupart de tout ce dont vous devriez avoir besoin.Le code de fragment est assez simple pour que chacun de vos fragments contienne.Mais laissez-moi savoir si plus est requis ou si vous avez des questions.
En outre, si vous avez des commentaires ou trouvez des erreurs, veuillez poster un commentaire.J'espère que cela aide les autres.
import android.content.Context;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.fragment.app.FragmentTransaction;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.tabs.TabLayout;
import java.util.ArrayList;
public class ChecklistPagerAdapter extends FragmentPagerAdapter {
private final Context mContext;
private int currentTabPosition = -1;
ArrayList<String> tabNames = new ArrayList<>();
ArrayList<Fragment> fragments = new ArrayList<>();
public ChecklistPagerAdapter(Context context, FragmentManager fm) {
super(fm);
mContext = context;
}
public void add(Fragment fragment, String title) {
tabNames.add(title);
fragments.add(fragment);
}
public int getCurrentTabPosition() {
return currentTabPosition;
}
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getItemPosition(@NonNull Object object) {
ChecklistFragment fragment = (ChecklistFragment) object;
for (int i = 0; i < fragments.size(); i++) {
if (fragments.get(i).equals(fragment)) {
return i;
}
}
return POSITION_NONE;
}
@Override
public long getItemId(int position) {
return fragments.get(position).hashCode();
}
@Override
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
super.setPrimaryItem(container, position, object);
currentTabPosition = position;
}
@Nullable
@Override
public CharSequence getPageTitle(int position) {
return tabNames.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
public void removeTab(TabLayout tabLayout, ViewPager viewPager, DBHelper dbHelper) {
// Get current tab position as it changes below
int position = currentTabPosition;
// Get current fragment representing curTab
ChecklistFragment fragment = (ChecklistFragment) fragments.get(position);
// Remove Tab
tabLayout.removeTabAt(position);
// Remove from ArrayLists
fragments.remove(position);
tabNames.remove(position);
// Remove fragment
FragmentManager fragmentManager = fragment.getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.remove(fragment);
fragmentTransaction.commit();
// Refresh
tabLayout.invalidate();
notifyDataSetChanged();
// Remove all records from ChecklistTab table
dbHelper.clearChecklistTab(fragment.getOutingId(), fragment.getChecklistId());
}
}