I am using Tablayout(android.support.design.widget.TabLayout) with ViePager instantiating 4 fragments to FragmentStatePagerAdapter.
When i scroll through all the fragments are loaded perfectly.But when i select a tab randomly pre-loaded fragment(I know that view pager instantiate neighbor fragments along current fragment) is shown instead of current fragment.
[In my case when i click 3rd tab fragment in 4th position is being shown,same fragment is shown in 4th position too].
How can i correct this situation.
Thanks in advance.
Adapter
public class OrderStatusAdapter extends FragmentStatePagerAdapter {
private final List<Fragment> mFragments = new ArrayList<>();
private final List<String> mFragmentTitles = new ArrayList<>();
public OrderStatusAdapter(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);
}
}
ViewPager
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
if (viewPager != null) {
setupViewPager(viewPager);
if (viewPager != null) {
viewPager.setAdapter(adapter);
tabLayout = (TabLayout) findViewById(R.id.orderStatusTabs);
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
tabLayout.setupWithViewPager(viewPager);
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
}
private void setupViewPager(ViewPager viewPager) {
OrderStatusAdapter adapter = new OrderStatusAdapter(getSupportFragmentManager());
adapter.addFragment(FailedFragment.newInstance(list1, title), "Category 1");
adapter.addFragment(FailedFragment.newInstance(list2, title), "Category 2");
adapter.addFragment(FailedFragment.newInstance(list3, title), "Category 3");
adapter.addFragment(FailedFragment.newInstance(list4, title), "Category 4");
}
It was all because of RecycleView Custom adapter whose instance is not being destroyed and so the previous data is being loaded.So i shifted the adapter inside the fragment and it does the trick.
Related
I have faced an issue where my data is not longer showing in the fragment when i navigate from one tab to another tab and then coming back to the previous tab.
These are the code for my tablayout and viewpager
tabLayout = (TabLayout) findViewById(R.id.tablayout);
Todaybooking = (TabItem) findViewById(R.id.Tab1);
Booking = (TabItem) findViewById(R.id.Tab2);
viewPager = findViewById(R.id.viewpager);
pagerAdapter = new FragmentAdapter(getSupportFragmentManager(), tabLayout.getTabCount());
viewPager.setAdapter(pagerAdapter);
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
if(tab.getPosition() == 0){
pagerAdapter.notifyDataSetChanged();
} else if (tab.getPosition() == 1){
pagerAdapter.notifyDataSetChanged();
}
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
These are the fragmentadapter i have created
public class FragmentAdapter extends FragmentPagerAdapter {
private int numoftabs;
public FragmentAdapter(#NonNull FragmentManager fm, int numoftabs) {
super(fm, numoftabs);
this.numoftabs = numoftabs;
}
#NonNull
#Override
public Fragment getItem(int position) {
switch(position){
case 0:
return new Todaybooking();
case 1:
return new Booking();
default:
return null;
}
}
#Override
public int getCount() {
return numoftabs;
}
#Override
public int getItemPosition(#NonNull Object object) {
return POSITION_NONE;
}
The fragment on Today's booking is not showing once i click the bookings tab and navigate back to the previous tab.
This is probably because you are returning POSITION_NONE in getItemPosition which is
Called when the host view is attempting to determine if an item's position has changed. Returns POSITION_UNCHANGED if the position of the given item has not changed or POSITION_NONE if the item is no longer present in the adapter.
from https://developer.android.com/reference/androidx/viewpager/widget/PagerAdapter#getItemPosition(java.lang.Object)
So Remove the override of getItemPosition you don't need this normally.
Because you are indicating that the current instance of each Fragment is no longer in the list of Fragments it will be cause the Fragment to be re-created each time you visit the Tab that holds it.
I use View-pager to set tab. inside category tab when i click any category load data from internet and i hide all category and data load inside recycleview. but now when I click on category tab I want to visible before view. note please : I want to click same tab and every time it need refresh. please check the image for better understand. Please check my adopter class.
viewPager = (CustomViewPager) findViewById(R.id.tabs_viewpager);
// viewPager.setPagingEnabled(false);
tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
tabFragmentPagerAdapter = new TabFragmentPagerAdapter(getSupportFragmentManager(), MainActivity.this, viewPager);
tabFragmentPagerAdapter.addFrag(new FeatureFragment(), "Feature");
tabFragmentPagerAdapter.addFrag(new DiscoverFragment(), "Discover");
tabFragmentPagerAdapter.addFrag(new TopFragment(), "Top");
tabFragmentPagerAdapter.addFrag(new CategoryFragment(), "Category");
// setupViewPager(viewPager);
viewPager.setAdapter(tabFragmentPagerAdapter);
My Adopter class
public class TabFragmentPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mfragmentlist = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
FragmentManager fragmentManager;
final int[] ICONS = new int[]{
R.drawable.feature,
R.drawable.discover,
R.drawable.top,
R.drawable.category};
public Context context;
public ViewPager viewPager;
public TabFragmentPagerAdapter(FragmentManager fm, Context context, ViewPager viewPager) {
super(fm);
this.context = context;
this.viewPager = viewPager;
this.fragmentManager = fm;
}
public View getTabView(int position) {
// Given you have a custom layout in `res/layout/custom_tab.xml` with a TextView and ImageView
View v = LayoutInflater.from(context).inflate(R.layout.custom_tab, null);
final TextView tv = (TextView) v.findViewById(R.id.textViewMainTabFrag);
tv.setText(mFragmentTitleList.get(position));
ImageView img = (ImageView) v.findViewById(R.id.imgView);
img.setImageResource(ICONS[position]);
return v;
}
public void SetOnSelectView(TabLayout tabLayout, int position) {
TabLayout.Tab tab = tabLayout.getTabAt(position);
View selected = tab.getCustomView();
TextView iv_text = (TextView) selected.findViewById(R.id.textViewMainTabFrag);
iv_text.setTextColor(context.getResources().getColor(R.color.apps_color));
}
public void SetUnSelectView(TabLayout tabLayout, int position) {
TabLayout.Tab tab = tabLayout.getTabAt(position);
View selected = tab.getCustomView();
TextView iv_text = (TextView) selected.findViewById(R.id.textViewMainTabFrag);
iv_text.setTextColor(context.getResources().getColor(R.color.black));
}
public void addFrag(Fragment fragment, String title) {
mfragmentlist.add(fragment);
mFragmentTitleList.add(title);
}
/* #Override
public Fragment getItem(int position) {
return ItemFragment.newInstance();
}*/
#Override
public Fragment getItem(int position) {
return mfragmentlist.get(position);
}
#Override
public int getCount() {
return mFragmentTitleList.size();
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
main activity OnTabSelectedListener here will be good option to reload activity. but how and how to visible my view
#Override
public void onTabUnselected(TabLayout.Tab tab) {
int c = tab.getPosition();
tabFragmentPagerAdapter.SetUnSelectView(tabLayout, c);
}
you can use setUserVisibleHint :
In your fragment:
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser){
//do something //Load or Refresh Data
}
}
OR
In your Activity:
viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// do something //Load or Refresh Data
}
});
check this solutions
Try this ...
public class ListCanali extends Fragment implements OnPageChangeListener{
private MyAdapter mAdapter;
#Override
public View OnCreateView (...) {
...
if(mAdapter == null) {
mAdapter = new MyAdapter(getChildFragmentManager());
}
viewPager.setAdapter(mAdapter);
viewPager.setOnPageChangeListener(this);
...
}
#Override
public void OnPageSelected (int position) {
switch (position){
case 0 :
((FragmentCanali)adapter.getItem(position)).refresh();
case 1 :
((FragmentPreferiti)adapter.getItem(position)).refresh();
}
}
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!
I want to implement Tablayout addOnTabSelectedListener to open a new Activity on a certain tab click. There are 3 tabs and at present they are connected with fragments. I want to start an activity when I click position 1 tab. I can do that in onTabSelected but before opening activity it shows the fragment attached to that same position. How to remove that fragment?
public class MainActivity extends AppCompatActivity {
private TabLayout tabs;
private ViewPager viewpager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tabs = (TabLayout)findViewById(R.id.tabs);
viewpager = (ViewPager)findViewById(R.id.viewpager);
setupViewPager(viewpager);
tabs.addTab(tabs.newTab());
tabs.addTab(tabs.newTab());
tabs.addTab(tabs.newTab());
tabs.setupWithViewPager(viewpager);
tabs.addOnTabSelectedListener(onTabSelectedListener(viewpager));
}
private TabLayout.OnTabSelectedListener onTabSelectedListener(final ViewPager viewPager) {
return new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
};
}
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new Frag1(), "ONE");
adapter.addFragment(new Frag2(), "TWO");
adapter.addFragment(new Frag3(), "THREE");
viewPager.setAdapter(adapter);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabs));
onTabSelectedListener(viewPager);
}
class ViewPagerAdapter extends FragmentPagerAdapter {
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();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
}
private TabLayout.OnTabSelectedListener onTabSelectedListener(final ViewPager viewPager) {
return new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
};
}
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new Frag1(), "ONE");
adapter.addFragment(new Frag2(), "TWO");
adapter.addFragment(new Frag3(), "THREE");
viewPager.setAdapter(adapter);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabs));
onTabSelectedListener(viewPager);
}
class ViewPagerAdapter extends FragmentPagerAdapter {
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();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
}
try this:
use a FragmentStatePagerAdapter instead 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
Also Override the adapter method getItemPosition
For example:
private class ViewPagerAdapter extends FragmentStatePagerAdapter {
//... your existing code
#Override
public int getItemPosition(Object object){
return PagerAdapter.POSITION_NONE;
}
}
source
it will recreate your fragment each time instead of loading them from memory first..
To start activity do it in your particular fragment's onCreate()
Hope this helps..
I had same requirement, what i did is overlap textview on center of TabLayout using RelativeLayout & apply click event on textview. I can not post my layout please refer demo image
Hi I have a TabLayout and ViewPager inside a fragment. But I can not slide beetween tab to come to child fragment (Working normally when in Activity but not work in fragment).
Here is my code for Tablayout inside fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View inflateView = inflater.inflate(R.layout.fragment_assign_beacon_to_event, container, false);
//Viewpager and TabLayout
viewPager = (ViewPager)inflateView.findViewById(R.id.viewPager);
viewPager.setAdapter(new CustomAdapter(getFragmentManager(), getContext()));
tabLayout = (TabLayout)inflateView.findViewById(R.id.tabLayout);
// Inflate the layout for this fragment
return inflateView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
tabLayout.post(new Runnable() {
#Override
public void run() {
tabLayout.setupWithViewPager(viewPager);
}
});
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
});
Any here is my Custom Adapter class
private class CustomAdapter extends FragmentPagerAdapter {
private String fragments[] = {"Assign Event", "Manage Event"};
public CustomAdapter(FragmentManager supportFragmentManager, Context applicationContext) {
super(supportFragmentManager);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
// return new AssignEventToBeacon();
return new Test1();
case 1:
return new ManageEventAssigned();
default:
return null;
}
}
#Override
public int getCount() {
return fragments.length;
}
#Override
public CharSequence getPageTitle(int position) {
return fragments[position];
}
}
I doubt i have problem with this line:
viewPager.setAdapter(new CustomAdapter(getFragmentManager(), getContext()));
Anyhelp is much appreciate, thanks
I have done a similar project and here is my code for the fragment :
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.outer_fragment, container, false);
setHasOptionsMenu(true);
ViewPager viewPager = (ViewPager) view.findViewById(R.id.viewpager);
if (viewPager != null) {
setupViewPager(viewPager);
}
Log.v("Layout","Tabs");
TabLayout tabLayout = (TabLayout) view.findViewById(R.id.tabs);
tabLayout.setSelectedTabIndicatorColor(Color.parseColor("#FFFFFF"));
tabLayout.setTabTextColors(Color.parseColor("#707070"), Color.parseColor("#FFFFFF"));
assert viewPager != null;
tabLayout.setupWithViewPager(viewPager);
return view;
}
private void setupViewPager(ViewPager viewPager) {
Adapter adapter = new Adapter(getChildFragmentManager());
adapter.addFragment(new Tab1Fragment(), "PHOTOS");
adapter.addFragment(new Tab2Fragment(), "HI-FIVES");
viewPager.setAdapter(adapter);
}
static 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);
}
}
You need to use getChildFragmentManager() in Fragment instead of getFragmentManager().
From getChildFragmentManager() documentation
Return a private FragmentManager for placing and managing Fragments
inside of this Fragment.
From getFragmentManager() documentation
Return the FragmentManager for interacting with fragments associated
with this fragment's activity.
In simple words,
Use getChildFragmentManager() for Child Fragments
Use getFragmentManager() for Fragments inside Activity
One can see #this answer for complete code.