Dynamically change the title of a android.support.v4.view.PagerTitleStrip - android

I am currentky using a PagerTitleStrip in my application
(Doc: http://developer.android.com/reference/android/support/v4/view/PagerTitleStrip.html)
Everything works fine, and I have set the title like this:
public class PageAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
public PageAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
#Override
public Fragment getItem(int position) {
return this.fragments.get(position);
}
#Override
public int getCount() {
return this.fragments.size();
}
String[] titles = { "1", "2", "3", "4","5" };
#Override
public CharSequence getPageTitle(int position) {
return titles[position];
}
}
My concern now, is that once the first Fragment has finished loading, I have to change the title of the strip.
I have already tried to get the FragmentPagerAdapter and tried to manipulate it, but never succeed to change a title (text)
There is indeed a getPageTitle method: mPagerAdapter.getPageTitle(position) but no setPageTitle ...
Any idea or suggestion?

If I understand problem correctly - you get data later and then want to update titles array and trigger refresh of titles.
If that's the case just trigger PagerAdapter.notifyDataSetChanged(); after that method is invoked Fragments will call getPageTitle method and update themselves.

Kind of ugly solution but working : iterate to the visual tree and set the text yourself.
Also, you have to be aware that there is a first transparent/empty item on the left.
Here is the code (Xamarin here) to update the first title.
var firstHidedOneFound = false;
for (int i = 0; i < _tabstrip.ChildCount; ++i)
{
var child = _tabstrip.GetChildAt(i) as TextView;
if (child == null) { continue; }
if (!firstHidedOneFound)
{
firstHidedOneFound = true;
continue;
}
child.Text = ViewModel.MyShowPanelTitle;
break;
}

Related

FragmentPagerAdapter strange behavior

So i have the next problem with FragmentPagerAdapter. I have a TabLayout with 3 tabs representing 3 fragments that i can switch. So when i switch to third fragment, for some reason the first one disappears (or its view). Does anyone know how to fix this problem? Thanks in advance.
public class SectionsPagerAdapter extends FragmentPagerAdapter {
private static final int FRAGMENT_COUNT = 3;
private final List<Fragment> listOfFragments = new ArrayList<>();
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return listOfFragments.get(position);
}
#Override
public int getCount() {
return FRAGMENT_COUNT;
}
public void addFragment(Fragment fragment) {
listOfFragments.add(fragment);
}
}
This is the code for FragmentPagerAdapter.
And i think i fixed this :) Only thing i did is to override the FragmentPagerAdapter destroyItem() method, with empty body (no super).
I don't know what is your problem. but if in your app only 3 fragments are there than you can try setOffscreenPageLimit method of ViewPager
ViewPager.setOffscreenPageLimit(3);
One of the problems here is a slightly confusing API.
In FragmentPagerAdapter, getItem(int position) actually means "create item". In other words, you shouldn't try to manually cache the Fragments inside a list in your Adapter.
#Override
public Fragment getItem(int position) {
return listOfFragments.get(position); //No! don't do this
}
Even though it may see counter-intuitive, you should actually create a new instance of the Fragment you want inside getItem, sticking very closely to the official Google example:
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return FirstFragment.getInstance();
case 1:
return SecondFragment.getInstance();
}
}
Otherwise you will run into problems where the FragmentManager's cache and your own List<Fragment> cache are out-of-sync. In short, caching of Fragments is handled by the FragmentManager and you don't need to roll-your-own caching.
I don't know really what happen but this is my code, hope this help you
public class AdapterFragmentViewPager extends FragmentPagerAdapter {
private List<Fragment> fragmentList = new ArrayList<>();
public AdapterFragmentViewPager(FragmentManager fm) {
super(fm);
}
public void addFragment(Fragment fragment) {
fragmentList.add(fragment);
}
#Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
#Override
public int getCount() {
return fragmentList.size();
}
}
and this is my Tablayout:
private AdapterFragmentViewPager adapterFragmentViewPager = new AdapterFragmentViewPager(getSupportFragmentManager());
TabLayout.Tab home = tabLayout.newTab();
tabLayout.addTab(home);
TabLayout.Tab newest = tabLayout.newTab();
tabLayout.addTab(newest);
TabLayout.Tab author = tabLayout.newTab();
tabLayout.addTab(author);
TabLayout.Tab category = tabLayout.newTab();
tabLayout.addTab(category);
TabLayout.Tab saved = tabLayout.newTab();
tabLayout.addTab(saved);
adapterFragmentViewPager.addFragment(FragmentHome.newInstance());
adapterFragmentViewPager.addFragment(FragmentQuote.newInstance());
adapterFragmentViewPager.addFragment(FragmentAuthor.newInstance());
adapterFragmentViewPager.addFragment(FragmentCategory.newInstance());
adapterFragmentViewPager.addFragment(FragmentFavorites.newInstance());
viewPager.setAdapter(adapterFragmentViewPager);
tabLayout.setupWithViewPager(viewPager);

