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();
}
Related
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.
I used a TabLayout for a tabbed view in my app. I added three List fragments - one for each tab.
The content of either of the fragments is supposed to be changed (and the list views have to be updated) when new record is added/removed from any of the fragments.
But after I modify some data and swiped to the next tab the list view is not updated and retained the old data.
I created an interface that is implemented in all of the ListFragments as follows:
public interface UpdatableFragment {
void updateContent();
}
public class LogFragment implements UpdatableFragment{
...
#Override
public void updateContent() {
Activity activity = getActivity();
if (isAdded() && activity != null) {
getLoaderManager().restartLoader(LOG_LIST_LOADER, null, this);
}
}
...
}
And I call the method in the MainActivity tab select listener
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
if(adapter != null){
int position = viewPager.getCurrentItem();
viewPager = (ViewPager) findViewById(R.id.viewpager);
viewPager.setCurrentItem(position);
Fragment tabbedFragment = adapter.getItem(viewPager.getCurrentItem());
if(tabbedFragment instanceof UpdatableFragment){
((UpdatableFragment) tabbedFragment).updateContent();
}
}
}
But the condition if (isAdded() && activity != null) in updateContent() method sometimes returns false because activity becomes null. On other times, it returns the MainActivity instance and the loader restarts.
Why is this inconsistent behavior happening and how can I make the ListFragments always show fresh content when their corresponding tabs are selected?
EDIT
adding the fragment pager code
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 getItem(int position) method does not return a reference to the Fragment currently in that position of your ViewPager. The getItem() method is used in the PagerAdapter when it calls instantiateItem() to create your views/fragments, so when you call getItem(int position) it's creating a brand new Fragment for you, and this is not added/attached to your Activity (causing the false/null in your if check). If you look into the code for FragmentPagerAdapter.instantiateItem() you can see where it calls getItem() and then adds the Fragment with the FragmentManager.
One way to get around this is to cache your Fragment references in your FragmentPagerAdapter (do this by caching the Fragment returned by instantiateItem() and remove the references in adapter.destroyItem()), or calling adapter.notifyDataSetChanged() to re-create your views with the updated data.
UPDATE:
You want to add something like this to your FragmentPagerAdapter:
public class Adapter extends FragmentPagerAdapter {
private SparseArray<Fragment> fragmentCache = new SparseArray<>();
#Override public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
fragmentCache.put(position, fragment);
return fragment;
}
#Override public void destroyItem(ViewGroup container, int position, Object object) {
fragmentCache.remove(position);
super.destroyItem(container, position, object);
}
// other code....
}
You can then get references to all the fragments currently in your adapter from the fragmentCache, and then you can call your updateContent method on them.
viewPager = (ViewPager) findViewById(R.id.tabanim_viewpager);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabanim_tabs);
setupViewPager(viewPager);
tabLayout.setupWithViewPager(viewPager);
public void setupViewPager(ViewPager upViewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFrag(new ViewTodayFragment(),"Daily");
adapter.addFrag(new ViewWeekFragment(),"Weekly");
adapter.addFrag(new ViewMonthFragment(),"Monthly");
adapter.addFrag(new ViewYearFragment(),"Yearly");
viewPager.setAdapter(adapter);
}
I want to refresh fragment every time when tab changing.
inside fragment this is my code
public class ViewTodayFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
RecyclerView recyclerView;
RecyclerView.LayoutManager mLayoutManager;
RecyclerView.Adapter mAdapter;
// TODO: Rename and change types of parameters
View v;
ListView listview;
private ArrayList<DailyModel> mItems;
public static String datesel="a";
public ViewTodayFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
v=inflater.inflate(R.layout.fragment_view_today, container, false);
recyclerView =(RecyclerView)v.findViewById(R.id.view_today_lv_today);
recyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(mLayoutManager);
loadData();
return v;
}
#Override
public void onResume() {
super.onResume();
loadData();
}
public void loadData(){
mItems=new ArrayList<DailyModel>();
List<Income> ll = null;
Log.d("ALLL",datesel);
if(datesel.equals("a")){
Calendar cw = Calendar.getInstance();
SimpleDateFormat format1 = new SimpleDateFormat("dd-MM-yyyy");
String currentDay=format1.format(cw.getTime());
ll=new IncomeHandler(getActivity()).getIncomeByThisDay(currentDay);
}else{
ll=new IncomeHandler(getActivity()).getIncomeByThisDay(datesel);
}
for (int i = 0; i < ll.size(); i++) {
DailyModel a=new DailyModel();
a.setCategory(ll.get(i).getWay());
a.setDescription(ll.get(i).getDes());
a.setType(ll.get(i).getType());
a.setBank("Bank");
a.setAmount(ll.get(i).getAmount());
mItems.add(a);
}
mAdapter = new DailyAdapter(mItems);
recyclerView.setAdapter(mAdapter);
}
}
So like this there are 4 tabs so i want to refresh every time it change the tab.I try to do that inside OnResume().But it also not working.
Create your pager adapter like this.
class PagerAdapter extends FragmentPagerAdapter {
private final List<String> fragmentTitleList = new ArrayList<>();
public PagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
public void addFragmentTitle(String title) {
fragmentTitleList.add(title);
}
#Override
public Fragment getItem(int position) {
if (position == 0) {
return new ViewTodayFragment();
} else if (position == 1) {
return new ViewWeekFragment();
} else if(position == 2){
return new ViewMonthFragment();
} else{
return new ViewYearFragment();
}
}
#Override
public int getCount() {
return 4;
}
#Override
public CharSequence getPageTitle(int position) {
return fragmentTitleList.get(position);
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
Now you need to add fragment like this
PagerAdapter pagerAdapter = new PagerAdapter(getSupportFragmentManager());
adapter .addFragmentTitle("Daily");
//..... add rest of the fragment title.
viewPager.setAdapter(pagerAdapter );
hope this will help you. though i didn't try this. just writing please let me know if you get any error.
I solved this type issue currently.Please reffer my Code line by line.it might be Help you.
Thanks.
ViewPager viewPager;
ViewPagerAdapter adapter;
viewPager = (ViewPager) findViewById(R.id.tabanim_viewpager);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabanim_tabs);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabanim_tabs);
setupViewPager(viewPager);
tabLayout.setupWithViewPager(viewPager);
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
adapter.getItem(position).onResume();
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
public void setupViewPager(ViewPager upViewPager) {
adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFrag(new ViewTodayFragment(),"Daily");
adapter.addFrag(new ViewWeekFragment(),"Weekly");
adapter.addFrag(new ViewMonthFragment(),"Monthly");
adapter.addFrag(new ViewYearFragment(),"Yearly");
viewPager.setAdapter(adapter);
}
Implement ViewPager.OnPageChangeListener http://developer.android.com/reference/android/support/v4/view/ViewPager.OnPageChangeListener.html
I solved a similar problem. My four tabs (a sports timer with athletes - skiers or cyclsits - starting at intervals) also needed to communicate with each other. For example once a race is started, the set up controls must be disabled.
My project was based on Google's SlidingTabsColors sample.
I created a simple, one method interface called Refreshable and each of my tabs (Fragments) implemented its refresh method.
In my SlidingTabsFragment (extends Fragment) I override instantiateItem so I can capture a reference to each tab's fragment.
// Here we can safely save a reference to the created
// Fragment, no matter where it came from (either getItem() or
// FragmentManger).
//
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
/**
* Save Fragment references in an array with the MainActivity
* so that other tabs can be refreshed (state updated) depending on
* changes to other tabs.
*/
MainActivity a = (MainActivity)getActivity();
a.addFragment((Refreshable)createdFragment);
return createdFragment;
}
My main is an observer of my data model, but yours may different.
This is the main's method to "register" the fragments.
/**
* Accepts the specified fragment and adds to the list of "Refreshable" Fragments.
* If it is already registered, it is not added a second time.
*
* #param fragment
* the Fragment (Observer) to add.
*/
public void addFragment(Refreshable fragment) {
if (fragment == null) {
throw new NullPointerException("fragment == null");
}
synchronized (this) {
if (!mRefreshables.contains(fragment))
mRefreshables.add(fragment);
}
}
In my case, this code is in the update method of my Observer. My data has changed (race started, interval countdown expired, finisher recorded) and I can refresh all tabs. I cannot call from one tab to another because of race (no pun intended) conditions.
/**
* Call refresh on every Fragment to update state.
*/
for (Refreshable refreshable : array) {
refreshable.refresh();
}
Each tab's refresh method does its own thing.
You may not need an Observer co-ordinating all tabs, but at least you'll have a reference to them and a method other than onResume (which didn't work for me either) to call and have the content refresh itself.
your answer....you must use
viewPager.setAdapter(adapter);
when your selected tab is change.
I call loadCategory method from different items of navigation drawer.
On the first call ViewPager load the correct data. But on the second call data doesn't change. ViewPager shows the old data, Please help.
Thanks in advance.
private void loadCategory(int id) {
toolbar.setTitle(categoryList[id]);
adapter = new PagerAdapter(getSupportFragmentManager());
mViewPager.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
public class PagerAdapter extends FragmentPagerAdapter{
public PagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
}
#Override
public Fragment getItem(int position) {
Bundle bundle = new Bundle();
bundle.putString("shayari",currentShayaaris[position]);
Fragment SFragment = new ShayariFragment();
SFragment.setArguments(bundle);
return SFragment;
}
#Override
public int getCount() {
return currentShayaaris.length;
}
}
If you are inside a fragment you should instantiate adapter like this
adapter = new PagerAdapter(getChildFragmentManager());
There are several ways to update
When using FragmentPagerAdapter or FragmentStatePagerAdapter,
if you want to switch out the actual fragments that are being
displayed, you need to avoid FragmentPagerAdapter and use
FragmentStatePagerAdapter.
check this link for more information.Update ViewPager
Override getItemPosition in your PagerAdapter
public int getItemPosition(Object object) {
return POSITION_NONE;
}
second way to update viewpager
You might need to removeView and addView to reload your viewpager to get new changes in your loadCategory function after updating adapter.
ViewGroup parent = (ViewGroup) mViewPager.getParent();
if (parent != null) {
parent.removeView(mViewPager);
mViewPager.getAdapter().notifyDataSetChanged();
parent.addView(mViewPager);
}
I have added a Android support library TabLayout(Parent) with 4 tabs. I have added another TabLayout(Child) inside one of the tab views of parent tablayout. Swipe inside tabs of child tablayout is not happening correctly (Mostly due to conflict in swipe b/w parent and child tab layouts). How can I disable swipe inside child tablayout?
I have used separate viewpager for both the tablayouts.
This Simple code can help you. Use this sample code in your parent fragment to add child tabs:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_index_markets, container, false);
viewPager = (ViewPager) view.findViewById(R.id.markets_viewpager);
setupViewPager(viewPager);
tabLayout = (TabLayout) view.findViewById(R.id.markets_tabs);
tabLayout.setupWithViewPager(viewPager);
return view;
}
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getChildFragmentManager()/*getActivity().getSupportFragmentManager()*/);
adapter.addFrag(new yourInnerFragment(), "tab1");
adapter.addFrag(new yourSecondInnerFragment, "tab2");
viewPager.setAdapter(adapter);
viewPager.setCurrentItem(1);
}
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 addFrag(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
Note that sometimes it is better to use getActivity().getSupportFragmentManager() instead of getChildFragmentManager().
Also check this link: https://code.google.com/p/android/issues/detail?id=180462