How to set the Adapter for the circular Scroll-able tab - android

I am trying to set infinite view Pager(circular Scroll-able tab) using Infinite ViewPager but when I tried to set the adapter
1.It work only from the end side (last Position).
2.It is not working on the start(position 0) side.
3.It repeat the last fragment when scrolled further.
My adapter
private InfiniteViewPager pager = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pager = (InfiniteViewPager) findViewById(R.id.pager);
FragmentManager fragmentManager = getSupportFragmentManager();
pager.setAdapter(new MyAdapter(fragmentManager));
pager.setPageTransformer(true, new CubeOutTransformer());
pager.setCurrentItem(2);
}
My adapter class
class MyAdapter extends FragmentPagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
public int getActualPosition(int i){
return i < 5? i : 0;
}
#Override
public Fragment getItem(int i) {
Fragment fragment = null;
i = getActualPosition(i);
if (i == 0) {
fragment = new Albums();
}
if (i == 1) {
fragment = new Artists();
}
if (i == 2) {
fragment = new Songs();
}
if (i == 3) {
fragment = new Genres();
}
if (i == 4) {
fragment = new Playlists();
}
return fragment;
}
#Override
public int getCount() {
return Integer.MAX_VALUE;
}
#Override
public CharSequence getPageTitle(int position) {
String title = new String();
if (position == 0) {
return "ALBUMS";
}
if (position == 1) {
return "ARTISTS";
}
if (position == 4) {
return "PLAYLIST";
}
if (position == 3) {
return "GENRES";
}
if (position == 2) {
return "SONGS";
}
return title;
}
}
I have gone through Infinite Pager Adapter and Mine pager adapter
but when I try to set the adapter inside another adapter I am getting an error in my adapter class.
where I am doing wrong and how I can fix the scrolling from both starting and ending.

You should set adapter like this
MyAdapter adapter=new MyAdapter(fragmentManager);
InfinitePagerAdapter myAdapter= new InfinitePagerAdapter(adapter);
pager.setAdapter(myAdapter);
Also in your adapter change this code
from this
#Override
public int getCount() {
return Integer.MAX_VALUE;
}
to
#Override
public int getCount() {
return 5;
}

Related

How to add String Array to tab layout and remove the existing items in tab layout in android

Am having Tab layout with the set of 11 items. I need to remove the existing items from the tab layout and need show only the selected item say for example only 4 items instead of 11.Below is my code.am having my selected items in(str) "String [] str = constants.selectedCategories;" All that i need to do now is i need to set a tablayout with the items in Str.How can i achieve this.
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(viewPagerAdapter);
tabLayout.setupWithViewPager(viewPager);
Below is viewpagerAdapter code
public class ViewPagerAdapter extends FragmentPagerAdapter {
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
Fragment fragment = null;
if (position == 0) {
fragment = new FashionFragment();
} else if (position == 1) {
fragment = new JewelFragment();
} else if (position == 2) {
fragment = new RestaurantFragment();
} else if (position == 3) {
fragment = new SuperMarketFragment();
} else if (position == 4) {
fragment = new HomeApplianceFragment();
} else if (position == 5) {
fragment = new MobileStoreFragment();
} else if (position == 6) {
fragment = new MotorFragment();
} else if (position == 7) {
fragment = new ConstructionElectricalFragment();
} else if (position == 8) {
fragment = new SalonFragment();
} else if (position == 9) {
fragment = new BakeryFragment();
}
else if (position == 10) {
fragment = new OtherFragment();
}
return fragment;
}
#Override
public int getCount() {
return 11;
}
#Override
public CharSequence getPageTitle(int position) {
String title = null;
if (position == 0) {
title = "Fashion";
} else if (position == 1) {
title = "Jewellery";
} else if (position == 2) {
title = "Restaurant";
} else if (position == 3) {
title = "Super Market";
} else if (position == 4) {
title = "Home Appliance";
} else if (position == 5) {
title = "Mobile & Computer accessories";
} else if (position == 6) {
title = "Motors";
} else if (position == 7) {
title = "Construction & Electricals";
} else if (position == 8) {
title = "Saloon & Spa";
} else if (position == 9) {
title = "Bakkery & Sweets";
}
else if (position == 10) {
title = "Others";
}
return title;
}
}
I would suggest you to use FragmentStatePagerAdapter instead of
FragmentPagerAdapter as the number of fragment in your viewpager is
not static and there are a large number of fragment pages.
You need to pass a list of fragment and its name in constructor of ViewPagerAdapter and whenever you want to add or remove fragment you just have to remove or add the fragment from list and notify the adapter.
public class ViewPagerAdapter extends FragmentPagerAdapter {
private ArrayList<Fragment> fragmentList = new ArrayList<Fragment>();
private ArrayList<String> fragmentName;
public ViewPagerAdapter(FragmentManager fm, ArrayList<String> name, ArrayList<Fragment> list) {
super(fm);
this.fragmentList = list;
this.fragmentName = name;
}
#Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
#Override
public int getCount() {
return fragmentList.size();
}
#Override
public CharSequence getPageTitle(int position) {
return fragmentName.get(position);
}
public void addTab(Fragment fragment, String name) {
fragmentList.add( fragment);
fragmentName.add( name);
}
public void removeTab(int position) {
fragmentList.remove(position);
fragmentName.remove(position);
}
}
ArrayList<Fragment> fragmentList;
fragmentList = new ArrayList<Fragment>();
fragmentList.add(new Fashion());
fragmentList.add(new Jewellery());
fragmentList.add(new Restaurent());
.....
ArrayList<String> name;
name = new ArrayList<String>() {
{
add("Fashion");
add("Jewellery");
add("Restaurent");
.....
}
};
Initialize ViewPager
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager(),name,fragmentList);
viewPager.setAdapter(viewPagerAdapter);
tabLayout.setupWithViewPager(viewPager);
Add a fragment
viewPagerAdapter.addTab(new Motors(),"Motors");
viewPagerAdapter.notifyDataSetChanged();
Remove a fragment
viewPagerAdapter.removeTab(3);
viewPagerAdapter.notifyDataSetChanged();

create fragment inside ViewPager android