Fragment keep being restored after destroyed/nulled

Im using my Custom FragmentAdapter to hold the fragment into a List
The Process i want:
1) User click in a list item and it create a new Activity within arguments and than create the fragment using the TagsPageAdapter.addPage(fragment);
2) This created fragment has a "id" int inside his arguments
3) When i hit the addPage, it verify all the fragments inside the List to check if any fragments has the id, if yes, restore it, if not, than create new and add to the list
this 3 steps are working perfeclty, the problem is when i try to remove one (error after the adapter code below)
adapter:
private class TabsPagerAdapter extends FragmentPagerAdapter {
private Bundle bundle;
private String titulo;
private TabsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public LeiAberta getItem(int position) {
current = fragments.get(position);
return current;
}
private void addPage(LeiAberta page) {
boolean found = false;
for (int i = 0; i < fragments.size(); i++) {
leiAberta = fragments.get(i);
if (leiAberta != null) {
if (leiAberta.getArguments() != null) {
if (leiAberta.getArguments().getInt("id") == page.getArguments().getInt("id")) {
viewPager.setCurrentItem(i);
found = true;
}
}
}
}
if (!found) {
fragments.add(page);
notifyDataSetChanged();
viewPager.setCurrentItem(fragments.size() - 1);
}
}
#Override
public int getCount() {
return fragments.size();
}
#Override
public CharSequence getPageTitle(int position) {
this.bundle = fragments.get(position).getArguments();
if (this.bundle != null) {
this.titulo = bundle.getString("titulo");
}
return titulo;
}
}
what im using to remove the fragment from the list:
int current_position = viewPager.getCurrentItem();
if(current_position == 0) {
viewPager.setCurrentItem(current_position +1);
} else {
viewPager.setCurrentItem(current_position -1);
}
fragments.remove(current_position);
adapter.notifyDataSetChanged();
if i remove the current tab/fragment, and then open another item in the list that will add another tab, no matter what item, it just restores the old fragment in the same position, for some reason the position of the removed fragment in the List keep filled in the shadows, and the strange thing is: the list.size(); decrease when i remove, so WHY? From where is this old fragment restored? how can i really destroy it, so the addPage doesnt find it in the "shadows"
i had tried:
Update ViewPager dynamically?
Removing fragments from FragmentStatePagerAdapter
Remove Fragment Page from ViewPager in Android
How to remove pages in Android ViewPager?
and many others
apparently the only solution was this framework:
https://github.com/inloop/UpdatableFragmentStatePagerAdapter?utm_source=android-arsenal.com&utm_medium=referral&utm_campaign=4851
using this override
#Override
public int getItemPosition(Object object) {
if (fragments.contains(object)) return fragments.indexOf(object);
else return POSITION_NONE;
}

Android FragmentPagerAdapter Circular listview

I want to create a circular listview in android, however I'm using/extending FragmentPagerAdapter and I want to check the item position in order to check the next item in circular listview.
I just want to develop a infinite listview which will repeat itself when the scroll ends.
My Code:
private class ListPageAdapter extends FragmentPagerAdapter {
private String[] items={"Item1","Item2","Item3","Item4", "Item5", "Item6", "Item7", "Item8"};
public ListPageAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
Fragment sampleFragment=new SampleFragment();
Bundle bundle=new Bundle();
bundle.putString("text","FragmentNumber"+i);
sampleFragment.setArguments(bundle);
return sampleFragment;
}
#Override
public int getCount() {
return items.length;
}
#Override
public CharSequence getPageTitle(int position) {
return items[position];
}
}
How I can make the Item1 after Item8 to make it a circular listview?
What about something like:
bundle.putString("text","FragmentNumber"+(i % items.length));
I didn't test it but I would say that it could work :D

Viewpager with fragments

I have a viewpager in my app with 7 fragments, each represent their own logic
however, there are 2 fragments that are mutually coupled, one cannot exist without the other.
I have 2 buttons, previous and next at the bottom of the screen which switch between the fragments.
I want to make it so the swiping in the viewpager cannot reach one of the coupled fragments
Right now I did this: I put the first fragment (of the coupled ones) to be at location 0, and the 2nd fragment at the last position, so that when you swipe left and right you reach the 2nd coupled fragment last.
I want to make it so you can't reach the last fragment with swiping
how to do that ?
EDIT:
Fragment Adapter
public class PurchaseFragmentStatePagerAdapter extends FragmentStatePagerAdapter {
private List<BaseFragment> fragments;
private boolean shouldShowLastFragment;
#Inject
public PurchaseFragmentStatePagerAdapter(FragmentManager fm) {
super(fm);
}
public void setFragments(List<BaseFragment> fragments) {
this.fragments = fragments;
}
#Override
public BaseFragment getItem(int position) {
return fragments.get(position);
}
#Override
public int getCount() {
return fragments == null ? 0 : shouldShowLastFragment ? fragments.size() : fragments.size()-1;
}
public void enableItem(int i) {
shouldShowLastFragment = true;
notifyDataSetChanged();
}
public void disableItem(int i) {
shouldShowLastFragment = false;
notifyDataSetChanged();
}
}
I assume you have either a FragmentStatePagerAdapter or a FragmentPagerAdapter.
In your adapter, setting the getCount() method to 6, will make sure that you cannot reach the last fragment.
#Override
public int getCount() {
return 6;
}

