I need to switch next tab, when a button is clicked from a child fragment.
This is how I setup tabs in parent,
TabAdapter adapter;
private void setUpTabs(ViewPager viewPager) {
adapter = new TabAdapter(getSupportFragmentManager());
adapter.addFragment(new FirstTabFragment(), "First Tab");
adapter.addFragment(new SecondTabFragment(), "Second Tab");
viewPager.setAdapter(adapter);
}
And my TabAdapter class is,
public class TabAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public TabAdapter(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);
}
}
I created a method to switch tab inside Parent
TabLayout myTabs= (TabLayout) findViewById(R.id.my_tabs);
Button chkBtn = (Button) findViewById(R.id.check_button);
chkBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
viewPager.setCurrentItem(1);
}
});
Switching tabs inside parent class works fine. But how could I Do the same inside FirstTabFragment, Please help me.
You should call
viewPager.setCurrentItem(fragmentIdex);
you should use setCurrentItem(int item)
Set the currently selected page. `
sample code
chkBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
viewPager.setCurrentItem(2);
}
});
Just to make your UI more Interactive and good looking, I'm gonna share what I've implemented.
Just to access your viewPager from the fragment's java file, declare your viewPager as below in your parent activity.
public static ViewPager viewPager;
Then in the onClick method or onClickListener of a button in the fragment, you can just use this.
ParentActivity.viewPager.arrowScroll(View.FOCUS_RIGHT);
This will smooth scroll your viewpager to the Second Fragment, and yes, if you want to limit the user from scrolling directly you can disable the scrolling of viewPager, read here.
You can also shift the focus to left if user wants to go back to FirstFragment by just
ParentActivity.viewPager.arrowScroll(View.FOCUS_LEFT);
And yes, it's working as I first test before posting answers, silly me.
Related
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);
I have an activity named: ShoppingListActivity in which i have added 3 fragments. For this example i will use only one fragment. In onCreate method i have declared a ViewPager that looks like this:
ViewPager viewPager = (ViewPager) findViewById(R.id.view_pager);
and a setupViewPager(viewPager); method that looks like this:
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
Fragment shoppingListFragment = new ShoppingListFragment();
getSupportFragmentManager().beginTransaction().add(shoppingListFragment, "ShoppingListFragmentTag").commit();
adapter.addFragment(shoppingListFragment, "SHOPPING LIST");
viewPager.setAdapter(adapter);
}
My ViewPagerAdapter class lookslike this:
private class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> fragmentList = new ArrayList<>();
private final List<String> fragmentTitleList = new ArrayList<>();
ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
#Override
public int getCount() {
return fragmentList.size();
}
void addFragment(Fragment fragment, String title) {
fragmentList.add(fragment);
fragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return fragmentTitleList.get(position);
}
}
My problem is when i go from ShoppingListActivity to another activity and than come back, my fragments are not refreshed. This is my code from onResume method in which i try to find the fragment to detach and attach the fragment like this:
FragmentManager fragmentManager = getSupportFragmentManager();
ShoppingListFragment shoppingListFragment = (ShoppingListFragment) fragmentManager.findFragmentByTag("ShoppingListFragmentTag");
fragmentManager.beginTransaction().detach(shoppingListFragment).attach(shoppingListFragment).commit();
The problem is that i get this error: java.lang.IllegalStateException: Can't change tag of fragment ShoppingListFragment{528673f4 #0 ShoppingListFragmentTag}: was ShoppingListFragmentTag now android:switcher:2131558559:0
How can i set the Tag correctly to the fragment?
Thanks in advance!
from the code what I understand is, There is a ViewPager implemented in ShoppingListActivity along with tabs.
In viewpager each fragment contains the list of something which come from server right? Now you want to refresh whole viewpager when user back from the ShoppingListInfoActivity right?
Do below changes in you ShoppinglistActivity.
1) Declare ViewPagerAdapter adapter; at class level global.
2)change private class ViewPagerAdapter extends FragmentPagerAdapter
replace FragmentPagerAdapter to FragmentStatePagerAdapter
3) change in onresume()
#Override
protected void onResume() {
super.onResume();
if(adapter!=null){
adapter.notifyDataSetChanged();
}
}
I am using Tab layout with view pager and adding fragments dynamically. Now I need to update a TextView which present in ViewPagers fragment, according to swipe of fragment or click of tab. Suppose if I click on first tab or swipe my fragments then TextView in OperatorPlanList fragment is updtate with text like "I just click".
Note - TextView is present in layout of fragment.
When I try to find position by using position in get view method, FragmentStatePageAdapter, then I found out it update position twice when first or last fragment is seen.
So how can I update my fragment dynamically according to current fragment seen on screen in ViewPager???
This is my FragmentStatePagerAdapter adapter.
class ViewPagerFinder extends FragmentStatePagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerFinder(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position){
return mFragmentList.get(position);
}
#Override
public int getCount() {
System.out.println("getcount>>>" + mFragmentList.size());
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
return super.instantiateItem(container, position);
}
#Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
This is how I am setting up ViewPager.
private void setupViewPager(ViewPager viewPager) {
adapter = new ViewPagerFinder(getSupportFragmentManager());
for(int i = 0; i<numberOfPlans;i++){
adapter.addFragment(new OperatorPlanList(),"Plan");
//This is how I am setting up my fragments.
viewPager.setAdapter(adapter);
}
}
This is how I am setting up my Tabs.
private void setupTabIcons() {
System.out.println("number of plans ="+numberOfPlans);
for(int i = 0; i<numberOfPlans;i++){
HashMap<String,String> map = applist.get(i);
String planName = map.get("plan_name");
TextView tabOne = (TextView) LayoutInflater.from(this).inflate(R.layout.custom_tab, null);
tabOne.setText(planName);
tabLayout.getTabAt(i).setCustomView(tabOne);
}
}
This is how I am calling my methods.
viewPager = (ViewPager)findViewById(R.id.viewpager);
setupViewPager(viewPager);
tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
setupTabIcons();
Create an interface that all of the tab fragments will implement
public interface TabFragment {
void onTabSwiped(int position);
}
In the class that hosts the ViewPager have it implement ViewPager.OnPageChangeListener
Inside your ViewPagerFinder, during the instantiateItem() keep a list of TabFragment's (Create the fragment and cast it to the new interface, THEN call super).
Now in your Class that implements OnPageChangeListener, call the method onTabSwiped on all of your TabFragments passing in the position inside the overridden method onPageSelected(int position).
Now you will get a callback to each fragment during swiping, so you can check if its the correct position and perform whatever you need to do if it is the correct page.
There are ways to make this more efficient, but it's just a quick way to get it working. It will all be similar
-- You could also just get the fragment from your list inside your adapter during onPageSelected(int position), then call the interface method.
#Override
public void onPageSelected(int position){
pagerAdapter.mFragmentList.get(position).onTabSwiped();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_dictionary);
getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
viewPager = (ViewPager) findViewById(R.id.viewpager);
setupViewPager(viewPager);
tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
setupNavMenu();
}
private void setupViewPager(ViewPager viewPager) {
adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new A(), "A");
adapter.addFragment(new B(), "B");
adapter.addFragment(new C(), "C");
adapter.addFragment(new D(), "D");
viewPager.setAdapter(adapter);
}
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);
}
}
The problem is:
When I starts the activity, i get the first fragment's view(A), BUT the next fragment(B) loads without the view, so when I slide to the next view(B), i get the view that i'v been loaded at the previous fragment, so now It's load fragment C...
the problem is that fragment B's content depends on the input in fragment A (data saved is sharedpreferences) so I allways get the default value at fragment B because it was loaded in fragment A.
The bug works the same way when I'm in the fragment D, so when I'll slide left to fragment C, it will show fragment C AND loads fragment B also.
its not a bug its the default functionality of a viewpager. for each nth page (n-1)th and (n+1)th page loads automatically with the nth page. I don't think there is any straight forward way to achieve what you want.
The best way would be to use a custom onSwipeListener instead of ViewPager and load the fragment yourself..
But for ViewPager you can use a hack:
After saving data in fragment A,
viewPager.setAdapter(adapter);
which will reload all fragments.
Don't forget to first save the current pager position.
after reset, set pager position so you don't go back to the first position every time.
not good coding but it should work.
on your ViewPagerAdapter. override method : getItemPosition : return POSITION_NONE
I am using PagerSlidingTabStrip to show 3 tabs, with each containing list view in it.
I have a scenario where i need to add new tab at runtime, say on swipe to refresh i need to add new tab to the left end.
Below is my code to add new tab :
pagerAdapter.TABS_COUNT = 4; //global value to change the tabs count
pagerAdapter.notifyDataSetChanged();
pagerSlidingTabStrip.setViewPager(mPager);
but some times one of the tabs content becomes empty listview is not scrollable.
What is the best way that i can achieve this ?
Here is an example on how to do it, don't say it's the best way, but I wrote it in hurry https://github.com/jacktech24/pager-sliding-strip-example
First, you will need a custom adapter, here I used a simple one which is displaying only text on each fragment, but it would be easy to modify it to support normal fragments etc. mTabs in the example is:
mTabs = (PagerSlidingTabStrip) findViewById(R.id.tabs);
then the example
private class TestAdapter extends FragmentPagerAdapter {
private ArrayList<String> tabs = new ArrayList<>();
public TestAdapter(FragmentManager supportFragmentManager) {
super(supportFragmentManager);
}
#Override
public Fragment getItem(int position) {
Fragment frag = new ExampleFragment();
Bundle bundle = new Bundle();
bundle.putString("title", (String) getPageTitle(position));
frag.setArguments(bundle);
return frag;
}
#Override
public CharSequence getPageTitle(int position) {
return tabs.get(position);
}
#Override
public int getCount() {
return tabs.size();
}
public void addTab(String tab) {
tabs.add(tab);
notifyDataSetChanged();
mTabs.notifyDataSetChanged();
}
public void removeTab(int position) {
tabs.remove(position);
notifyDataSetChanged();
mTabs.notifyDataSetChanged();
}
}
then, it is just as simple as this:
//mAdapter is instance of your adapter
mAdapter.addTab("test 1");
mAdapter.addTab("test 2");
mAdapter.addTab("test 3");
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mAdapter.addTab("test "+(mAdapter.getCount()+1));
}
});