MainActivity(extends fragmentActivity) has listview which calls listviewadapter within which have a ViewPager with ViewpagerAdapter now if i need to generate 5 fragments within ViewPager how to pass getFragmentManager() to adapter.
MainActivity [fragmentActivity] ----> Listview ----> ListviewAdapter[Custom BaseAdapterAdapter with getview of layout ViewPager] ---> ViewPager ---> ViewPageAdapter[i need to create 5 fragments based on position?]
It will be too long if i paste the whole code so i have attached only
public class ViewPagerAdapter extends PagerAdapter {
ArrayList<ModelClass> arrayModelClasses = new ArrayList<ModelClass>();
Context mcontext ;
LinearLayout layouttest;
final int PAGE_COUNT = 5;
private String titles[] = new String[] { "Villa ","", "" ,"","",""};
private int[] imageResId = { R.drawable.transparant,R.drawable.ic_action_place, R.drawable.icon_3d1,
R.drawable.icon_flooplan,R.drawable.icon_gallery,R.drawable.icon_location };
#SuppressLint("NewApi")
#Override
public void finishUpdate(ViewGroup container) {
// TODO Auto-generated method stub
super.finishUpdate(container);
}
public ViewPagerAdapter(ArrayList<ModelClass> arrayModelClasses , Context context) {
super();
this.arrayModelClasses = arrayModelClasses;
this.mcontext= context;
}
#Override
public boolean isViewFromObject(View collection, Object object) {
return collection == ((View) object);
}
View view;
#Override
public Object instantiateItem(View collection, int position) {
if (position == 0) {
//need to call fragment 1
}if (position == 1) {
//need to call fragment 2
}if (position == 2) {
//need to call fragment 3
}if (position == 3) {
//need to call fragment 4
}if (position == 4) {
//need to call fragment 5
}
return view;
}
#Override
public void destroyItem(View container, int position, Object object) {
((ViewPager) container).removeView((View) object);
}
#Override
public CharSequence getPageTitle(int position) {
Drawable image = mcontext.getResources().getDrawable(imageResId[position]);
image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight());
SpannableString sb = new SpannableString(" " + titles[position] );
ImageSpan imageSpan = new ImageSpan(image, ImageSpan.ALIGN_BOTTOM);
sb.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return sb;
}
#Override
public int getCount() {
return PAGE_COUNT;
}
}
link but it uses FragmentPagerAdapter for viewPager and passed the getSupportFragmentManager from FragmentActivity but its not possible with 2 adapters so help.
Question: How to create fragment within viewPager which is inside listview. sorry if its confusing.
Thanks,
Considering you did not post your ListView Adapter I'll assume you extend BaseAdapter (either way it'll be similar). On the getView(...) method instantiate a new ViewPagerAdapter and set it to the PagerAdapter defined in the list item xml.
Note: having a ViewPager inside the ListView (and specially while loading the items that way) could cause low performance.
I've attached fragments inside ViewPager with the code as follows
public class IntroslideActivity extends FragmentActivity {
private static int NUM_PAGES = 5;
private ViewPager mPager;
private PagerAdapter mPagerAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_introslide);
mPager = (ViewPager) findViewById(R.id.pager);
/**
* A simple pager adapter that represents 5 {#link ScreenSlidePageFragment} objects, in
* sequence.
*/
private class ScreenSlidePagerAdapter extends FragmentPagerAdapter{
protected final int[] ICONS = new int[] {
R.drawable.ic_message,
R.drawable.ic_phone,
R.drawable.ic_message,
R.drawable.ic_message,
R.drawable.ic_message
};
public ScreenSlidePagerAdapter(android.support.v4.app.FragmentManager fm) {
super(fm);
}
#Override
public android.support.v4.app.Fragment getItem(int position) {
android.support.v4.app.Fragment frm = null;
System.out.println("scrolling position"+position);
if(position==0){
frm=ScreenSlidePageFragment.create(position);
}
else if(position==1){
frm=Screenslidetwo.create(position);
}
else if(position==2){
frm=Screenslidethree.create(position);
}
else if(position==3){
frm=Screenslidefour.create(position);
}
else if(position==4){
frm=Screenslidefive.create(position);
}
return frm;
}
#Override
public int getCount() {
return NUM_PAGES;
}
public void setCount(int count) {
if (count > 0 && count < 5) {
NUM_PAGES = count;
notifyDataSetChanged();
}
}
}
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
}
}

ViewPager + FragmentStatePagerAdapter: How to recreate all fragment with new adapter

I'm using the v4 compatibility library. I have a Fragment Tabhost, the first tab have a ViewPager using FragmentStatePagerAdapter. The problem is when I switch to other tabs, change data of the first tab's ViewPager, then return to the first tab, recreate new Adapter with new data and set it to ViewPager, but the first 3 fragments in ViewPager still hold reference to old data.
My code in the first tab to create adapter (called in onCreateView method):
private void setPagerData() {
if (mPager == null || AppConfig.getInstance().todayData == null)
return;
if (AppConfig.getInstance().todayData != null && !AppConfig.getInstance().todayData.isEmpty()) {
//
mPager.setOffscreenPageLimit(AppConfig.PAGER_OFFSCREEN_PAGE_LIMIT);
mPager.setAlwaysDrawnWithCacheEnabled(true);
//
mAdapter = new TodayPagerAdapter(getChildFragmentManager(), AppConfig.getInstance().todayData);
mPager.setAdapter(mAdapter);
mAdapter.notifyDataSetChanged();
if (mAdapter.getCount() == 1)
mPager.setCurrentItem(0);
else
mPager.setCurrentItem(1);
text_currentpage.setText("1");
text_totalpage.setText(String.valueOf(mAdapter.getCount() - 2));
anim_numpage = AnimationUtils.loadAnimation(TodayFragment.this.getActivity(), R.anim.fade_numpage);
layout_numpage.setVisibility(View.INVISIBLE);
image_nextpage.setOnClickListener(this);
image_prevpage.setOnClickListener(this);
//
mPager.setOnPageChangeListener(this);
} else
onNoData(true);
}
onDestroyView():
public void onDestroyView() {
AppUtils.Log("Destroy view Today Fragment");
mAdapter = null;
mPager = null;
super.onDestroyView();
}
My Adapter:
public class TodayPagerAdapter extends FragmentStatePagerAdapter {
private List<PostDTO> posts;
private FragmentManager fm;
public TodayPagerAdapter(FragmentManager fm, List<PostDTO> posts) {
super(fm);
this.fm = fm;
this.posts = posts;
if (posts == null)
posts = new ArrayList<PostDTO>();
}
#Override
public Fragment getItem(int page) {
if (page == 0 && posts.size() > 1)
return TodayPagerFragment.init(posts.size() - 1, posts.get(posts.size() - 1));
if (page == posts.size() + 1)
return TodayPagerFragment.init(0, posts.get(0));
if (posts.size() > 1)
return TodayPagerFragment.init(page - 1, posts.get(page - 1));
return TodayPagerFragment.init(page, posts.get(page));
}
#Override
public int getCount() {
if (posts.size() <= 1)
return posts.size();
return posts.size() + 2;
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
My ViewPager's Fragment:
public class TodayPagerFragment extends AbstractFragment implements View.OnClickListener {
int page;
private ImageView iv_image;
private LikeButton button_like;
private PostDTO data;
public static TodayPagerFragment init(int val, PostDTO data) {
TodayPagerFragment frm = new TodayPagerFragment();
Bundle args = new Bundle();
args.putInt("page", val);
frm.setArguments(args);
frm.data = data;
return frm;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
page = getArguments() != null ? getArguments().getInt("page") : 0;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.tab_today_viewpager, container, false);
setupView(view);
iv_image = (ImageView) view.findViewById(R.id.today_viewpager_image);
button_like = (LikeButton) view.findViewById(R.id.today_button_like);
button_like.setUp(true);
initViews();
return view;
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.today_viewpager_image:
((BaseContainerFragment) getParentFragment().getParentFragment()).replaceFragment(TodayDetailFragment.init(this.data), true);
break;
case R.id.today_button_like:
if (!AppConfig.getInstance().isLoggedIn || AppConfig.getInstance().appUser == null) {
AppUtils.openLogin(getActivity());
} else {
String ms = getString(R.string.do_you_want_to_like_this_post_);
if (data.isLiked())
ms = getString(R.string.do_you_want_to_unlike_this_post_);
new MyDialogHandler().confirm(getActivity(), getString(R.string.like_confirm), ms, getString(R.string.no), getString(R.string.yes), new Runnable() {
#Override
public void run() {
new PostLikeTask(button_like, data, !data.isLiked()).execute();
// data.setLiked(!data.isLiked());
}
}, null);
}
break;
default:
break;
}
}
// Setup view data
private void initViews() {
iv_image.setOnClickListener(this);
button_like.setOnClickListener(this);
if (this.data != null) {
AppUtils.Log("Current: //////// " + (data.toString().equals(AppConfig.getInstance().todayData.get(page))));
// if (AppConfig.getInstance().appUser != null &&
// AppConfig.getInstance().isLoggedIn)
// new GetLikedTask().execute();
// else
button_like.setData(data.getLikes(), data.isLiked());
// ImageLoader.getInstance().displayImage(AppConfig.SERVER_IMAGE_URL
// + this.data.getImage(), iv_image);
// onLoading(true);
UrlImageViewHelper.setUrlDrawable(iv_image, AppConfig.SERVER_IMAGE_URL + this.data.getImage());
}
}
}

