Pergunta

Estou usando o código que encontrei aqui.

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

Estou tentando modificá-lo para poder excluir guias dinamicamente.Eu tentei simplesmente criando esta função:

    public void removeTab(ActionBar.Tab tab) {
        mTabs.remove(tab);
        mActionBar.removeTab(tab);
        notifyDataSetChanged();
    }

Mas sempre recebo uma exceção indexoutofbound.Alguém sabe uma boa maneira de fazer isso?

EDITAR

Mudando meu método para:

    public void removeTab(ActionBar.Tab tab) {
        mTabs.remove(tab.getTag());
        mActionBar.removeTab(tab);
        notifyDataSetChanged();
    }

Consegui remover as guias com sucesso.No entanto, quando excluo uma guia que NÃO É a da extrema direita, a visualização (ou fragmento?) que estava associada à guia não desaparece.Em vez disso, parece estar associado à próxima guia mais alta.Por exemplo, se eu excluí a guia 0, a visualização da guia 0 apenas passa para a guia 1.Se eu excluir a guia com o ID mais alto, a guia e a visualização desaparecerão corretamente, mas VOLTARÃO quando eu adicionar uma nova guia.

É como se houvesse uma lista de fragmentos em algum lugar que está sendo associada às guias e excluir a guia não exclui o fragmento.Alguém tem alguma ideia do que está causando isso?

EDITAR2

Tentei excluir os fragmentos com:

            Fragment fragmentToRemove = getItem(tab.getPosition());
            destroyItem(mViewPager, tab.getPosition(), fragmentToRemove);

e também

        Fragment fragmentToRemove = getItem(tab.getPosition());
        FragmentTransaction fragmentTransaction = mActivity
                .getSupportFragmentManager().beginTransaction();
        fragmentTransaction.remove(fragmentToRemove);
        fragmentTransaction.commit();

Mas nenhum dos dois funcionou até agora.

Foi útil?

Solução

Entendi!

public void removeTab(ActionBar.Tab tab) {
    mTabs.remove(tab.getTag());
    mActionBar.removeTab(tab);
    notifyDataSetChanged();
}

e substituir 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();
    }

Funciona perfeitamente!!!

Outras dicas

Acabei de descobrir hoje que o verdadeiro truque para suportar a inserção ou remoção de guias é substituir 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() será chamado pelo ViewPager depois que você ligou notifyDataSetChanged() (depois de adicionar/remover guias).O ViewPager está tentando ressincronizar seu cache com este adaptador.Ele chama getItemPosition() para cada 'objeto' (Fragmento) que ele contém, e nós informamos de qual posição esse Fragmento vem.Se não houver correspondência é porque excluímos aquela aba, então retorne POSITION_NONE.

Eu também descobri que é importante substituir FragmentPagerAdapter.getItemId() se você inserir ou remover abas, porque os fragmentos mudarão de posição para a esquerda e para a direita.Este método é chamado por FragmentPagerAdapter.instantiateItem() e é anexado a um nome (String) para o item.Ele usa esse nome para procurar um Fragment pré-existente com um nome correspondente (se houver), caso contrário, instancia um novo.Aqui está um código:

@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 - este comeu meu almoço por 2 semanas.Não achei que o procedimento acima funcionasse para mim exatamente como mostrado.Estou usando o Android Studio 3.5.1, caso isso seja importante.

O que se segue é meu código FragmentPagerAdapter na íntegra.Ele contém quase tudo que você precisa.O código do Fragment é bastante simples para tudo o que cada um dos seus fragmentos contém.Mas deixe-me saber se for necessário mais ou se você tiver alguma dúvida.

Além disso, se você tiver algum comentário ou encontrar algum erro, poste um comentário.Espero que isso ajude outros.

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());
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top