Come eliminare una scheda con ActionBar, ViewPager e più frammenti?
-
11-12-2019 - |
Domanda
Sto usando il codice che ho trovato qui .
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) {
}
}
}
.
Sto cercando di modificarlo in modo da poter cancellare le schede dinamicamente. Ho provato semplicemente creando questa funzione:
public void removeTab(ActionBar.Tab tab) {
mTabs.remove(tab);
mActionBar.removeTab(tab);
notifyDataSetChanged();
}
.
Ma ottengo sempre un'intinautifboundsexception. Qualcuno conosce un buon modo per farlo?
Modifica
cambiando il mio metodo per:
.
public void removeTab(ActionBar.Tab tab) {
mTabs.remove(tab.getTag());
mActionBar.removeTab(tab);
notifyDataSetChanged();
}
Sono stato in grado di rimuovere con successo le schede. Tuttavia, quando eliminisco una scheda che non è quella dell'estrema destra, la vista (o il frammento?) Che era associato alla scheda non va via. Invece, sembra essere associato alla seguente scheda più alta. Ad esempio, se ho cancellato la scheda 0, la visualizzazione della scheda 0, si sposta solo sulla scheda 1. Se eliminisco la scheda con l'ID più alto, quindi la scheda e la vista vanno via correttamente ma poi tornare quando aggiungo una nuova scheda.
È come se ci fosse un elenco di frammenti da qualche parte che viene associato alle schede e l'eliminazione della scheda non elimina il frammento. Qualcuno ha idea di ciò che sta causando questo?
Edit2
Ho provato a cancellare i frammenti con:
.
Fragment fragmentToRemove = getItem(tab.getPosition());
destroyItem(mViewPager, tab.getPosition(), fragmentToRemove);
e anche
.
Fragment fragmentToRemove = getItem(tab.getPosition());
FragmentTransaction fragmentTransaction = mActivity
.getSupportFragmentManager().beginTransaction();
fragmentTransaction.remove(fragmentToRemove);
fragmentTransaction.commit();
Ma nessuno dei due ha funzionato finora.
Soluzione
GOTTO!
public void removeTab(ActionBar.Tab tab) {
mTabs.remove(tab.getTag());
mActionBar.removeTab(tab);
notifyDataSetChanged();
}
.
e override Destroyitem
@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();
}
.
funziona perfettamente !!!
Altri suggerimenti
Ho appena scoperto oggi che il vero trucco per supportare l'inserimento o la rimozione delle schede è ignorare 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()
verrà chiamato dal ViewPager
dopo aver chiamato notifyDataSetChanged()
(dopo l'aggiunta / rimozione delle schede).Il ViewPager
sta cercando di resinserire la sua cache con questo adattatore.Chiama getItemPosition()
per ogni "oggetto" (frammento) che detiene, e lo diciamo in quale posizione proviene il frammento.Se non c'è una partita, è perché abbiamo eliminato quella scheda, quindi restituire POSITION_NONE
.
Ho anche trovato che è importante ignorare FragmentPagerAdapter.getItemId()
se si inseriscono o si rimuovono le linguette, perché i frammenti cambieranno le posizioni a sinistra ea destra.Questo metodo è chiamato da FragmentPagerAdapter.instantiateItem()
ed è aggiunto a un nome (stringa) per l'articolo.Utilizza questo nome per cercare un frammento preesistente con un nome corrispondente (se ce ne è uno) altrimenti istanziare uno nuovo.Ecco alcuni codici:
@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 - questo ha mangiato il mio pranzo per 2 settimane.Non ho trovato che quanto sopra ha funzionato per me esattamente come mostrato.Sto usando Android Studio 3.5.1 nel caso in cui questioni.
Quello che segue è il mio codice frammentpageradapter nella sua interezza.Contiene la maggior parte di tutto ciò che dovresti aver bisogno.Il codice frammento è abbastanza semplice per qualsiasi cosa contenga ciascuno dei tuoi frammenti.Ma fammi sapere se è richiesto di più o se avete domande.
Inoltre, se avete commenti o trovare eventuali errori, pubblica un commento.Spero che questo aiuti gli altri.
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());
}
}
.