Viewpager and FragmentPagerAdapter: Page view removal

I'm using a Viewpager with a the FragmentPagerAdapter to allow adding and removing of pages. Each page displays data obtained from the internet.
As a new page is added, a new Fragment is associated with that page. The data are obtained via AsyncTask and displayed in the Fragment. When the user chooses to remove a page, the idea is to destroy the page and the associated Fragment.
In general, this all works well. The problem I'm seeing is as follows:
You have three pages with data:
[Page 1] [Page 2] [Page 3]
You delete any page other than the last one, say page 2; Page 2 disappears as desired:
[Page 1] [Page 3]
You add a new page; but instead of a blank, new page, the new page shows the data (view) from page 3.
[Page 1] [Page 3] [Page 4, but showing view/data of Page 3, should be blank]
The page removal code in my activity is as follows:
// Destroy fragment for this page
DataListFragment curFrag = getFragmentByName(currentPage);
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction().remove(curFrag).commit();
fm.executePendingTransactions();
curFrag = null;
// Remove page and update adapter
mPageTitles.remove(position);
mAdapter.notifyDataSetChanged();
Using the debugger, it shows that the fragment is removed from the FragmentManager after the executePendingTransactions() call. But in the FrampePagerAdapters call, mAdapter.notifyDataSetChanged(), the fragment is added back in and then displayed when a new page is created.
I tried using the FrameStatePagerAdapter, since that should allow destroying fragments, but it did not work. In my FragmentPagerAdapter's getItemPosition() method, I use return FragmentAdapter.POSITION_NONE; as pointed out in another SO article I came across.
It seems as if the View for that page is not destroyed, but then added back into the new page. I tried using the removeViewAt() method on the view of the new page, but that did not work.
Being new to this, I'm sure I'm missing something obvious...
You should rather extend FragmentStatePagerAdapter and remove corresponding item from the list of items in that adapter, instead of trying to remove a Fragment from activity. Do not forget to call adapter.notifyDataSetChanged() after you removed an item in adapter. Once done, ViewPager and FragmentStatePagerAdapter will take care for the rest.
See your getCount() method is returning exact number of items in the viewPager. And yes, FragmentStatePagerAdapter counts too.
I've ended up with a solution that mixes the following knowledge based on experience:
You can add a new Fragment at the tail without problems.
You cannot readd a Fragment that was previously removed, as it leads to java.lang.IllegalStateException: Can't change tag of fragment sometimes, so you have to clone it.
For removing a Fragment you have to return PagerAdapter.POSITION_NONE in the method getItemPosition(Object object), and remove the Fragment from the FragmentManager.
If you are adding/removing/replacing in other place different than the tail, you have to remove everything from the position you are changing until the end, do the stuff, and then readd the (cloned) Fragments that you removed.
Here it is a complete FragmentActivity code with a FragmentPagerAdapter that has 3 methods for adding, removing and replacing tabs:
public class TabTestActivity extends FragmentActivity implements
ActionBar.TabListener {
private SectionsPagerAdapter mSectionsPagerAdapter;
private ViewPager mViewPager;
private static int tabCount = 0;
private static String labelString = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
labelString = getString(R.string.title_section);
setContentView(R.layout.activity_tab_test);
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
mSectionsPagerAdapter = new SectionsPagerAdapter(
getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(final int position) {
(new Handler()).postDelayed(new Runnable() {
#Override
public void run() {
actionBar.setSelectedNavigationItem(position);
}
}, 1);
}
});
for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
actionBar.addTab(actionBar.newTab()
.setText(mSectionsPagerAdapter.getPageTitle(i))
.setTabListener(this));
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.tab_test, menu);
return true;
}
public void addNewTab() {
int position = (mSectionsPagerAdapter.getCount() > 0 ? mViewPager.getCurrentItem() : 0);
mSectionsPagerAdapter.insertFragment(position);
mViewPager.setCurrentItem(position, true);
}
public void removeTab() {
if (mSectionsPagerAdapter.getCount() > 0) {
int position = mViewPager.getCurrentItem();
mSectionsPagerAdapter.removeFragment(position);
}
}
public void replaceTab() {
if (mSectionsPagerAdapter.getCount() > 0) {
int position = mViewPager.getCurrentItem();
mSectionsPagerAdapter.replaceFragment(position);
mViewPager.setCurrentItem(position, false);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_add_tab:
addNewTab();
return true;
case R.id.action_remove_tab:
removeTab();
return true;
case R.id.action_replace_tab:
replaceTab();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onTabSelected(ActionBar.Tab tab,
FragmentTransaction fragmentTransaction) {
mViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(ActionBar.Tab tab,
FragmentTransaction fragmentTransaction) {
}
#Override
public void onTabReselected(ActionBar.Tab tab,
FragmentTransaction fragmentTransaction) {
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> currentFragments;
private FragmentManager fragmentManager;
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
fragmentManager = fm;
currentFragments = new ArrayList<Fragment>();
}
public void insertFragment(int position) {
// Remove fragments from position
List<Fragment> fragmentsToRemove = new ArrayList<Fragment>(currentFragments.subList(position, currentFragments.size()));
int i = currentFragments.size() - 1;
int j = -1;
int k = i;
while (i >= position) {
currentFragments.remove(i);
i--;
j++;
}
notifyDataSetChanged();
final ActionBar actionBar = getActionBar();
while (k >= position) {
actionBar.removeTabAt(k);
k--;
}
android.support.v4.app.FragmentTransaction transaction = fragmentManager.beginTransaction();
while (j >= 0) {
Fragment fragmentToRemove = fragmentsToRemove.get(j);
transaction.detach(fragmentToRemove);
transaction.remove(fragmentToRemove);
j--;
}
transaction.commit();
fragmentManager.executePendingTransactions();
notifyDataSetChanged();
// Add new fragment
Fragment fragment = new DummySectionFragment();
currentFragments.add(position, fragment);
notifyDataSetChanged();
actionBar.addTab(actionBar.newTab()
.setText(mSectionsPagerAdapter.getPageTitle(position))
.setTabListener(TabTestActivity.this), position);
// Readd fragments
if (fragmentsToRemove.size() > 0) {
i = 1;
for (Fragment fragmentToRemove : fragmentsToRemove) {
currentFragments.add(DummySectionFragment.cloneExistingFragment((DummySectionFragment)fragmentToRemove));
notifyDataSetChanged();
actionBar.addTab(actionBar.newTab()
.setText(mSectionsPagerAdapter.getPageTitle(position + i))
.setTabListener(TabTestActivity.this), position + i);
i++;
}
}
}
public void removeFragment(int position) {
// Remove fragments from position
List<Fragment> fragmentsToRemove = new ArrayList<Fragment>(currentFragments.subList(position, currentFragments.size()));
int i = currentFragments.size() - 1;
int j = -1;
int k = i;
while (i >= position) {
currentFragments.remove(i);
i--;
j++;
}
notifyDataSetChanged();
final ActionBar actionBar = getActionBar();
while (k >= position) {
actionBar.removeTabAt(k);
k--;
}
android.support.v4.app.FragmentTransaction transaction = fragmentManager.beginTransaction();
while (j >= 0) {
Fragment fragmentToRemove = fragmentsToRemove.get(j);
transaction.detach(fragmentToRemove);
transaction.remove(fragmentToRemove);
j--;
}
transaction.commitAllowingStateLoss();
fragmentManager.executePendingTransactions();
notifyDataSetChanged();
// Readd fragments (except one)
if (fragmentsToRemove.size() > 1) {
i = 0;
for (Fragment fragment : fragmentsToRemove.subList(1, fragmentsToRemove.size())) {
currentFragments.add(DummySectionFragment.cloneExistingFragment((DummySectionFragment)fragment));
notifyDataSetChanged();
actionBar.addTab(actionBar.newTab()
.setText(mSectionsPagerAdapter.getPageTitle(position + i))
.setTabListener(TabTestActivity.this), position + i);
i++;
}
}
}
public void replaceFragment(int position) {
// Remove fragments from position
List<Fragment> fragmentsToRemove = new ArrayList<Fragment>(currentFragments.subList(position, currentFragments.size()));
int i = currentFragments.size() - 1;
int j = -1;
int k = i;
while (i >= position) {
currentFragments.remove(i);
i--;
j++;
}
notifyDataSetChanged();
final ActionBar actionBar = getActionBar();
while (k >= position) {
actionBar.removeTabAt(k);
k--;
}
android.support.v4.app.FragmentTransaction transaction = fragmentManager.beginTransaction();
while (j >= 0) {
Fragment fragmentToRemove = fragmentsToRemove.get(j);
transaction.detach(fragmentToRemove);
transaction.remove(fragmentToRemove);
j--;
}
transaction.commit();
fragmentManager.executePendingTransactions();
notifyDataSetChanged();
// Add new fragment
Fragment fragment = new DummySectionFragment();
currentFragments.add(position, fragment);
notifyDataSetChanged();
actionBar.addTab(actionBar.newTab()
.setText(mSectionsPagerAdapter.getPageTitle(position))
.setTabListener(TabTestActivity.this), position);
// Readd fragments (except one)
if (fragmentsToRemove.size() > 0) {
i = 1;
for (Fragment fragmentToRemove : fragmentsToRemove.subList(1, fragmentsToRemove.size())) {
currentFragments.add(DummySectionFragment.cloneExistingFragment((DummySectionFragment)fragmentToRemove));
notifyDataSetChanged();
actionBar.addTab(actionBar.newTab()
.setText(mSectionsPagerAdapter.getPageTitle(position + i))
.setTabListener(TabTestActivity.this), position + i);
i++;
}
}
}
#Override
public Fragment getItem(int position) {
if (currentFragments == null) {
currentFragments = new ArrayList<Fragment>();
}
while (currentFragments.size() <= position) {
currentFragments.add(null);
}
if (currentFragments.get(position) != null) {
return currentFragments.get(position);
}
Fragment fragment = new DummySectionFragment();
currentFragments.set(position, fragment);
return fragment;
}
#Override
public int getCount() {
return currentFragments.size();
}
#Override
public int getItemPosition(Object object) {
int position = currentFragments.indexOf(object);
if (position == -1) {
return PagerAdapter.POSITION_NONE;
}
return position;
}
#Override
public CharSequence getPageTitle(int position) {
return ((DummySectionFragment)getItem(position)).getTitle();
}
}
public static class DummySectionFragment extends Fragment {
private int sectionNumber;
public DummySectionFragment() {
super();
sectionNumber = ++tabCount;
}
public static DummySectionFragment cloneExistingFragment(DummySectionFragment fragment) {
DummySectionFragment cloned = new DummySectionFragment();
// Hack for avoiding autoincrement
--tabCount;
cloned.sectionNumber = fragment.getSectionNumber();
return cloned;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_tab_test_dummy,
container, false);
TextView dummyTextView = (TextView) rootView
.findViewById(R.id.section_label);
dummyTextView.setText(String.format(labelString, sectionNumber));
return rootView;
}
public int getSectionNumber() {
return sectionNumber;
}
public String getTitle() {
return String.format(labelString, sectionNumber);
}
}
}

