简体   繁体   English

如何删除带有动作栏,viewpager和多个片段的标签?

[英]How to delete a tab with actionbar, viewpager, and multiple fragments?

I'm using code I found here . 我正在使用在这里找到的代码。

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

I'm trying to modify it so that I can delete tabs dynamically. 我正在尝试对其进行修改,以便可以动态删除标签。 I tried by simply creating this function: 我尝试通过简单地创建以下功能:

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

But I always get an indexoutofboundsexception. 但是我总是得到indexoutofboundsexception。 Does anyone know a good way to do this? 有人知道这样做的好方法吗?

EDIT 编辑

By changing my method to: 通过将我的方法更改为:

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

I was able to successfully remove tabs. 我能够成功删除标签。 However, when I delete a tab that IS NOT the one on the far right, the view (or fragment?) that was associated with the tab doesn't go away. 但是,当我删除一个不是最右边的选项卡时,与该选项卡关联的视图(或片段?)不会消失。 Instead, it seems to become associated with the next highest tab. 相反,它似乎与下一个最高的选项卡相关联。 For instance, if I deleted tab 0, tab 0's view just moves to tab 1. If I delete the tab with the highest ID then the tab and view go away correctly but then COME BACK when I add a new tab. 例如,如果删除了选项卡0,则选项卡0的视图仅移至选项卡1。如果删除ID最高的选项卡,则选项卡和视图将正确消失,但是在添加新选项卡时会返回。

It's as if there's a list of fragments somewhere that is being associated with the tabs and deleting the tab doesn't delete the fragment. 好像有一些片段列表与选项卡相关联,并且删除选项卡并不会删除片段。 Does anyone have any idea what's causing this? 有谁知道是什么原因造成的?

EDIT2 编辑2

I've tried to delete the fragments with: 我试图用以下方式删除片段:

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

and also 并且

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

But neither has worked so far. 但到目前为止,两者都没有奏效。

Got it! 得到它了!

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

and override destroyItem 并覆盖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();
    }

Works perfectly!!! 完美的作品!!!

I just discovered today that the real trick to supporting inserting or removing tabs is to override FragmentPagerAdapter.getItemPosition() : 我今天才发现,支持插入或删除选项卡的真正技巧是重写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() will be called by the ViewPager after you have called notifyDataSetChanged() (after adding/removing tabs). getItemPosition()将被称为ViewPager你叫后notifyDataSetChanged() (添加/删除选项卡后)。 The ViewPager is trying to resync its cache with this adapter. ViewPager尝试与此适配器重新同步其缓存。 It calls getItemPosition() for each 'object' (Fragment) it holds, and we tell it what position that Fragment is from. 它为它拥有的每个“对象”(片段)调用getItemPosition() ,然后告诉它Fragment的位置。 If there is no match, it is because we deleted that tab, so return POSITION_NONE . 如果不匹配,那是因为我们删除了该标签,所以返回POSITION_NONE

I have also found it's important to override FragmentPagerAdapter.getItemId() if you insert or remove tabs, because the Fragments will be shifting positions left and right. 我还发现,如果您插入或删除选项卡,则覆盖FragmentPagerAdapter.getItemId()很重要,因为Fragments将在左右移动位置。 This method is called by FragmentPagerAdapter.instantiateItem() and is appended to a name (String) for the item. FragmentPagerAdapter.instantiateItem()调用此方法,并将该方法附加到该项的名称(字符串)。 It uses this name to lookup a pre-existing Fragment with a matching name (if there is one) otherwise instantiate a new one. 它使用该名称查找具有匹配名称(如果有)的现有Fragment,否则实例化一个新的。 Here's some 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 - this one ate my lunch for 2 weeks. 好的-这个吃了我的午餐2周。 I didn't find that the above worked for me at all exactly as shown. 我没有发现上述内容对我完全适用。 I am using Android Studio 3.5.1 in case that matters. 如果有问题,我正在使用Android Studio 3.5.1。

What follows is my FragmentPagerAdapter code in its entirety. 接下来是我的FragmentPagerAdapter代码的全部内容。 It contains most everything you should need. 它包含您需要的大部分内容。 The Fragment code is fairly straightforward for whatever each of your fragments contains. 无论您的每个片段包含什么,片段代码都非常简单。 But let me know if more is required or if you have any questions. 但是,如果需要更多信息或有任何疑问,请告诉我。

Also, if you have any comments or find any errors, please post a comment. 另外,如果您有任何评论或发现任何错误,请发表评论。 I hope this helps others. 我希望这对其他人有帮助。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM