ViewPager Not Synched with TabLayout - android

I have a ViewPager and Tablayout that shows nth number of items. The Tabs are populated with the correct page titles and the ViewPager contained Fragments display the correct fine except that the selected Tab is not synched with the ViewPager current item.
The selected Tab position is 1 less than the position of viewpager current item. Here is the Viewpager adapter.
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
public ViewPagerAdapter(FragmentManager fm){
super(fm);
}
#Override
public Fragment getItem(int position) {
Recipe selectedRecipe = getRecipeList().get(position);
return RecipeDetailFragment.newInstance(selectedRecipe.getId);
}
#Override
public int getCount() {
return .getRecipeList().size();
}
#Override
public CharSequence getPageTitle(int position) {
Recipe selectedRecipe = .getRecipeList().get(position);
String title = selectedRecipe.getTitle();
return title ;
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
Here is how I setup the ViewPager
private void setupViewPager() {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
tabLayout.setupWithViewPager(viewPager);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
}
Here is what the output looks like
Edit 1:
I think the problem have to do with how the getItem method of the ViewPager is being called, here is log of left and right scroll for10 items

instead of using static variable in fragment you can use,
public function in fragment like below.
add
#Override
public Fragment getItem(int position) {
Recipe selectedRecipe = getRecipeList().get(position);
RecipeDetailFragment receiptFRagment= new ReceiptFragment();
receiptFragment.setData(selectedRecipe.getId);
return receiptFragment;
}
instead of this
#Override
public Fragment getItem(int position) {
Recipe selectedRecipe = getRecipeList().get(position);
return RecipeDetailFragment.newInstance(selectedRecipe.getId);
}
Add public function in fragment,
public void setData(int id){
this.id= id;
}

Finally, this is how I synched the ViewPager selected item with the Tablayout selected tab.
void selectPage(final int pageIndex){
new Handler().postDelayed(
new Runnable() {
#Override public void run() {
tabLayout.setSmoothScrollingEnabled(true);
tabLayout.setScrollPosition(pageIndex, 0f, true);
}
}, 100);
}
Then I called this method from two places, first when I setup Viewpager
recipePosition = getIntent().getIntExtra(Constants.RECIPE_POSITION, 0);
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
tabLayout.setupWithViewPager(viewPager);
if (recipePosition > 0){
recipePosition--;
}
viewPager.setCurrentItem(recipePosition,true);
selectPage(recipePosition);
And then second in the setItem
Recipe selectedRecipe = getRecipeList().get(position);
RecipeDetailFragment receiptFRagment= new ReceiptFragment();
receiptFragment.setData(selectedRecipe.getId);
selectPage(position);
return receiptFragment;
Its works, I still could not understand why these are not synched by default!

Related

ViewPager with FragmentStatePagerAdapter keeps recreating deleted fragments

Need a help with dynamic ViewPager with EditText (straggling to do a multiple tabbed editor).
Here are problems I faced:
e. g. I create 3 pages and put some text, so I have
page0 - "a"
page1 - "b"
page2 - "c"
Adding works normally here, removing page0 leads not to "a" "c" but to "a" "b" left, removing page0 leads to "a" "b" instead of "b" "c" as well, removing page2 is ok. So it seems like pager remembers text of removed page n and moves it to page n+1, text from page n+1 to n+2 and so on
same pages with the same text, but now I remove page1 and page2 (the order doesn't matter) so text "a" left. Adding two new pages will recreate "b" and "c", next pages would be blank as they should be.
if I remove just page1 and add new page, text "c" will appear.
I've been here, here and here, no help.
Tried to follow getItem(int position) calls
Also searched ViewPager and FragmentStatePagerAdapter sources, it looks like it has smth to do with instantiateItem and/or destroyItem but I have no clue what exactly.
Here is my code:
Adapter
public class PagerAdapter extends FragmentStatePagerAdapter {
private ArrayList<Fragment> fragmentsList = new ArrayList<>();
private ArrayList<String> titlesList = new ArrayList<>();
private TabLayout layout;
public PagerAdapter(FragmentManager manager, Context context, ViewPager pager, TabLayout layout) {
super(manager);
this.layout = layout;
}
#Override
public Fragment getItem(int position) {
return fragmentsList.get(position);
}
#Override
public int getItemPosition(#NonNull Object object) {
return POSITION_NONE;
}
#Override
public int getCount() {
return fragmentsList.size();
}
#Override
public CharSequence getPageTitle(int position) {
return titlesList.get(position);
}
public void addFrag(Fragment f, String s) {
fragmentsList.add(f);
titlesList.add(s);
}
public void removeFragment(int position) {
if (layout.getChildCount() > 0)
layout.removeTabAt(position);
Fragment fragment = fragmentsList.get(position);
fragmentsList.remove(fragment);
titlesList.remove(position);
FragmentManager manager = fragment.getFragmentManager();
FragmentTransaction trans = manager.beginTransaction();
trans.remove(fragment);
trans.commit();
notifyDataSetChanged();
}
}
RootFragment
public class RootFragment extends Fragment {
private TabLayout layout;
private ViewPager pager;
private PagerAdapter adapter;
private int currentTab;
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.root_fragment, container, false);
pager = view.findViewById(R.id.viewpager);
layout = view.findViewById(R.id.sliding_tabs);
adapter = new PagerAdapter(getFragmentManager(), getActivity(), pager, layout);
pager.setAdapter(adapter);
layout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
currentTab = tab.getPosition();
pager.setCurrentItem(currentTab);
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
return view;
}
public void addTab(String title) {
Bundle bundle = new Bundle();
bundle.putString("data", title);
LeafFragment leafFragment = new LeafFragment();
leafFragment.setArguments(bundle);
adapter.addFrag(leafFragment, title);
adapter.notifyDataSetChanged();
layout.setupWithViewPager(pager);
currentTab = adapter.getCount() - 1;
pager.setCurrentItem(currentTab);
}
public void deleteTab(int position) {
adapter.removeFragment(position);
}
}
Thanks and sorry for my English.
FragmentStatePagerAdapter already stores a list of Fragments, you don't need (and potentially, you should not) implement your own list while using it. Simply:
public class MyAdapter extends FragmentStatePagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
return 3;
}
#Override
public Fragment getItem(int position) {
//Simply create a fragment based on position here
}
}
Second, the unfortunate truth is, removing/reordering fragments in a FragmentStatePagerAdapter appears to have still open bugs as here:
https://issuetracker.google.com/issues/36956111
My suggestion is to simply re-create the adapter if you need to delete fragments from the adapter.

How to update a recyclerview in current tab inside viewpager, which contains 4 tabs with the same reciclerview and adapter

I have a viewpager with 4 tabs (fragments), each tab contains the same fragment with a recyclerview. I want update the checkboxes inside the cardviews of recyclerview, from checkbox click (view bottom of images) that have the main activity. The problem is that no refresh the checkbox of current tab, for example, if I click the checkbox from the first page, refresh the checkbox of the recyclerview of last tab, its very extrange. Maybe a bug?
This is mi pager adapter:
private void setupViewPager(ViewPager viewPager) {
Adapter adapter = new Adapter(getChildFragmentManager());
adapter.addFragment(new DiaFragment(), viewPagerTitles[0]);
adapter.addFragment(new DiaFragment(), viewPagerTitles[1]);
adapter.addFragment(new DiaFragment(), viewPagerTitles[2]);
adapter.addFragment(new DiaFragment(), viewPagerTitles[3]);
viewPager.setAdapter(adapter);
}
class Adapter extends FragmentPagerAdapter {
private final List<Fragment> mFragments = new ArrayList<>();
private final List<String> mFragmentTitles = new ArrayList<>();
public Adapter(FragmentManager fm) {
super(fm);
}
public void addFragment(Fragment fragment, String title) {
mFragments.add(fragment);
mFragmentTitles.add(title);
}
#Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
#Override
public int getCount() {
return mFragments.size();
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitles.get(position);
}
}
This is my code to refresh current recyclerview:
CheckBox CBmarcarTodos = (CheckBox) getActivity().findViewById(R.id.CBmarcarTodos);
CBmarcarTodos.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (CBmarcarTodos.isChecked()) {
((MonedaSerieAdapter) mRecyclerView.getAdapter()).setChecked(true);
} else {
((MonedaSerieAdapter) mRecyclerView.getAdapter()).setChecked(false);
}
mRecyclerView.getAdapter().notifyDataSetChanged();
ViewPager viewPager = (ViewPager) getActivity().findViewById(R.id.viewpager);
viewPager.getAdapter().notifyDataSetChanged();
}
});
View image
This is the method inside recyclerview adapter to checked/unchecked the checkbox
public void setChecked(Boolean valor) {
visibleCheckBox = new ArrayList<>();
for (int i = 0; i < allCheckBox.size(); i++) {
visibleCheckBox.add(valor);
}
notifyDataSetChanged();
}

opening a layout (xml) inside a fragment instead of string text input

Problem: I was modifying a small app where three tabs are there in fragment but all refers to text string. I wanted to use layout xml so that I can make good graphics in it. How can I do it in this code:
Information_tab refers to a string where I can put text, but I want a layout.
public class AdapterInformation extends FragmentPagerAdapter {
public AdapterInformation(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int index) {
Bundle bundle = new Bundle();
int imgResId = 0;
int tab = 0;
int colorResId = 0;
switch (index) {
case 0:
tab = R.string.information_tab1;
break;
case 1:
tab = R.string.information_tab2;
break;
case 2:
tab = R.string.information_tab3;
break;
}
bundle.putInt("image", imgResId);
bundle.putInt("tab",tab);
bundle.putInt("color", colorResId);
SwipeTabFragment swipeTabFragment = new SwipeTabFragment();
swipeTabFragment.setArguments(bundle);
return swipeTabFragment;
}
#Override
public int getCount() {
return 3;
}}
you can add fragment layout like this.
private void setupViewPager(final ViewPager viewPager) {
final ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new OneFragment(), "Pending Upload");
adapter.addFragment(new TwoFragment(), "Complete Upload");
viewPager.setAdapter(adapter);
}
and your fragmentPagerAdapter code is like this:
public 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(Object object) {
return 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);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
and also add your setupViewPager method in onCreate()
viewPager = (ViewPager) findViewById(R.id.viewpager);
tabLayout = (TabLayout) findViewById(R.id.tabs);
setupViewPager(viewPager)
tabLayout.setupWithViewPager(viewPager);
Note: Do not use getItemPosition() method if its possible.. it
will produce redundancy of your listItems or ArrayList.. bcz every
time you swipe to other layout it will refresh page automatically..
its good if want this facility.. but you have write some code
regarding to handle this method.. and its also going to slow your
swipe animation if you have large amount of data.
For more information about tab layout and fragment: you can refer this one:
http://www.androidhive.info/2015/09/android-material-design-working-with-tabs/

Android add fragment and tab after load?

I have a FragmentActivity with two Fragments in it and a sliding tab layout:
String titles[] = new String[] {"Tab One", "Tab Two"};
int numTabs = titles.length;
EventAdapter adapter = new EventAdapter(getSupportFragmentManager(), titles, numTabs);
ViewPager pager = (ViewPager) findViewById(R.id.pager);
pager.setAdapter(adapter);
SlidingTabLayout sliding_tabs = (SlidingTabLayout) findViewById(R.id.sliding_tabs);
sliding_tabs.setDistributeEvenly(true);
sliding_tabs.setViewPager(pager);
With the FragmentPagerAdapter:
private class EventAdapter extends FragmentPagerAdapter {
private List<String> titles;
private int numTabs;
public void addTab (String title) {
this.titles.add(title);
this.numTabs++;
this.notifyDataSetChanged();
}
public EventAdapter(FragmentManager fm, List<String> mTitles, int mNumTabs) {
super(fm);
this.titles = mTitles;
this.numTabs = mNumTabs;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 2:
return new FragThree();
case 1:
return new FragTwo();
default:
return new FragOne();
}
}
#Override
public String getPageTitle(int position) {
return titles.get(position);
}
#Override
public int getCount() {
return numTabs;
}
}
Some time down the line, I would like to dynamically add the third tab to this layout. Is there a way to do this in code? As you can see, I already have the PagerAdapter set up to catch the third tab. I just need to load it in...
You need to add this method to your adapter EventAdapter :
public void addTab (String title) {
this.titles.add(title);
// this is the variable returned from getCount method
this.numbTabs++;
this.notifyDataSetChanged();
}
Main purpose is to add the tab and call notifydatasetchanged.
Now call addTab on this adapter's object and tab will be added.
after addTab do sliding_tab.setViewPager(this.pager);
Please accept if this solves the purpose.

View pager fragments and Tabs are out of sync android

In my project I have a tab layout and a fragments viewpager. When I load the fragments and tabs the tab index and the displayed fragment is out of sync, and also when I swipe back and forth the fragments are not in sync with the tabs. I checked the getItem(int position) and the getTitle(int position) methods both have the same position number and the corresponding entries in the ArrayList<Fragments> and the ArrayList<String> (for tab headings) are correct but some how the tabs display is out of sync with the view pager.
Here is my fragmentPagerAdapter.java
public class DetailsFragmentPagerAdapter extends FragmentPagerAdapter {
private ArrayList<Fragment> fragments;
private ArrayList<String> titles;
public DetailsFragmentPagerAdapter(FragmentManager fm) {
super(fm);
fragments = new ArrayList<>();
titles = new ArrayList<>();
}
#Override
public Fragment getItem(int position) {
return fragments.get(position);
}
#Override
public int getCount() {
return titles.size();
}
#Override
public CharSequence getPageTitle(int position) {
return titles.get(position);
}
public void setFragment(Fragment fragment, String title) {
fragments.add(fragment);
titles.add(title);
notifyDataSetChanged();
}
}
this is activity on create.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_details);
tabLayout = (TabLayout) findViewById(R.id.detailsTabs);
viewPager = (ViewPager) findViewById(R.id.viewPager);
new GetCategoriesAsync2().execute();
}
the async task's doInBackground is calling is preparing arraylist
and the onPostExecute
#Override
protected void onPostExecute(Void aVoid) {
int size = lists.size();
ArrayList<Fragment> fragments = new ArrayList<>(size);
ArrayList<String> titles = new ArrayList<>(size);
for (int i = 0; i < lists.size(); i++) {
ArrayList<String> x = lists.get(i);
titles.add(x.remove(0));
fragments.add(DetailsListFragment.newInstance(x));
}
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentPagerAdapter = new DetailsFragmentPagerAdapter(fragmentManager);
fragmentPagerAdapter.setFragments(fragments,titles);
viewPager.setAdapter(fragmentPagerAdapter);
tabLayout.setupWithViewPager(viewPager);
progressDialog.dismiss();
}
I am using design support library 23.0.1 and the build target is 23.
how can I fix this tab layout out of sync?
if you use a TabLayout, you need to connect it to the adapter
If you're using a ViewPager together with this layout, you can use
setTabsFromPagerAdapter(PagerAdapter) which will populate the tabs
using the given PagerAdapter's page titles. You should also use a
TabLayout.TabLayoutOnPageChangeListener to forward the scroll and
selection changes to this layout like so:
ViewPager viewPager = ...;
TabLayout tabLayout = ...;
viewPager.addOnPageChangeListener(new TabLayoutOnPageChangeListener(tabLayout));
Try this, it worked for me
public class DetailsFragmentPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> fragments= new ArrayList<Fragment>();
private final List<String> titles= new ArrayList<String>();
public DetailsFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return fragments.get(position);
}
#Override
public int getCount() {
return fragments.size();
}
#Override
public CharSequence getPageTitle(int position) {
return titles.get(position);
}
public void setFragment(Fragment fragment, String title) {
fragments.add(fragment);
titles.add(title);
}
}
And Change
fragmentPagerAdapter.setFragments(fragments,titles); To
for (int i=0;i<fragments.size();i++)
{
adapter.setFragments(fragments.get(i),titles.get(i));
}
Check this out
it's a demo app that uses a TabLayout with a ViewPager
https://github.com/chrisbanes/cheesesquare
and if you don't know the number of the fragments that you will have in the ViewPager
your pageadapter should extends FragmentStatePagerAdapter
https://developer.android.com/reference/android/support/v4/app/FragmentStatePagerAdapter.html

Categories

Resources