Remove Fragment Page from ViewPager in Android

I'm trying to dynamically add and remove Fragments from a ViewPager, adding works without any problems, but removing doesn't work as expected.
Everytime I want to remove the current item, the last one gets removed.
I also tried to use an FragmentStatePagerAdapter or return POSITION_NONE in the adapter's getItemPosition method.
What am I doing wrong?
Here's a basic example:
MainActivity.java
public class MainActivity extends FragmentActivity implements TextProvider {
private Button mAdd;
private Button mRemove;
private ViewPager mPager;
private MyPagerAdapter mAdapter;
private ArrayList<String> mEntries = new ArrayList<String>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mEntries.add("pos 1");
mEntries.add("pos 2");
mEntries.add("pos 3");
mEntries.add("pos 4");
mEntries.add("pos 5");
mAdd = (Button) findViewById(R.id.add);
mRemove = (Button) findViewById(R.id.remove);
mPager = (ViewPager) findViewById(R.id.pager);
mAdd.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
addNewItem();
}
});
mRemove.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
removeCurrentItem();
}
});
mAdapter = new MyPagerAdapter(this.getSupportFragmentManager(), this);
mPager.setAdapter(mAdapter);
}
private void addNewItem() {
mEntries.add("new item");
mAdapter.notifyDataSetChanged();
}
private void removeCurrentItem() {
int position = mPager.getCurrentItem();
mEntries.remove(position);
mAdapter.notifyDataSetChanged();
}
#Override
public String getTextForPosition(int position) {
return mEntries.get(position);
}
#Override
public int getCount() {
return mEntries.size();
}
private class MyPagerAdapter extends FragmentPagerAdapter {
private TextProvider mProvider;
public MyPagerAdapter(FragmentManager fm, TextProvider provider) {
super(fm);
this.mProvider = provider;
}
#Override
public Fragment getItem(int position) {
return MyFragment.newInstance(mProvider.getTextForPosition(position));
}
#Override
public int getCount() {
return mProvider.getCount();
}
}
}
TextProvider.java
public interface TextProvider {
public String getTextForPosition(int position);
public int getCount();
}
MyFragment.java
public class MyFragment extends Fragment {
private String mText;
public static MyFragment newInstance(String text) {
MyFragment f = new MyFragment(text);
return f;
}
public MyFragment() {
}
public MyFragment(String text) {
this.mText = text;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment, container, false);
((TextView) root.findViewById(R.id.position)).setText(mText);
return root;
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="#+id/add"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="add new item" />
<Button
android:id="#+id/remove"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="remove current item" />
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1" />
</LinearLayout>
fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/position"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="35sp" />
</LinearLayout>
The ViewPager doesn't remove your fragments with the code above because it loads several views (or fragments in your case) into memory. In addition to the visible view, it also loads the view to either side of the visible one. This provides the smooth scrolling from view to view that makes the ViewPager so cool.
To achieve the effect you want, you need to do a couple of things.
Change the FragmentPagerAdapter to a FragmentStatePagerAdapter. The reason for this is that the FragmentPagerAdapter will keep all the views that it loads into memory forever. Where the FragmentStatePagerAdapter disposes of views that fall outside the current and traversable views.
Override the adapter method getItemPosition (shown below). When we call mAdapter.notifyDataSetChanged(); the ViewPager interrogates the adapter to determine what has changed in terms of positioning. We use this method to say that everything has changed so reprocess all your view positioning.
And here's the code...
private class MyPagerAdapter extends FragmentStatePagerAdapter {
//... your existing code
#Override
public int getItemPosition(Object object){
return PagerAdapter.POSITION_NONE;
}
}
The solution by Louth was not enough to get things working for me, as the existing fragments were not getting destroyed. Motivated by this answer, I found that the solution is to override the getItemId(int position) method of FragmentPagerAdapter to give a new unique ID whenever there has been a change in the expected position of a Fragment.
Source Code:
private class MyPagerAdapter extends FragmentPagerAdapter {
private TextProvider mProvider;
private long baseId = 0;
public MyPagerAdapter(FragmentManager fm, TextProvider provider) {
super(fm);
this.mProvider = provider;
}
#Override
public Fragment getItem(int position) {
return MyFragment.newInstance(mProvider.getTextForPosition(position));
}
#Override
public int getCount() {
return mProvider.getCount();
}
//this is called when notifyDataSetChanged() is called
#Override
public int getItemPosition(Object object) {
// refresh all fragments when data set changed
return PagerAdapter.POSITION_NONE;
}
#Override
public long getItemId(int position) {
// give an ID different from position when position has been changed
return baseId + position;
}
/**
* Notify that the position of a fragment has been changed.
* Create a new ID for each position to force recreation of the fragment
* #param n number of items which have been changed
*/
public void notifyChangeInPosition(int n) {
// shift the ID returned by getItemId outside the range of all previous fragments
baseId += getCount() + n;
}
}
Now, for example if you delete a single tab or make some change to the order, you should call notifyChangeInPosition(1) before calling notifyDataSetChanged(), which will ensure that all the Fragments will be recreated.
Why this solution works
Overriding getItemPosition():
When notifyDataSetChanged() is called, the adapter calls the notifyChanged() method of the ViewPager which it is attached to. The ViewPager then checks the value returned by the adapter's getItemPosition() for each item, removing those items which return POSITION_NONE (see the source code) and then repopulating.
Overriding getItemId():
This is necessary to prevent the adapter from reloading the old fragment when the ViewPager is repopulating. You can easily understand why this works by looking at the source code for instantiateItem() in FragmentPagerAdapter.
final long itemId = getItemId(position);
// Do we already have this fragment?
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
mCurTransaction.attach(fragment);
} else {
fragment = getItem(position);
if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
mCurTransaction.add(container.getId(), fragment,
makeFragmentName(container.getId(), itemId));
}
As you can see, the getItem() method is only called if the fragment manager finds no existing fragments with the same Id. To me it seems like a bug that the old fragments are still attached even after notifyDataSetChanged() is called, but the documentation for ViewPager does clearly state that:
Note this class is currently under early design and development. The API will likely change in later updates of the compatibility library, requiring changes to the source code of apps when they are compiled against the newer version.
So hopefully the workaround given here will not be necessary in a future version of the support library.
my working solution to remove fragment page from view pager
public class MyFragmentAdapter extends FragmentStatePagerAdapter {
private ArrayList<ItemFragment> pages;
public MyFragmentAdapter(FragmentManager fragmentManager, ArrayList<ItemFragment> pages) {
super(fragmentManager);
this.pages = pages;
}
#Override
public Fragment getItem(int index) {
return pages.get(index);
}
#Override
public int getCount() {
return pages.size();
}
#Override
public int getItemPosition(Object object) {
int index = pages.indexOf (object);
if (index == -1)
return POSITION_NONE;
else
return index;
}
}
And when i need to remove some page by index i do this
pages.remove(position); // ArrayList<ItemFragment>
adapter.notifyDataSetChanged(); // MyFragmentAdapter
Here it is my adapter initialization
MyFragmentAdapter adapter = new MyFragmentAdapter(getSupportFragmentManager(), pages);
viewPager.setAdapter(adapter);
The fragment must be already removed but the issue was viewpager save state
Try
myViewPager.setSaveFromParentEnabled(false);
Nothing worked but this solved the issue !
Cheers !
I had the idea of simply copy the source code from android.support.v4.app.FragmentPagerAdpater into a custom class named
CustumFragmentPagerAdapter. This gave me the chance to modify the instantiateItem(...) so that every time it is called, it removes / destroys the currently attached fragment before it adds the new fragment received from getItem() method.
Simply modify the instantiateItem(...) in the following way:
#Override
public Object instantiateItem(ViewGroup container, int position) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
final long itemId = getItemId(position);
// Do we already have this fragment?
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
// remove / destroy current fragment
if (fragment != null) {
mCurTransaction.remove(fragment);
}
// get new fragment and add it
fragment = getItem(position);
mCurTransaction.add(container.getId(), fragment, makeFragmentName(container.getId(), itemId));
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
}
return fragment;
}
You can combine both for better :
private class MyPagerAdapter extends FragmentStatePagerAdapter {
//... your existing code
#Override
public int getItemPosition(Object object){
if(Any_Reason_You_WantTo_Update_Positions) //this includes deleting or adding pages
return PagerAdapter.POSITION_NONE;
}
else
return PagerAdapter.POSITION_UNCHANGED; //this ensures high performance in other operations such as editing list items.
}
I had some problems with FragmentStatePagerAdapter.
After removing an item:
there was another item used for a position (an item which did not belong to the position but to a position next to it)
or some fragment was not loaded (there was only blank background visible on that page)
After lots of experiments, I came up with the following solution.
public class SomeAdapter extends FragmentStatePagerAdapter {
private List<Item> items = new ArrayList<Item>();
private boolean removing;
#Override
public Fragment getItem(int position) {
ItemFragment fragment = new ItemFragment();
Bundle args = new Bundle();
// use items.get(position) to configure fragment
fragment.setArguments(args);
return fragment;
}
#Override
public int getCount() {
return items.size();
}
#Override
public int getItemPosition(Object object) {
if (removing) {
return PagerAdapter.POSITION_NONE;
}
Item item = getItemOfFragment(object);
int index = items.indexOf(item);
if (index == -1) {
return POSITION_NONE;
} else {
return index;
}
}
public void addItem(Item item) {
items.add(item);
notifyDataSetChanged();
}
public void removeItem(int position) {
items.remove(position);
removing = true;
notifyDataSetChanged();
removing = false;
}
}
This solution only uses a hack in case of removing an item. Otherwise (e.g. when adding an item) it retains the cleanliness and performance of an original code.
Of course, from the outside of the adapter, you call only addItem/removeItem, no need to call notifyDataSetChanged().
For future readers!
Now you can use ViewPager2 for dynamically adding, removing fragment from the viewpager.
Quoting form API reference
ViewPager2 replaces ViewPager, addressing most of its predecessor’s
pain-points, including right-to-left layout support, vertical
orientation, modifiable Fragment collections, etc.
Take look at MutableCollectionFragmentActivity.kt in googlesample/android-viewpager2 for an example of adding, removing fragments dynamically from the viewpager.
For your information:
Articles:
Exploring the ViewPager2
Look deep into ViewPager2
API reference
Release notes
Samples Repo: https://github.com/googlesamples/android-viewpager2
Louth's answer works fine. But I don't think always return POSITION_NONE is a good idea. Because POSITION_NONE means that fragment should be destroyed and a new fragment will be created.
You can check that in dataSetChanged function in the source code of ViewPager.
if (newPos == PagerAdapter.POSITION_NONE) {
mItems.remove(i);
i--;
... not related code
mAdapter.destroyItem(this, ii.position, ii.object);
So I think you'd better use an arraylist of weakReference to save all the fragments you have created. And when you add or remove some page, you can get the right position from your own arraylist.
public int getItemPosition(Object object) {
for (int i = 0; i < mFragmentsReferences.size(); i ++) {
WeakReference<Fragment> reference = mFragmentsReferences.get(i);
if (reference != null && reference.get() != null) {
Fragment fragment = reference.get();
if (fragment == object) {
return i;
}
}
}
return POSITION_NONE;
}
According to the comments, getItemPosition is Called when the host view is attempting to determine if an item's position has changed. And the return value means its new position.
But this is not enought. We still have an important step to take.
In the source code of FragmentStatePagerAdapter, there is an array named "mFragments" caches the fragments which are not destroyed. And in instantiateItem function.
if (mFragments.size() > position) {
Fragment f = mFragments.get(position);
if (f != null) {
return f;
}
}
It returned the cached fragment directly when it find that cached fragment is not null. So there is a problem. From example, let's delete one page at position 2, Firstly, We remove that fragment from our own reference arraylist. so in getItemPosition it will return POSITION_NONE for that fragment, and then that fragment will be destroyed and removed from "mFragments".
mFragments.set(position, null);
Now the fragment at position 3 will be at position 2. And instantiatedItem with param position 3 will be called. At this time, the third item in "mFramgents" is not null, so it will return directly. But actually what it returned is the fragment at position 2. So when we turn into page 3, we will find an empty page there.
To work around this problem. My advise is that you can copy the source code of FragmentStatePagerAdapter into your own project, and when you do add or remove operations, you should add and remove elements in the "mFragments" arraylist.
Things will be simpler if you just use PagerAdapter instead of FragmentStatePagerAdapter. Good Luck.
add or remove fragment in viewpager dynamically.
Call setupViewPager(viewPager) on activity start.
To load different fragment call setupViewPagerCustom(viewPager).
e.g. on button click call: setupViewPagerCustom(viewPager);
private void setupViewPager(ViewPager viewPager)
{
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFrag(new fragmnet1(), "HOME");
adapter.addFrag(new fragmnet2(), "SERVICES");
viewPager.setAdapter(adapter);
}
private void setupViewPagerCustom(ViewPager viewPager)
{
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFrag(new fragmnet3(), "Contact us");
adapter.addFrag(new fragmnet4(), "ABOUT US");
viewPager.setAdapter(adapter);
}
//Viewpageradapter, handles the views
static class ViewPagerAdapter extends FragmentStatePagerAdapter
{
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager){
super(manager);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
#Override
public int getItemPosition(Object object){
return PagerAdapter.POSITION_NONE;
}
public void addFrag(Fragment fragment, String title){
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position){
return mFragmentTitleList.get(position);
}
}
Try this solution. I have used databinding for binding view. You can use common "findViewById()" function.
public class ActCPExpense extends BaseActivity implements View.OnClickListener, {
private static final String TAG = ActCPExpense.class.getSimpleName();
private Context mContext;
private ActCpLossBinding mBinding;
private ViewPagerAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
setContentView(R.layout.act_cp_loss);
mBinding = DataBindingUtil.setContentView(this, R.layout.act_cp_loss);
mContext = ActCPExpense.this;
initViewsAct();
} catch (Exception e) {
LogUtils.LOGE(TAG, e);
}
}
private void initViewsAct() {
adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(FragmentCPPayee.newInstance(), "Title");
mBinding.viewpager.setAdapter(adapter);
mBinding.tab.setViewPager(mBinding.viewpager);
}
#Override
public boolean onOptionsItemSelected(MenuItem itemActUtility) {
int i = itemActUtility.getItemId();
if (i == android.R.id.home) {
onBackPressed();
}
return super.onOptionsItemSelected(itemActUtility);
}
#Override
public void onClick(View view) {
super.onClick(view);
int id = view.getId();
if (id == R.id.btnAdd) {
addFragment();
} else if (id == R.id.btnDelete) {
removeFragment();
}
}
private void addFragment(){
adapter.addFragment(FragmentCPPayee.newInstance("Title");
adapter.notifyDataSetChanged();
mBinding.tab.setViewPager(mBinding.viewpager);
}
private void removeFragment(){
adapter.removeItem(mBinding.viewpager.getCurrentItem());
mBinding.tab.setViewPager(mBinding.viewpager);
}
class ViewPagerAdapter extends FragmentStatePagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public int getItemPosition(#NonNull Object object) {
return PagerAdapter.POSITION_NONE;
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
public void removeItem(int pos) {
destroyItem(null, pos, mFragmentList.get(pos));
mFragmentList.remove(pos);
mFragmentTitleList.remove(pos);
adapter.notifyDataSetChanged();
mBinding.viewpager.setCurrentItem(pos - 1, false);
}
#Override
public CharSequence getPageTitle(int position) {
return "Title " + String.valueOf(position + 1);
}
}
}
I added a function "clearFragments" and I used that function to clear adapter before setting the new fragments. This calls the proper remove actions of Fragments. My pagerAdapter class:
private class ChartPagerAdapter extends FragmentPagerAdapter{
private ArrayList<Fragment> fragmentList;
ChartPagerAdapter(FragmentManager fm){
super(fm);
fragmentList = new ArrayList<>();
}
void setFragments(ArrayList<? extends Fragment> fragments){
fragmentList.addAll(fragments);
}
void clearFragments(){
for(Fragment fragment:fragmentList)
getChildFragmentManager().beginTransaction().remove(fragment).commit();
fragmentList.clear();
}
#Override
public Fragment getItem(int i) {
return fragmentList.get(i);
}
#Override
public int getCount() {
return fragmentList.size();
}
}
i solved this problem by these steps
1- use FragmentPagerAdapter
2- in each fragment create a random id
fragment.id = new Random().nextInt();
3- override getItemPosition in adapter
#Override
public int getItemPosition(#NonNull Object object) {
return PagerAdapter.POSITION_NONE;
}
4-override getItemId in adapter
#Override
public long getItemId(int position) {
return mDatasetFragments.get(position).id;
}
5- now delete code is
adapter.mDatasetFragments.remove(< item to delete position >);
adapter.notifyDataSetChanged();
this worked for me i hope help
My final version code, fixed ALL bugs. It took me 3 days
Updated 2020/07/18:
I had changed a lot of the source code and fix so many bugs, but I don't promise it still work today.
https://github.com/lin1987www/FragmentBuilder/blob/master/commonLibrary/src/main/java/android/support/v4/app/FragmentStatePagerAdapterFix.java
public class FragmentStatePagerAdapterFix extends PagerAdapter {
private static final String TAG = FragmentStatePagerAdapterFix.class.getSimpleName();
private static final boolean DEBUG = false;
private WeakReference<FragmentActivity> wrFragmentActivity;
private WeakReference<Fragment> wrParentFragment;
private final FragmentManager mFragmentManager;
private FragmentTransaction mCurTransaction = null;
protected ArrayList<Fragment> mFragments = new ArrayList<>();
protected ArrayList<FragmentState> mFragmentStates = new ArrayList<>();
protected ArrayList<String> mFragmentTags = new ArrayList<>();
protected ArrayList<String> mFragmentClassNames = new ArrayList<>();
protected ArrayList<Bundle> mFragmentArgs = new ArrayList<>();
private Fragment mCurrentPrimaryItem = null;
private boolean[] mTempPositionChange;
#Override
public int getCount() {
return mFragmentClassNames.size();
}
public FragmentActivity getFragmentActivity() {
return wrFragmentActivity.get();
}
public Fragment getParentFragment() {
return wrParentFragment.get();
}
public FragmentStatePagerAdapterFix(FragmentActivity activity) {
mFragmentManager = activity.getSupportFragmentManager();
wrFragmentActivity = new WeakReference<>(activity);
wrParentFragment = new WeakReference<>(null);
}
public FragmentStatePagerAdapterFix(Fragment fragment) {
mFragmentManager = fragment.getChildFragmentManager();
wrFragmentActivity = new WeakReference<>(fragment.getActivity());
wrParentFragment = new WeakReference<>(fragment);
}
public void add(Class<? extends android.support.v4.app.Fragment> fragClass) {
add(fragClass, null, null);
}
public void add(Class<? extends android.support.v4.app.Fragment> fragClass, Bundle args) {
add(fragClass, args, null);
}
public void add(Class<? extends android.support.v4.app.Fragment> fragClass, String tag) {
add(fragClass, null, tag);
}
public void add(Class<? extends android.support.v4.app.Fragment> fragClass, Bundle args, String tag) {
add(fragClass, args, tag, getCount());
}
public void add(Class<? extends android.support.v4.app.Fragment> fragClass, Bundle args, String tag, int position) {
mFragments.add(position, null);
mFragmentStates.add(position, null);
mFragmentTags.add(position, tag);
mFragmentClassNames.add(position, fragClass.getName());
mFragmentArgs.add(position, args);
mTempPositionChange = new boolean[getCount()];
}
public void remove(int position) {
if (position < getCount()) {
mTempPositionChange = new boolean[getCount()];
for (int i = position; i < mTempPositionChange.length; i++) {
mTempPositionChange[i] = true;
}
mFragments.remove(position);
mFragmentStates.remove(position);
mFragmentTags.remove(position);
mFragmentClassNames.remove(position);
mFragmentArgs.remove(position);
}
}
public void clear(){
mFragments.clear();
mFragmentStates.clear();
mFragmentTags.clear();
mFragmentClassNames.clear();
mFragmentArgs.clear();
}
#Override
public void startUpdate(ViewGroup container) {
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment;
// If we already have this item instantiated, there is nothing
// to do. This can happen when we are restoring the entire pager
// from its saved state, where the fragment manager has already
// taken care of restoring the fragments we previously had instantiated.
fragment = mFragments.get(position);
if (fragment != null) {
return fragment;
}
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
FragmentState fs = mFragmentStates.get(position);
if (fs != null) {
fragment = fs.instantiate(getFragmentActivity(), getParentFragment());
// Fix bug
// http://stackoverflow.com/questions/11381470/classnotfoundexception-when-unmarshalling-android-support-v4-view-viewpagersav
if (fragment.mSavedFragmentState != null) {
fragment.mSavedFragmentState.setClassLoader(fragment.getClass().getClassLoader());
}
}
if (fragment == null) {
fragment = Fragment.instantiate(getFragmentActivity(), mFragmentClassNames.get(position), mFragmentArgs.get(position));
}
if (DEBUG) {
Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
}
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
mFragments.set(position, fragment);
mFragmentStates.set(position, null);
mCurTransaction.add(container.getId(), fragment, mFragmentTags.get(position));
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
Fragment fragment = (Fragment) object;
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
if (DEBUG) {
Log.v(TAG, "Removing item #" + position + ": f=" + object
+ " v=" + ((Fragment) object).getView());
}
if (position < getCount()) {
FragmentState fragmentState = new FragmentState(fragment);
Fragment.SavedState savedState = mFragmentManager.saveFragmentInstanceState(fragment);
if (savedState != null) {
fragmentState.mSavedFragmentState = savedState.mState;
}
mFragmentStates.set(position, fragmentState);
mFragments.set(position, null);
}
mCurTransaction.remove(fragment);
}
#Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
Fragment fragment = (Fragment) object;
if (fragment != mCurrentPrimaryItem) {
if (mCurrentPrimaryItem != null) {
mCurrentPrimaryItem.setMenuVisibility(false);
mCurrentPrimaryItem.setUserVisibleHint(false);
}
if (fragment != null) {
fragment.setMenuVisibility(true);
fragment.setUserVisibleHint(true);
}
mCurrentPrimaryItem = fragment;
}
}
#Override
public void finishUpdate(ViewGroup container) {
if (mCurTransaction != null) {
mCurTransaction.commitAllowingStateLoss();
mCurTransaction = null;
mFragmentManager.executePendingTransactions();
// Fix: Fragment is added by transaction. BUT didn't add to FragmentManager's mActive.
for (Fragment fragment : mFragments) {
if (fragment != null) {
fixActiveFragment(mFragmentManager, fragment);
}
}
}
}
#Override
public boolean isViewFromObject(View view, Object object) {
return ((Fragment) object).getView() == view;
}
#Override
public Parcelable saveState() {
Bundle state = null;
// 目前顯示的 Fragments
for (int i = 0; i < mFragments.size(); i++) {
Fragment f = mFragments.get(i);
if (f != null && f.isAdded()) {
if (state == null) {
state = new Bundle();
}
String key = "f" + i;
mFragmentManager.putFragment(state, key, f);
}
}
if (mFragmentStates.size() > 0) {
if (state == null) {
state = new Bundle();
}
FragmentState[] fs = new FragmentState[mFragmentStates.size()];
mFragmentStates.toArray(fs);
state.putParcelableArray("states_fragment", fs);
}
return state;
}
#Override
public void restoreState(Parcelable state, ClassLoader loader) {
if (state != null) {
Bundle bundle = (Bundle) state;
bundle.setClassLoader(loader);
Parcelable[] fs = bundle.getParcelableArray("states_fragment");
mFragments.clear();
mFragmentStates.clear();
mFragmentTags.clear();
mFragmentClassNames.clear();
mFragmentArgs.clear();
if (fs != null) {
for (int i = 0; i < fs.length; i++) {
FragmentState fragmentState = (FragmentState) fs[i];
mFragmentStates.add(fragmentState);
if (fragmentState != null) {
mFragmentArgs.add(fragmentState.mArguments);
mFragmentTags.add(fragmentState.mTag);
mFragmentClassNames.add(fragmentState.mClassName);
} else {
mFragmentArgs.add(null);
mFragmentTags.add(null);
mFragmentClassNames.add(null);
}
mFragments.add(null);
}
}
Iterable<String> keys = bundle.keySet();
for (String key : keys) {
if (key.startsWith("f")) {
int index = Integer.parseInt(key.substring(1));
Fragment f = mFragmentManager.getFragment(bundle, key);
if (f != null) {
f.setMenuVisibility(false);
mFragments.set(index, f);
mFragmentArgs.set(index, f.mArguments);
mFragmentTags.set(index, f.mTag);
mFragmentClassNames.set(index, f.getClass().getName());
} else {
Log.w(TAG, "Bad fragment at key " + key);
}
}
}
// If restore will change
notifyDataSetChanged();
}
}
public static void fixActiveFragment(FragmentManager fragmentManager, Fragment fragment) {
FragmentManagerImpl fm = (FragmentManagerImpl) fragmentManager;
if (fm.mActive != null) {
int index = fragment.mIndex;
Fragment origin = fm.mActive.get(index);
if (origin != null) {
if ((origin.mIndex != fragment.mIndex) || !(origin.equals(fragment))) {
Log.e(TAG,
String.format("fixActiveFragment: Not Equal! Origin: %s %s, Fragment: %s $s",
origin.getClass().getName(), origin.mIndex,
fragment.getClass().getName(), fragment.mIndex
));
}
}
fm.mActive.set(index, fragment);
}
}
// Fix
// http://stackoverflow.com/questions/10396321/remove-fragment-page-from-viewpager-in-android
#Override
public int getItemPosition(Object object) {
int index = mFragments.indexOf(object);
if (index < 0) {
return PagerAdapter.POSITION_NONE;
}
boolean isPositionChange = mTempPositionChange[index];
int result = PagerAdapter.POSITION_UNCHANGED;
if (isPositionChange) {
result = PagerAdapter.POSITION_NONE;
}
return result;
}
}
2020 now.
Simple add this to PageAdapter:
override fun getItemPosition(`object`: Any): Int {
return PagerAdapter.POSITION_NONE
}
You could just override the destroyItem method
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
fragmentManager.beginTransaction().remove((Fragment) object).commitNowAllowingStateLoss();
}
I hope this can help what you want.
private class MyPagerAdapter extends FragmentStatePagerAdapter {
//... your existing code
#Override
public int getItemPosition(Object object){
return PagerAdapter.POSITION_UNCHANGED;
}
}

Categories

Resources