I've been trying to test how to mix all these things together and I'm having problems!!
I just want an app with three tabs using the ActionBar.Tab. For example, this tabs can be movies genres Action, Adventure and Animation, the user can swipe through the tabs, so it will use the ViewPager and each tab will show a list of movies of that genre. There's no need to have three different fragments classes because all tabs will be the same format a simple list.
And I'm having problems because when I select the second tab, the position for onPageSelected is 1,
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mCollectionPagerAdapter);
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
}
});
This causes the call to the method public Fragment getItem(int i) inside the CollectionPagerAdapter class, but then the value of i is 2 NOT 1, so then it calls the createView for the TabFragment class with a value of 2 NOT 1, so tabs are not refreshing successfully.
Any help will be really appreciated!!
Code to create the tabs,
// For each of the sections in the app, add a tab to the action bar.
for (int i = 0; i < mCollectionPagerAdapter.getCount(); i++) {
mActionBar.addTab(mActionBar.newTab()
.setText(mGenres.get(i).getName())
.setTabListener(this));
//Let's request the movies for the first three genres
new GetMoviesByGenre().execute(mGenres.get(i).getId());
}
When a tab is selected,
#Override
public void onTabSelected(ActionBar.Tab tab, android.app.FragmentTransaction arg1) {
//Let's update the dataset for the selected genre
TabFragment fragment =
(TabFragment) getSupportFragmentManager().findFragmentByTag(
"android:switcher:"+R.id.pager+":"+tab.getPosition());
if(fragment != null) // could be null if not instantiated yet
{
if(fragment.getView() != null)
{
fragment.updateDisplay(tab.getPosition()); // do what updates are required
}
}
mViewPager.setCurrentItem(tab.getPosition());
}
CollectionPageAdapter class
public class CollectionPagerAdapter extends FragmentPagerAdapter {
final int NUM_ITEMS = 3; // number of tabs
List<Fragment> fragments = new ArrayList<Fragment>();
public Fragment getItem(int pos) {
return fragments.get(pos);
}
public void addFragment(Fragment f) {
fragments.add(f);
}
public CollectionPagerAdapter(FragmentManager fm) {
super(fm);
//Let's add the fragments
for (int i=0;i<NUM_ITEMS;i++)
{
Fragment fragment = new TabFragment();
Bundle args = new Bundle();
args.putInt(TabFragment.ARG_OBJECT, 0);
fragment.setArguments(args);
addFragment (fragment);
}
}
#Override
public int getCount() {
return NUM_ITEMS;
}
}
TabFragment class
public class TabFragment extends ListFragment {
public static final String ARG_OBJECT = "object";
private MoviesAdapter m_Adapter;
private ArrayList <Movie> mMovies = new ArrayList<Movie>();
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// you only need to instantiate these the first time your fragment is
// created; then, the method above will do the rest
if (m_Adapter == null) {
m_Adapter = new MoviesAdapter(getActivity(), mMovies);
}
setListAdapter(m_Adapter);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
int position = getArguments().getInt(ARG_OBJECT); // to check is the right fragment
View rootView = inflater.inflate(R.layout.tabs, container, false);
return rootView;
}
public void updateDisplay (int type)
{
GlobalVars gv = (GlobalVars)getActivity().getApplicationContext();
switch (type)
{
case 0:
mMovies = gv.getActionMovies();
break;
case 1:
mMovies = gv.getAdventureMovies();
break;
case 2:
mMovies = gv.getAnimationMovies();
break;
}
m_Adapter.notifyDataSetChanged();
}
}
I don't what I'm doing wrong, I guess that the fragments are messed up, because when I press the second tab, data from the first tab is updated, and so on ...
Thanks!
Instead of using CollectionPageAdapter, I changed to use the TabsAdapter class shown in Android documentation of ViewPager and it works!
public 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 final List<Fragment> fragments = new ArrayList<Fragment>();
static final class TabInfo {
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
public TabsAdapter(FragmentActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getActionBar();
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 int getItemPosition(Object object) {
return POSITION_NONE;
}
#Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
Fragment fr = Fragment.instantiate(mContext, info.clss.getName(), info.args);
//addFragment (fr, position);
return fr;
}
public void addFragment(Fragment f, int location) {
if (fragments.size() == 0)
fragments.add(f);
else
fragments.add(location, f);
}
#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) {
}
#Override
public void onTabSelected(Tab tab, android.app.FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i=0; i<mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
updateDatasetMovies (i);
mViewPager.setCurrentItem(i);
}
}
}
#Override
public void onTabReselected(Tab tab, android.app.FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void onTabUnselected(Tab tab, android.app.FragmentTransaction ft) {
// TODO Auto-generated method stub
}
public void updateDatasetMovies (int pos)
{
//Let's update the dataset for the selected genre
TabFragment fragment =
(TabFragment) ((FragmentActivity)mContext).getSupportFragmentManager().findFragmentByTag(
"android:switcher:"+R.id.pager+":"+pos);
//TabFragment fragment = (TabFragment) getItem(pos);
if(fragment != null) // could be null if not instantiated yet
{
if(fragment.getView() != null)
{
// no need to call if fragment's onDestroyView()
//has since been called.
fragment.updateDisplay(pos); // do what updates are required
}
}
}
}`
I agree with nirvik on this, however there is one cruciual improvement that should be made. This implementation has one flaw - when swiping to a next fragment the onPageSelected method is invoked, which in turn invokes onTabSelected method by calling mActionBar.setSelectedNavigationItem(position);. This causes a flicker in the animation.
This:
viewPager.setCurrentItem(i);
should be replaced by this:
if(i != viewPager.getCurrentItem()) {
viewPager.setCurrentItem(i);
}
resulting in a smooth transition.
You can try including the following code in your FragmentPagerAdapter and see if this addresses the issue.
public int getItemPosition(Object object) {
return POSITION_NONE;
}
You could also try using a FragmentStatePagerAdapter.
Related
Creating app in which i want to pass bundle data from one tab fragment to another.I have created two tab and getting list in one fragment but now i want to select item from Recyclerview list using checkbox and set this selected item to another tab fragment on swipe.Using viewpager for creating tab.In second tab fragment set bundle and in first tab fragment get bundle but not working.
In second fragment i set bundle
Bundle data = new Bundle();
data.putString("name",contactArrayList.get(position).getContactName());
data.putString("mobile",contactArrayList.get(position).getContactNumber());
Fragment fragment = FragmentInfo.newInstance(1);
fragment.setArguments(data);
In first fragment i get bundle
if (bundle != null) {
String name = bundle.getString("name");
String mobile = bundle.getString("mobile");
// object of Model Class
mydata.setName(name);
mydata.setMobile(mobile);
myDataArrayList.add(mydata);
}
try this:
create a mechanism to access the tag across fragments via the main activity, . - Call getTag() in onCreateView() of FragmentB. Then pass it to the main activity. When FragmentA need to pass something to FragmentB, it retrieve it from MainActivity.
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(FragmentActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getActionBar();
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 void onPageScrollStateChanged(int state) {
// TODO Auto-generated method stub
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// TODO Auto-generated method stub
}
#Override
public void onPageSelected(int position) {
// TODO Auto-generated method stub
mActionBar.setSelectedNavigationItem(position);
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#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) {
// TODO Auto-generated method stub
}
#Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
#Override
public int getCount() {
return mTabs.size();
}
}
For full implementation see this link:
http://android-er.blogspot.com/2012/06/communication-between-fragments-in.html
I have the following...
Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Adapter code...
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter implements ActionBar.TabListener {
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
private Fragment f;
public ScreenSlidePagerAdapter(FragmentManager fm) {
super(fm);
this.addTab(actionBar.newTab().setText("Score"), ScoreFragment.class, null);
f = new TeamFragment();
this.addTab(actionBar.newTab().setText("Team"), TeamFragment.class, null);
}
#Override
public Fragment getItem(int position) {
if(position == 0){
TabInfo info = mTabs.get(position);
return Fragment.instantiate(context, info.clss.getName(), info.args);
}
else{
return f;
}
}
#Override
public int getCount() {
return mTabs.size();
}
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);
actionBar.addTab(tab);
notifyDataSetChanged();
}
#Override
public void onTabReselected(Tab arg0,
android.app.FragmentTransaction arg1) {
// TODO Auto-generated method stub
}
#Override
public void onTabSelected(Tab tab, android.app.FragmentTransaction arg1) {
Object tag = tab.getTag();
for (int i = 0; i < mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mPager.setCurrentItem(i);
}
}
}
#Override
public void onTabUnselected(Tab arg0,
android.app.FragmentTransaction arg1) {
// TODO Auto-generated method stub
}
/**
* #return the f
*/
public Fragment getF() {
return f;
}
/**
* #param f the f to set
*/
public void setF(Fragment f) {
startUpdate((ViewGroup)findViewById(R.id.pager));
destroyItem((ViewGroup)findViewById(R.id.pager), 1, this.f);
this.f = f;
instantiateItem((ViewGroup)findViewById(R.id.pager), 1);
finishUpdate((ViewGroup)findViewById(R.id.pager));
notifyDataSetChanged();
}
}
However, when I call setF with a new fragment, the old one disappears as expected but the new one never shows up. Can someone help me with what I am doing wrong?
I tried changing to...
public void setF(Fragment f) {
ViewGroup g = (ViewGroup)findViewById(R.id.pager);
startUpdate(g);
destroyItem(g, 1, this.f);
this.f = f;
WebViewFragment v = (WebViewFragment)instantiateItem(g, 1);
FragmentManager fm = v.getFragmentManager();
finishUpdate(g);
Fragment f3 = v;
f3.setUserVisibleHint(true);
setPrimaryItem(g,1,v);
notifyDataSetChanged();
}
but now I get...
10-24 17:10:12.290: E/AndroidRuntime(1113): java.lang.NullPointerException
10-24 17:10:12.290: E/AndroidRuntime(1113): at android.support.v4.app.Fragment.setUserVisibleHint(Fragment.java:819)
10-24 17:10:12.290: E/AndroidRuntime(1113): at android.support.v4.app.FragmentStatePagerAdapter.setPrimaryItem(FragmentStatePagerAdapter.java:152)
10-24 17:10:12.290: E/AndroidRuntime(1113): at android.support.v4.view.ViewPager.populate(ViewPager.java:1066)
Looks like maybe a race condition?
ActionBar with ViewPager - clicking partially visible tab crashes the app
Update
If I remove the setPrimaryItem(g,1,v); then it appears to run fine till I go to another tab and come back. Then it fails the same way. This leads me to believe I am doing it somewhat right and just missing something.
Here is the functional version, I had to change multiple things around. I would still like to add to the BackStack (If you can do that you will get the check) but this should help anyone in the same boat.
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter implements ActionBar.TabListener {
private ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
private List<Fragment> fragments = new ArrayList<Fragment>();
public ScreenSlidePagerAdapter(FragmentManager fm) {
super(fm);
fragments.add(new ScoreFragment());
fragments.add(new TeamFragment());
this.addTab(actionBar.newTab().setText("Score"), ScoreFragment.class, null);
this.addTab(actionBar.newTab().setText("Team"), TeamFragment.class, null);
}
#Override
public Fragment getItem(int position) {
return fragments.get(position);
}
#Override
public int getCount() {
return fragments.size();
}
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);
actionBar.addTab(tab);
notifyDataSetChanged();
}
#Override
public void onTabReselected(Tab arg0,
android.app.FragmentTransaction arg1) {}
#Override
public void onTabSelected(Tab tab, android.app.FragmentTransaction arg1) {
Object tag = tab.getTag();
for (int i = 0; i < mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mPager.setCurrentItem(i);
}
}
}
#Override
public void onTabUnselected(Tab arg0,
android.app.FragmentTransaction arg1) {}
/**
* #param f the f to set
*/
public void setF(Fragment f) {
int loc = actionBar.getSelectedTab().getPosition();
fragments.set(loc, f);
notifyDataSetChanged();
}
#Override
public int getItemPosition(Object object) {
if(object instanceof Fragment){
if(fragments.contains(object))
return POSITION_UNCHANGED;
}
return POSITION_NONE;
}
}
Trying to using transition fragment to replace, add or remove fragments might doesn’t word sometimes and it just shows a blank layout. This problem happen because some reasons. I had the problem and I figured it out. It just was the way that I implemented onCreate method in my fragmentActivity.
This is is how it was:
protected void onCreate(android.os.Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mybooks);
}
And the problem was gone when I changed android.os.Bundle to just Bundle. I hope this help anybody who has same this problem.
I implemented a ActionBarSherlock with a ViewPager and a TabsAdapter. It works fine until I try to communicate between fragments.
I've 3 Tabs in my Application, and I can click on each of the tabs no problem, but when communicating through an interface, in two out of three tabs, one of my fragments in my tab is null. This happens when I select a menu item. I want selecting a menu item to be communicated to all fragments in the ViewPager. However, when I'm in tab[0], tab[2] is null but tabs[0] and tab[1] are not null. When I'm in tab[2], tab[0] is null, but tab[1] and tab[2] are not null. However, when I'm in tab[1], no fragments are null.
All the fragments are visible when I click on each of the tabs. That's not a problem.
The Code:
public class GPSTrackingActivity extends SherlockFragmentActivity implements DistanceFragment.OnCoordinatesAddedListener, ReportsFragment.ReportStartDateListener
{
long insertedID = 0;
private Menu menu;
//for shared preferences
private static final String KEY_UNITS = "units";
private static final String KEY_START_POSITION = "start";
ViewPager mViewPager;
TabsAdapter mTabsAdapter;
String TAG = "GPSTrackingActivity";
//set 0 for miles, 1 for kilometers
int mMilesOrKilometers = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
//create a new ViewPager and set to the pager we have created in Ids.xml
mViewPager = new ViewPager(this);
mViewPager.setId(R.id.pager);
setContentView(mViewPager);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setDisplayShowHomeEnabled(false);
actionBar.setNavigationMode ( ActionBar . NAVIGATION_MODE_TABS );
//if user has previous settings, get them from shared prefs.
getSharedPrefs();
mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter.addTab(actionBar.newTab().setText(" Track").setIcon(R.drawable.browser_compass_icon),
DistanceFragment.class, null);
mTabsAdapter.addTab(actionBar.newTab().setText(" Trips").setIcon(R.drawable.folder_chart_icon),
TripsFragment.class, null);
mTabsAdapter.addTab(actionBar.newTab().setText(" Report").setIcon(R.drawable.mail_compose_icon),
ReportsFragment.class, null);
}
/* set the units of measurement for all the fragments
*/
public void ChangeUnitsOfMeasure() {
try {
DistanceFragment DistanceFrag = (DistanceFragment) getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":0");
if (DistanceFrag != null && DistanceFrag.getView() != null) {
Log.d(TAG,"Class=" + DistanceFrag.getClass());
Log.d(TAG,"Found the Distance Fragment");
DistanceFrag.ClearData();
DistanceFrag.setMileOrKilometers(mMilesOrKilometers);
}
TripsFragment TripsFrag = (TripsFragment) getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":1");
if (TripsFrag != null && TripsFrag.getView() != null) {
Log.d(TAG,"Class=" + TripsFrag.getClass());
if (TripsFrag.getClass() == TripsFragment.class) {
Log.d(TAG,"Found the Trips Fragment");
TripsFrag.setMileOrKilometers(mMilesOrKilometers);
}
}
ReportsFragment ReportsFrag = (ReportsFragment) getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":2");
if (ReportsFrag != null && ReportsFrag.getView() != null) {
Log.d(TAG,"Class=" + ReportsFrag.getClass());
Log.d(TAG,"Found the Reports Fragment");
ReportsFrag.setMileOrKilometers(mMilesOrKilometers);
}
}
//in case we change the getCurrentItem() value to anything other than 1
//would expect a ClassCastException
catch (Exception e) {
Log.d(TAG,String.valueOf(e));
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
//check selected menu item
switch (item.getItemId()) {
case R.id.miles:
mMilesOrKilometers = 0;
ChangeUnitsOfMeasure();
return true;
case R.id.kilometers:
mMilesOrKilometers = 1;
ChangeUnitsOfMeasure();
return true;
//quit program
case R.id.menu_quit:
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
//called from ReportsFragment
public void getCurrentIdOfFragment() {
int mCurrentItem = mViewPager.getCurrentItem();
Log.d(TAG,"Current View Page=" + String.valueOf(mCurrentItem));
}
// create TabsAdapter to create tabs and behavior
public 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>();
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 void onPageScrollStateChanged(int state) {
// TODO Auto-generated method stub
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// TODO Auto-generated method stub
}
#Override
public void onPageSelected(int position) {
// TODO Auto-generated method stub
mActionBar.setSelectedNavigationItem(position);
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#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) {
// TODO Auto-generated method stub
}
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
//Fragment mFragment = Fragment.instantiate(mContext, info.clss.getName(), info.args);
return (Fragment) Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
#Override
public int getCount() {
return mTabs.size();
}
}
}
It's all happening when I call the ChangeUnitsOfMeasure() function due to menu items being selected. I know the fragments are null because I test for the fragments being null before calling a function in the fragments. My LogCat (see code) is reporting showing only fragments[0] and [1] or fragments[1] and [2] or fragments [0], [1] and [2] being found, depending on what tab I am in.
Really Weird behavior!
I found the answer. It has to do with the ViewPager.setOffscreenPageLimit(), which is set by default to 1. Increasing the limit to 2 allowed me to access all fragments at one time.
mViewPager.setOffscreenPageLimit(2);
I found the answer here: My fragments in viewpager tab dont refresh.
I have a parent SherlockFragmentActivity class that contains ViewPager with 4 Fragments inside.
One of them extends from SherlockListFragment and I want to scroll it to top by click on it's tab.
MainActivity class:
public class MainActivity extends SherlockFragmentActivity {
ViewPager viewPager;
TabAdapter tabAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
setTheme(Constants.THEME);
viewPager = new ViewPager(this);
viewPager.setId(R.id.pager);
viewPager.setBackgroundResource(R.color.background_color);
tabAdapter = new TabAdapter(this,viewPager);
super.onCreate(savedInstanceState);
setContentView(viewPager);
// Action bar setup
setupTabs(savedInstanceState);
}
private void setupTabs(Bundle savedInstanceState) {
final ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
for (int i = 1; i <= 4; i++) {
ActionBar.Tab tab = getSupportActionBar().newTab();
switch (i) {
case 1:
tab.setText(R.string.feed).setTabListener(tabAdapter);
tabAdapter.addTab(EventListFragment.class);
break;
case 2:
tab.setText(R.string.downloads).setTabListener(tabAdapter);
tabAdapter.addTab(LocalEventListFragment.class);
break;
case 3:
tab.setText(R.string.tags).setTabListener(tabAdapter);
tabAdapter.addTab(TagsFragment.class);
break;
case 4:
tab.setText(R.string.settings).setTabListener(tabAdapter);
tabAdapter.addTab(SettingsFragment.class);
break;
}
getSupportActionBar().addTab(tab);
}
}
TabAdapter class:
public static class TabAdapter extends FragmentPagerAdapter implements ViewPager.OnPageChangeListener, ActionBar.TabListener {
private final Context mContext;
private final ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
private final ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
private final ActionBar mActionBar;
private final ViewPager mViewPager;
public TabAdapter(SherlockFragmentActivity activity, ViewPager pager){
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getSupportActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(Class<?> clss){
classes.add(clss);
mFragments.add(Fragment.instantiate(mContext, clss.getName(),
null));
}
#Override
public Fragment getItem(int i) {
return mFragments.get(i);
}
public int getId(int index){
return mFragments.get(index).getId();
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
// fixed double call onTabReselected
if (mActionBar.getSelectedNavigationIndex() != position)
mActionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrollStateChanged(int i) {
}
#Override
public int getCount() {
return 4;
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
mViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
final int position = tab.getPosition();
final Fragment fragment = mFragments.get(position);
if (fragment != null) {
switch (position) {
case 0:
// call tab's ListFragment scroll to top item
((EventListFragment) fragment).scrollToTop();
break;
case 1:
// do something
break;
}
}
}
onTabReselected called, then user press current tab, so I try to do EventListFragment scrolling:
EventListFragment class:
public class EventListFragment extends SherlockListFragment {
#Override
public void onCreate(Bundle state) {
super.onCreate(state);
mAdapter = new EventListAdapter(getSherlockActivity());
setListAdapter(mAdapter);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setRetainInstance(true);
}
#Override
public final View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View eventListLayout = inflater.inflate(R.layout.eventlist_fragment,null);
ListView lv = (ListView) eventListLayout.findViewById(android.R.id.list);
ViewGroup parent = (ViewGroup) lv.getParent();
//Remove ListView and add PullToRefreshListView in its place
int lvIndex = parent.indexOfChild(lv);
parent.removeViewAt(lvIndex);
mPullToRefreshListView = onCreatePullToRefreshListView(inflater, savedInstanceState);
parent.addView(mPullToRefreshListView, lvIndex, lv.getLayoutParams());
return eventListLayout;
}
public void scrollToTop() {
if (getSherlockActivity() != null) { // null after screen rotation
final ListView listView = getListView();
listView.post(new Runnable(){
public void run() {
listView.smoothScrollToPosition(0);
}});
}
}
It works on application start, but after screen rotation scrollToTop - getSherlockActivity() returns null.
If remove this condition check, have an exception:
java.lang.IllegalStateException: Content view not yet created
at android.support.v4.app.ListFragment.ensureList(ListFragment.java:328)
at android.support.v4.app.ListFragment.getListView(ListFragment.java:222)
at com.project.fragment.EventListFragment.scrollToTop(EventListFragment.java:337)
at com.project.MainActivity$TabAdapter.onTabReselected(MainActivity.java:411)
at com.actionbarsherlock.internal.app.ActionBarWrapper$TabWrapper.onTabReselected(ActionBarWrapper.java:327)
I haven't totally understatinding how to ViewPager and its FragmentPagerAdapter works. So can't find a problem, that occurs.
Use this FragmentPageAdapter:
public class TestFragmentAdapter extends FragmentPagerAdapter implements IconPagerAdapter {
protected static final String[] CONTENT = new String[] { "CATEGORIAS", "PRINCIPAL", "AS MELHORES", };
protected static final int[] ICONS = new int[] {
R.drawable.perm_group_calendar,
R.drawable.perm_group_camera,
R.drawable.perm_group_device_alarms,
};
private int mCount = CONTENT.length;
public TestFragmentAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {Fragment f = null;
switch(position){
case 0:
{
f = new ArrayListFragment();//YourFragment
// set arguments here, if required
Bundle args = new Bundle();
f.setArguments(args);
break;
}
case 1:
{
f = new HomeFragment();//YourFragment
// set arguments here, if required
Bundle args = new Bundle();
f.setArguments(args);
break;
}
case 2:
{
f = new EndlessCustomView();//YourFragment
// set arguments here, if required
Bundle args = new Bundle();
f.setArguments(args);
break;
}
default:
throw new IllegalArgumentException("not this many fragments: " + position);
}
return f;
}
#Override
public int getCount() {
return mCount;
}
#Override
public CharSequence getPageTitle(int position) {
return TestFragmentAdapter.CONTENT[position % CONTENT.length];
}
#Override
public int getIconResId(int index) {
return ICONS[index % ICONS.length];
}
public void setCount(int count) {
if (count > 0 && count <= 10) {
mCount = count;
notifyDataSetChanged();
}
}
}
This Activity:
public class BaseSampleActivity extends SlidingFragmentActivity {
private static final Random RANDOM = new Random();
TestFragmentAdapter mAdapter;
ViewPager mPager;
PageIndicator mIndicator;
protected ListFragment mFrag;
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.themed_titles);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mAdapter = new TestFragmentAdapter(getSupportFragmentManager());
mPager = (ViewPager)findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
mPager.setCurrentItem(1);
mIndicator = (TitlePageIndicator)findViewById(R.id.indicator);
mIndicator.setViewPager(mPager);
}
Applied solution according to this post:
MainActivity class:
//...
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
FragmentManager manager = getSupportFragmentManager();
for (int i = 0; i < tabAdapter.getClasses().size(); i++) {
String className = tabAdapter.getClasses().get(i).getName();
if (manager.findFragmentByTag(className) != null) {
manager.putFragment(outState, className, manager.findFragmentByTag(className));
}
}
}
//...
TabAdapter class:
//...
public void addTab(Class<?> clss, FragmentManager manager, Bundle savedInstanceState) {
classes.add(clss);
String className = clss.getName();
tags.add(className);
Fragment fragment;
if (savedInstanceState != null) {
fragment = manager.getFragment(savedInstanceState, className);
if (fragment == null) {
fragment = createFragment(className);
manager.beginTransaction().add(fragment, className);
}
} else {
fragment = createFragment(className);
manager.beginTransaction().add(fragment, className);
}
mFragments.add(fragment);
}
//...
where createFragment is a simple method, that creates needed fragment by passed class name.
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