Viewpager Tabs Fragment - android

I have a viewpager in a fragment that works correctly on start up but if reload the fragment by replace() or replace with another fragment then load it again. The viewpager doesn't work correctly. I have 4 tabs in my pager and depending on which tabs was currently selected the other tabs will appear blank. For example if have the first tab selected the first tab will appear blank and the other 3 will work when i reload the viewpager fragment. Or if the third tab was selected the first and fourth tabs appear blank and the second and third tabs work correctly. Not sure if this is related but if don't call removeAllTabs() on destory the tabs appear twice in the actionbar
edit:
I know have it so that if I click on the working tabs and wait a bit the views in the viewpager that where blank show up. Could this behavior be a result of the viewpager being nested in a fragment?
public class ActionBarTabsPager extends SherlockFragment{
ViewPager mViewPager;
TabsAdapter mTabsAdapter;
#Override
protected void initView(Bundle savedInstanceState) {
final ActionBar bar = getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter.addTab(bar.newTab().setText("Simple"),
CountingFragment.class, null);
mTabsAdapter.addTab(bar.newTab().setText("List"),
FragmentPagerSupport.ArrayListFragment.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Cursor"),
CursorFragment.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Another"),
AnotherFragment.class, null);
if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.activity_main, container,
false);
mViewPager = (ViewPager) rootView.findViewById(R.id.view_holder);
initView(savedInstanceState);
return rootView;
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
}
/**
* This is a helper class that implements the management of tabs and all
* details of connecting a ViewPager with associated TabHost. It relies on a
* trick. Normally a tab host has a simple API for supplying a View or
* Intent that each tab will show. This is not sufficient for switching
* between pages. So instead we make the content part of the tab host
* 0dp high (it is not shown) and the TabsAdapter supplies its own dummy
* view to show as the tab content. It listens to changes in tabs, and takes
* care of switch to the correct paged in the ViewPager whenever the selected
* tab changes.
*/
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(Activity activity, ViewPager pager) {
super(activity.getFragmentManager());
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 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) {
}
#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) {
}
}
#Override
public void onDestroyView() {
super.onDestroyView();
mActionBar.removeAllTabs();
}
}

Found the answer: use getChildFragmentManager().
In the above code, this fixes it:
public TabsAdapter(SherlockFragment frag, ViewPager pager) {
super(frag.getChildFragmentManager());
mContext = frag.getActivity();
mActionBar = mContext.getActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}

Related

String transfer from Activity to Fragment

I saw this code in the documentation of view pager. I want to pass a string from my activity to a fragment class. I figured I can pass it using the bundle args. How would I access it in my fragment class? Also can someone explain why we extend Fragment Activity here?
public class ActionBarTabsPager extends Activity {
ViewPager mViewPager;
TabsAdapter mTabsAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mViewPager = new ViewPager(this);
mViewPager.setId(R.id.pager);
setContentView(mViewPager);
final ActionBar bar = getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter.addTab(bar.newTab().setText("Simple"),
CountingFragment.class, null);
mTabsAdapter.addTab(bar.newTab().setText("List"),
FragmentPagerSupport.ArrayListFragment.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Cursor"),
CursorFragment.class, null);
if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
}
/**
* This is a helper class that implements the management of tabs and all
* details of connecting a ViewPager with associated TabHost. It relies on a
* trick. Normally a tab host has a simple API for supplying a View or
* Intent that each tab will show. This is not sufficient for switching
* between pages. So instead we make the content part of the tab host
* 0dp high (it is not shown) and the TabsAdapter supplies its own dummy
* view to show as the tab content. It listens to changes in tabs, and takes
* care of switch to the correct paged in the ViewPager whenever the selected
* tab changes.
*/
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(Activity activity, ViewPager pager) {
super(activity.getFragmentManager());
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 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) {
}
#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) {
}
}
}
We extend from FragmentActivity when we want to use Fragments for devices running on Android < 3.0. In order to use Fragments for android 2.3.3 or similar you need FragmentActivity which is in the Android support library.
Also you can access the bundle passed into the fragment in this way:-
private void LoadBundle()
{
Bundle b = getArguments();
if (b != null) {
int value=b.getInt("yourkey")
}
}
Call the LoadBundle() method anywhere in the fragment to load data passed into the fragment.
You can transfer data from Activity to Fragment like this:
FragmentA fragmentA = new FragmentA();
Bundle bundle = new Bundle();
bundle.putXXX("YourDataKey", YourDataValue);
fragmentA.setArguments(bundle);
getFragmentManager().beginTransaction().add(fragmentA);
In my opion , the reason why extends FragmentActivity is that it can then manage Fragment easily . The advatage of using Fragment is not that simple. please read the google android doc:
http://developer.android.com/guide/components/fragments.html

addToBackStack() with Fragment's instantiate

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).

How to disable recreation of the first Fragment in FragmentPagerAdapter on tab Selected?

onCreateView for my first fragment in the FragmentPagerAdapter is not very quick.
So, changing curent tab to the first has a delay.
How to disable recreate first Fragment in FragmentPagerAdapter on tab Selected?
private class TabsAdapter extends FragmentPagerAdapter implements ViewPager.OnPageChangeListener, ActionBar.TabListener {
private final Context context;
private ActionBar bar;
private final ViewPager viewPager;
private final ArrayList<TabInfo> tabs = new ArrayList<TabInfo>();
final class TabInfo {
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
TabsAdapter(SherlockFragmentActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
context = activity;
bar = activity.getSupportActionBar();
viewPager = pager;
viewPager.setAdapter(this);
viewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
tabs.add(info);
bar.addTab(tab);
notifyDataSetChanged();
}
#Override
public int getCount() {
return tabs.size();
}
#Override
public Fragment getItem(int position) {
TabInfo info = tabs.get(position);
Fragment fragment = Fragment.instantiate(context, info.clss.getName(), info.args);
return fragment;
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
#Override
public void onPageScrollStateChanged(int state) {}
#Override
public void onPageSelected(int position) {
bar.setSelectedNavigationItem(position);
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i = 0; i < tabs.size(); i++) {
if (tabs.get(i) == tag)
viewPager.setCurrentItem(i);
}
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {}
}
Right now i am stuck with the same problem.
when you are on a Tab:(n), only Tab:(n-1) and Tab:(n+1) will be alive in the memory, for memory usage optimization. Rest all Tabs will be destroyed, thats the reason why when you come back to the first Tab, its onCreateView is being called again.
Actually Tab:1's onCreateView will be called even if you click Tab:2 because its the neighbourhood Tab.
One solution i got is:
change the OffscreenPageLimit of the ViewPager. Its default value is 1
viewPager.setOffscreenPageLimit(total no of Tabs - 1);
This way all the Tabs will be alive even if its offScreen. But this is recommended only if you have decent no of Tabs(<=5)
If you have huge no.of Tabs, better use
FragmentStatePagerAdapter

How to set initially selected tab ActionBarSherlock

I'm trying to set my Tab2 as the initially selected tab using ActionBarShelock but I'm having trouble getting to work.
The tabs are working perfectly but I can't get it to select the 2nd tab instead of the first one when the app starts.
Here's my code:
#Override
public void onCreate(Bundle savedInstanceState) {
setTheme(R.style.AppThemeLightDarkActionBar);
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayShowTitleEnabled(true);
mViewPager = new ViewPager(this);
mViewPager.setId(R.id.pager);
setContentView(mViewPager);
ActionBar bar = getSupportActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter.addTab(bar.newTab().setText("Tab1"), Tab1.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Tab2"),
Tab2.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Tab3"), Tab3.class,
null);
mTabsAdapter.addTab(bar.newTab().setText("Tab4"), Tab4.class, null);
}
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) {
}
}
How can I make it work?
Thanks.
Use this at the end of your onCreate method:
mViewPager.setCurrentItem(1);
The above method should be 0-based, so 1 is the second page.

How to design a custom Tabs while using ActionBarSherlock

I've been trying to style ActionBarSherlock so as to give my app the look I desire, but while I've succeeded with most, I've struggled with Tabs (which can be swiped with Fragments). I've so far failed to give it a custom background and text color, while also removing the border in between tabs.
What I currently have is
Whereas what I desire to make it look like is
Here's the code I'm using in the activity, the majority of which I've borrowed from another question on SO (I'll link it as soon as I find it again):
public class HomeActivity extends SherlockFragmentActivity {
ViewPager mViewPager;
TabsAdapter mTabsAdapter;
TextView tabCenter;
TextView tabText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mViewPager = new ViewPager(this);
mViewPager.setId(R.id.pager);
setContentView(mViewPager);
ActionBar bar = getSupportActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter.addTab(bar.newTab().setText("Tab 1"),
MyFragment.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Tab 2"),
MyFragment.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Tab 3"),
MyFragment.class, null);
}
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);
}
#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 onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
}
}
Avoid the inheritence of FragmentPagerAdapter to do what you want. You should use the viewPager with the viewPagerIndicator library: ViewPagerIndicator
Have a look, it's very easy to use and develop by SJ (Super Jake)

Categories

Resources