I want to handle one fragment within tabsadapter which is a static class in my Activity. The problem is how can i get the getfragmentbytag in the onTabSelected?
From the onCreate i have this code:
Tab tab1 = actionBar.newTab().setText("ABOUT");
tabsAdapter.addTab(tab1, PoiAboutFragment.class, null);
and my tabs adapter class is the following which works with no problem.
public static class TabsAdapter extends FragmentPagerAdapter implements
ActionBar.TabListener, ViewPager.OnPageChangeListener {
private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
private Object gridTag;
static final class TabInfo {
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
public TabsAdapter(SherlockFragmentActivity activity, ViewPager pager,
ActionBar actionBar) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = actionBar;
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
if(clss.equals(GridFragment.class))
gridTag = tab.getTag();
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();
}
#Override
public int getCount() {
return mTabs.size();
}
#Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(),
info.args);
}
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
}
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
}
public void onPageScrollStateChanged(int state) {
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Object tag = tab.getTag();
Log.i(TAG, "onTabSelected has been called");
if(tag.equals(gridTag))
Log.i(TAG, "gridtab has been called");
for (int i = 0; i < mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
}
the problem is that i want to handle one of my fragments in both the oncreate method and in the tabsAdapter but i don't have neither a fragment tag neither an fragment Id. How can i handle their methods from my Activity?
The FragmentPagerAdapter source's makeFragmentName methods shows that fragments are created with the following tags:
"android:switcher:" + viewId + ":" + id
Where viewId is the id of the ViewPager, i.e., use
activity.getSupportFragmentManager().findFragmentByTag(
"android:switcher:" + pager.getId() + ":0"
to get the first Fragment.
I found the answer I was looking for in this site android-er.blogasppot
Related
I'm using a FragmentPagerAdapter to create a layout with 2 fragments, where user can swipe between them:
mTabsAdapter = new TabsAdapter(this, mPager);
mTabsAdapter.addTab(bar.newTab().setText("Tab 1"), FirstFragment.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Tab 2"), SecondFragment.class, null);
Right after that, i want to get the added fragment to call its methods:
FirstFragment firstFragment = (FirstFragment) mTabsAdapter.findFragmentByPosition(pos);
The problem is at this time the tabs aren't ready yet, and findFragmentByPosition returns null. If I do this inside a Handler().postDelayed(new Runnable(){..., it does the trick when testing, but I still get this error from some users.
Is there a way to know if fragments are ready?
Below is the TabsAdapter class:
public static class TabsAdapter extends FragmentPagerAdapter implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final SherlockFragmentActivity mActivity;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i=0; i<mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
}
public void selectTabByPosition(int position){
mViewPager.setCurrentItem(position);
}
public Fragment findFragmentByPosition(int position) {
FragmentPagerAdapter fragmentPagerAdapter = this;
return mActivity.getSupportFragmentManager().findFragmentByTag(
"android:switcher:" + mViewPager.getId() + ":"
+ fragmentPagerAdapter.getItemId(position));
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
//
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
//
}
static final class TabInfo {
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
public TabsAdapter(SherlockFragmentActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActivity = activity;
mActionBar = activity.getSupportActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();
}
#Override
public int getCount() {
return mTabs.size();
}
#Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrollStateChanged(int state) {
}
}
MainActivity.java
// Fragments and ViewPager Initialization
List<Fragment> fragments = getFragments();
pageAdapter = new MyPageAdapter(getSupportFragmentManager(), fragments);
mViewPager.setAdapter(pageAdapter);
mViewPager.setOnPageChangeListener(MainActivity.this);
MyPageAdapter.java
public class MyPageAdapter extends FragmentPagerAdapter
{
private List<Fragment> fragments;
public MyPageAdapter(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();
}}
I have a view pager with 2 tabs, the thing is, as soon as I open the Activity, both the tabs(i.e fragments) start(try to load data). Is there a way I can start the fragment only when the tab is selected.
PagerAdapter adapter = new PagerAdapter((MFragmentActivity ) this,
mViewPager);
adapter.addTab(actionBar.newTab().setText("TAB-1"),
TabOneFragment.class, null);
adapter.addTab(actionBar.newTab().setText("TAB-2"),
TabTwoFragment.class, null);
public static class PagerAdapter extends FragmentPagerAdapter implements
ActionBar.TabListener, ViewPager.OnPageChangeListener {
private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo {
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
public PagerAdapter(MFragmentActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getSupportActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();
}
public int getCount() {
return mTabs.size();
}
public SherlockFragment getItem(int position) {
TabInfo info = mTabs.get(position);
return (SherlockFragment) Fragment.instantiate(mContext,
info.clss.getName(), info.args);
}
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
}
public void onPageScrollStateChanged(int state) {
}
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
mViewPager.setCurrentItem(tab.getPosition());
Object tag = tab.getTag();
for (int i = 0; i < mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
}
I have implemented a Sherlock ActionBar with navigation tabs using a tabs adapter. Below is my tab adapter class:
public static class TabsAdapter extends FragmentPagerAdapter implements
ActionBar.TabListener, ViewPager.OnPageChangeListener
{
private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo
{
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args)
{
clss = _class;
args = _args;
}
}
public TabsAdapter(SherlockFragmentActivity activity, ViewPager pager)
{
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getSupportActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args)
{
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();
}
#Override
public int getCount()
{
return mTabs.size();
}
#Override
public Fragment getItem(int position)
{
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext,info.clss.getName(),
info.args);
}
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels)
{
}
public void onPageSelected(int position)
{
mActionBar.setSelectedNavigationItem(position);
}
public void onPageScrollStateChanged(int state)
{
}
public void onTabSelected(Tab tab, FragmentTransaction ft)
{
Object tag = tab.getTag();
for (int i = 0; i < mTabs.size(); i++)
{
if (mTabs.get(i) == tag)
{
mViewPager.setCurrentItem(i);
}
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft)
{
}
public void onTabReselected(Tab tab, FragmentTransaction ft)
{
}
}
My problem is how to use addToBackStack() with Fragment.instantiate()(or if there is any other way for handling back button)?
My problem is how to use addtobackstack with Fragment.instantiate or
any other way for handling back button
You really shouldn't do this. If you're going to use tabs with fragments in a ViewPager it's safe to assume the user could switch/swipe a lot the tab fragments as he uses the app. Having the BACK button recreating his steps when he wants out of the activity could be very frustrating(imagine trying to get out of this activity after switching tabs for 15-20 times).
If you really want to do that then store the user's navigation path in a list/array of integers(when swiping/switching the tabs store the int position of the ViewPager's page where the user has gone). Then override the onBackPressed method of the activity and have it pop(every time the BACK button is clicked) the last position from the previous list/array moving the ViewPager to that position(along with highlighting the proper tab).
I have a working state pager project using actionbarsherlock but I'm having trouble with getting the current fragment that was displayed. Is it possible to get the position of the current fragment?
Yes it is possible. If you are using a ViewPager you can do that :
_viewPager.getCurrentItem();
or that
_pageListener = new PageListener();
_viewPager.setOnPageChangeListener(_pageListener);
and keep trace of current page with something like that :
private int _currentPage;
private static class PageListener extends SimpleOnPageChangeListener{
public void onPageSelected(int position) {
Log.i(TAG, "page selected " + position);
_currentPage = position;
}
}
Or else you can easily do that with a TabAdapter like this :
public static class TabsAdapter extends FragmentPagerAdapter implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo {
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
public TabsAdapter(SherlockFragmentActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getSupportActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();
}
#Override
public int getCount() {
return mTabs.size();
}
#Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
((SherlockFragmentActivity) mContext).supportInvalidateOptionsMenu();
}
public void onPageScrollStateChanged(int state) {
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i = 0; i < mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
}
You only need to keep the current page with one/or two of the methods. For example in onTabSelected
hope it helps you
good luck
I have following problem:
I have one activity in which I have two tabs which are made both as fragments using FragmentPagerAdapter
In some moment I would like to change View of one of these fragments, but I am not able to findFragmentById() or findFragmentByTag() I am unable to set id, because I am not declaring Fragment in XML, because of the FragmentPagerAdapter
And when I am trying to set tag I am getting following problem:
08-15 21:46:23.805: E/AndroidRuntime(9297): java.lang.IllegalStateException: Can't change tag of fragment Companies{416d7b78 id=0x7f04002e companies}: was companies now android:switcher:2130968622:1
My code of the pager FragmentPagerAdapter:
public class TabsAdapter extends FragmentPagerAdapter implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
private final FragmentActivity mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
final class TabInfo {
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
public TabsAdapter(SherlockFragmentActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getSupportActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();
}
#Override
public int getCount() {
return mTabs.size();
}
#Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
FragmentTransaction ft=mContext.getSupportFragmentManager().beginTransaction();
Fragment fragment=Fragment.instantiate(mContext, info.clss.getName(), info.args);
if(position==1){
ft.add(mViewPager.getId(), fragment, "companies");
}else{
ft.add(mViewPager.getId(), fragment);
}
Log.v("FRAGMENT ID", "fragment tag: "+fragment.getTag());
ft.commit();
Log.v("FRAGMENT ID", "fragment tag: "+fragment.getTag());
return fragment;
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
new Thread(new Runnable() {
#Override
public void run() {
MainActivity.this.hideKeyboard();
}
}).start();
}
#Override
public void onPageScrollStateChanged(int state) {
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i = 0; i < mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
}
Thank you in advance for your answers.
The Fragments supplied by the FragmentPagerAdapter are auto-tagged when they're instantiated. You can retrieve the tag with this method:
private static String makeFragmentName(int viewPagerId, int index) {
return "android:switcher:" + viewPagerId + ":" + index;
}
Reference: reusing fragments in a fragmentpageradapter
With this function you can find the fragment by pager adapter position.
public Fragment findFragmentByPosition(int position) {
FragmentPagerAdapter fragmentPagerAdapter = getFragmentPagerAdapter();
return getSupportFragmentManager().findFragmentByTag(
"android:switcher:" + getViewPager().getId() + ":"
+ fragmentPagerAdapter.getItemId(position));
}
Sample code for v4 support api.
I found a slightly less gross way to get a handle on a Fragment created by a FragmentPagerAdapter.
Instead of imitating the way tags are created, override instantiateItem(), get the Fragment returned by the superclass, and save the tag in TabInfo. This works for me on API >= 15, may work with lower. This still makes some assumptions about private code.
static final class TabInfo {
private final Class<?> clss;
private final Bundle args;
private String tag; // ** add this
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
final Fragment fragment = (Fragment) super.instantiateItem(container, position);
final TabInfo info = mTabs.get(position);
info.tag = fragment.getTag(); // set it here
return fragment;
}
Or in API < 16, I think instantiateItem() takes a View() instead of ViewGroup(), like this:
public Object instantiateItem(View container, int position);
Then allow a way to get the Fragment, keeping the hack contained.
public Fragment getFragment(int index) {
return mContext.getFragmentManager().findFragmentByTag(mTabs.get(index).tag);
}
For that to work, the declaration for mContext needs to change to Activity, it's passed in as an Activity anyway:
private final Activity mContext;
A simpler approach to this is to get the Tags directly from the Fragment Manager; like this:
fm.getFragments().get(0).getTag()
You can replace the position, depending on the fragment you need the tag for. Hope this helps others!.
It is very late to answer this question but i have searched a lot no one tell me the exact answer, Might be some one found it useful.
I have set my fragments through FragmentPagerAdapter and i did communication between fragments
https://developer.android.com/training/basics/fragments/communicating.html#Deliver
following this link and for FindFragmentById i simply used viewpager.getId() on the mainactivity .