[英]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.