Fragment constantly updated

I've got a FragmentActivity when I instantiate three different (n, n+1, n+2) Fragments.
I need to keep each Fragment updated when user swipes to it, so I used ViewPager.SimpleOnPageChangeListener.onPageSelected in the Fragment Activity, so when user swipes to n+1 or n+2 Fragment and again to n that function update the content.
Without using this workaround if I'm in the Fragment n+1, both n and n+2 are already loaded! I'd like instead that the Fragment load when the user swipes to it, without "pre-load".
This workaround works fine for me but it has a problem: the n Fragment that is the first in the list at start up of the app doesn't load its content. To load its content I have to swipe to n+1 then go back to n.
I know that the content of the Fragment should be setted on the class called at the moment of instantiate the fragment and that extends Fragment class, but in this way I don't know how to keep up to date each Fragment, as I do using onPageSelected.
Any suggestions?
EDIT 1:
I istantiate my fragments in this way in onCreate():
for(int x = 0; x < 3; x++) {
Bundle b = new Bundle();
b.putString( "id" , x );
Fragment myFrag = Fragment.instantiate( myContext , Mm_FragmentPage.class.getName() );
myFrag.setArguments( b );
fragments.add(myFrag);
}
Then I set the adapter in the ViewPager:
mPagerAdapter = new PagerAdapter( super.getSupportFragmentManager() , fragments );
mPager.setAdapter( mPagerAdapter );
Then I use the adapter in the TitlePageIndicator
titleIndicator = (TitlePageIndicator) findViewById( R.id.titleFragments );
titleIndicator.setViewPager( mPager );
titleIndicator.setOnPageChangeListener( new myPageChangeListener() );
And, at the end, the class PagerAdapter:
public class PagerAdapter extends FragmentPagerAdapter
{
// fragments to instantiate in the viewpager
private List<Fragment> fragments;
// constructor
public PagerAdapter(FragmentManager fm, List<Fragment> fragments)
{
super(fm);
this.fragments = fragments;
}
// return access to fragment from position, required override
#Override
public Fragment getItem(int position)
{
return this.fragments.get(position);
}
// number of fragments in list, required override
#Override
public int getCount()
{
return this.fragments.size();
}
#Override
public CharSequence getPageTitle(int position)
{
return getResources().getStringArray( R.array.tab_header_name )[ position ];
}
}
OK, so first thing you need to set OnPageChangeListener on the ViewPager and implement method onPageSelected(int i) and call the adapter's notifyDataSetChanged(), like so:
mPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int i, float v, int i2) {
}
#Override
public void onPageSelected(int i) {
//Tell the adapter that the content was changed
mPager.getAdapter().notifyDataSetChanged();
}
#Override
public void onPageScrollStateChanged(int i) {
}
});
In order to keep the fragments updated, you need to extends FragmentStatePagerAdapter and not FragmentPagerAdapter like what you did. The difference is that with FragmentPagerAdapter the ViewPager will never re-create the fragments, while in FragmentStatePagerAdapter it will.
Then on getItem(..) make sure to return a new instance of the fragment with the new content by passing the content to its arguments via setArguments(). Then override also getItemPosition(..) to tell the adapter that the fragment is not found, and therefore it must re-create it.
public class MyPagerAdapter extends FragmentStatePagerAdapter {
//List to hold the fragments to be shown
//NOTE: It's a list of Fragment classes, not a list of Fragment instances!
private List<Class<? extends Fragment> fragments;
public MyPagerAdapter(FragmentManager fm) {
super(fm);
fragments.add(SomeFragment.class);
fragments.add(AnotherFragment.class);
fragments.add(MoreFragment.class);
}
#Override
public Fragment getItem(int i) {
try {
//Creates a new instance of the fragment
Fragment instance = fragments.get(i).newInstance();
//Put the new content by passing Bundle with new content
instance.setArguments(args);
return instance;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
#Override
public int getItemPosition(Object object) {
//NOTE: you might want to put better logic here
return POSITION_NONE;
}
#Override
public int getCount() {
return pages.size();
}
}
Every time you slide from one fragment to another, onPageSelected() will be fired calling notifyDataSetChanged() which will force the adapter to check also if the position of the fragment has changed. Since we return POSITION_NONE in getItemPosition(..), the adapter thinks that the position changed and will then call getItem(i). In getItem(i) we return a new instance (optionally, passing new arguments). Problem solved! :)
I just tested it by myself, created a small app that have a counter which increases everytime the user slides the page and it works!
This way you can drop the ViewPager.SimpleOnPageChangeListener.onPageSelected.
Learn more about ViewPager.

Categories

Resources