Action Bar Tabs - Having two fragments (one being dynamic) in one tab - android

I am trying to create a tab that displays a list on the left hand fragment and a detailed fragment on the right. When a user clicks a list item, the right hand fragment should change to the appropriate one.
I am new to android so I used a tutorial and I know I need to do something with the tablistener: public static class TabListener implements ActionBar.TabListener
{
private final Activity mActivity;
private final String mTag;
private final Class mClass;
private final Bundle mArgs;
private Fragment mFragment;
public TabListener(Activity activity, String tag, Class<T> clz) {
this(activity, tag, clz, null);
}
public TabListener(Activity activity, String tag, Class<T> clz, Bundle args) {
mActivity = activity;
mTag = tag;
mClass = clz;
mArgs = args;
// Check to see if we already have a fragment for this tab, probably
// from a previously saved state. If so, deactivate it, because our
// initial state is that a tab isn't shown.
mFragment = mActivity.getFragmentManager().findFragmentByTag(mTag);
if (mFragment != null && !mFragment.isDetached()) {
ft = mActivity.getFragmentManager().beginTransaction();
ft.detach(mFragment);
ft.commit();
}
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if (mFragment == null) {
mFragment = Fragment.instantiate(mActivity, mClass.getName(), mArgs);
ft.add(android.R.id.content, mFragment, mTag);
tabtag = mTag;
}
else {
ft.attach(mFragment);
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (mFragment != null) {
ft.detach(mFragment);
}
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
//Toast.makeText(mActivity, "Reselected!", Toast.LENGTH_SHORT).show();
}
}
Another good example of what I need would be something like the Gmail app, with a list on the left, detail on the right, and keeping the action bar (mine has tabs) on top.
I understand that this listener inflates a fragment for each tab clicked, but how do I inflate a layout that has two fragments in it?

Inflating a layout with two fragments is simple: you just specify the Class of each fragment in the layout. But you can't mix static (layout XML-defined) and dynamic Fragments. By which I mean, you can't dynamically instantiate a new Fragment in code and insert it into a View container (e.g., a LinearLayout) that was originally populated with Fragments in the XML.

Related

Going back to fragment second time using tabs shows blank fragment

I have 2 tabs in my app, using tablistner and I'm facing an issue when I'm navigating in a very specific situation to other tab and then navigating back to the first tab.
It happens after i load a fragment called "setFrom" from another fragment:
public void LoadSetFrom ()
{
final FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
SherlockFragment setFrag = new setFrom();
ft.replace(R.id.main_layout, setFrag, "setfrom");
ft.commit();
}
This "setFrom" fragment is one of my 2 tabs, after that I'm navigatin to the second tab and when I'm going back to "setFrom" the tabs navigation still appears but the fragment is totally blank.
I'm using TabListener that way:
public class TabListener<T extends SherlockFragment> implements com.actionbarsherlock.app.ActionBar.TabListener
{
private SherlockFragment mFragment;
private setFrom fromFragment;
private final SherlockFragmentActivity mActivity;
private final String mTag;
private final Class<T> mClass;
public TabListener(SherlockFragmentActivity activity, String tag, Class<T> clz) {
mActivity = activity;
mTag = tag;
mClass = clz;
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
SherlockFragment preInitializedFragment = (SherlockFragment)mActivity.getSupportFragmentManager().findFragmentByTag(mTag);
if (preInitializedFragment == null) {
mFragment = (SherlockFragment) SherlockFragment.instantiate(mActivity, mClass.getName());
ft.add(R.id.main_layout, mFragment, mTag);
}
else {
ft.attach(preInitializedFragment);
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (mFragment != null)
ft.detach(mFragment);
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
}
After checking onTabSelected, "setFrom" is not null,it attached to the right fragment and it goes to ft.attach(preInitializedFragment) which is fine.
My question is why after the attach to the right fragment the view is still blank?
I was facing the same problem
Solved it by adding setRetainInstance(true); to my Fragment's onCreate

Hiding/Showing SherlockFragments in ActionBar.TabListener Class, content is empty

I have an app built using TabBarSherlock and the Support library to add ActionBar support to pre 3.0 devices. I can't remember what tutorial I followed to create the Tabs and the Listener but I have the following code.
Firstly creating the Tabs (Inside a SherlockFragmentActivity):
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
/*--------Setup News Tab--------*/
Tab tab1 = actionBar.newTab()
.setText("News")
.setTabListener(new TabListener<TabFragment>(
this, "tab1", TabFragment.class));
Bundle newsBundle = new Bundle();
newsBundle.putInt("news_id", newsID);
tab1.setTag(newsBundle);
actionBar.addTab(tab1);
/*------------------------------*/
// This is repeated 3 more times to total 4 Tabs.
Then I have a classCalled TabListener which is used in each of these Tabs to detect when they have been selected.
public class TabListener<T extends Fragment> implements ActionBar.TabListener{
private TabFragment mFragment;
private final Activity mActivity;
private final String mTag;
private final Class<T> mClass;
public TabListener(Activity activity, String tag, Class<T> clz) {
mActivity = activity;
mTag = tag;
mClass = clz;
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// Check if the fragment is already initialised
if (mFragment == null) {
Log.v("FRAGMENT", "FRAGMENT NEEDS TO BE CREATED");
mFragment = (TabFragment) Fragment.instantiate(mActivity, mClass.getName(), (Bundle)tab.getTag());
ft.add(android.R.id.content, mFragment, mTag);
} else {
Log.v("FRAGMENT", "FRAGMENT ALREADY CREATED");
ft.show(mFragment);
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (mFragment != null) {
ft.hide(mFragment);
}
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
}
With the class TabFragment containing a ViewPager for each Tab. My issue is that when selecting a Tab other than the first one the content inside the Fragment does not show. From the logs in place when the Fragment is initialised I can tell the views are being created just not being shown, it's just a blank area showing the background.
Instead of using show() and hide(), use attach() and detach(). Using show/hide does not remove the view hierarchy from the screen, simply hides it, so there might be issues related to that.
You are not detaching fragment rather you are just hiding it. so you should detach it so that other fragment should be attached in your onTabUnSelected.
FragmentManager will automatically restore whatever fragment (and history) was currently displayed upon a configuration change. Call findFragmentByTag to see if an instance of the target fragment already exists before creating and attaching a new instance.
Example:
public void onTabSelected(Tab tab, FragmentTransaction ft) {
SherlockFragment preInitializedFragment = (SherlockFragment) mActivity.getSupportFragmentManager().findFragmentByTag(mTag);
// Check if the fragment is already initialized
if (mFragment == null && preInitializedFragment == null) {
// If not, instantiate and add it to the activity
mFragment = (SherlockFragment) SherlockFragment.instantiate(mActivity, mClass.getName());
ft.add(android.R.id.content, mFragment, mTag);
} else if (mFragment != null) {
// If it exists, simply attach it in order to show it
ft.attach(mFragment);
} else if (preInitializedFragment != null) {
ft.attach(preInitializedFragment);
mFragment = preInitializedFragment;
}
}
and you onTabUnSelected should be like this
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (mFragment != null) {
// Detach the fragment, because another one is being attached
ft.detach(mFragment);
}
}
Content is empty on tab bar then write below code
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(actionBar.NAVIGATION_MODE_STANDARD);

Replacing Fragment in tab, changes all tabs

EDIT
I edited the previous question, wich i solved. Thanks a lot for the replies.
I have a gui with 3 tabs (News, Strategy and History), in one of them (News) i load an ExpandableListView and when the user clicks in one of the items from the list, it loads another fragment containg details from the selected item. I managed to replace the fragment in that tab with another fragment, using this code:
CategoryTab categories = new CategoryTab();//Fragment 2
FragmentManager manager = activity.getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(this.getId(), categories, "News");
//transaction.replace(android.R.id.content, categories, "News");
transaction.addToBackStack(null);
transaction.commit();
When the seconds fragment loads in the News tab, all the other tabs shows that fragment. I'm using this listener to manage tab navigation
public static class TabListener<T extends Fragment> implements ActionBar.TabListener {
private final Activity mActivity;
private final String mTag;
private final Class<T> mClass;
private final Bundle mArgs;
private Fragment mFragment;
public TabListener(Activity activity, String tag, Class<T> clz) {
this(activity, tag, clz, null);
}
public TabListener(Activity activity, String tag, Class<T> clz, Bundle args) {
mActivity = activity;
mTag = tag;
mClass = clz;
mArgs = args;
// Check to see if we already have a fragment for this tab, probably
// from a previously saved state. If so, deactivate it, because our
// initial state is that a tab isn't shown.
mFragment = mActivity.getFragmentManager().findFragmentByTag(mTag);
if (mFragment != null && !mFragment.isDetached()) {
FragmentTransaction ft = mActivity.getFragmentManager().beginTransaction();
ft.detach(mFragment);
ft.commit();
}
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if (mFragment == null) {
mFragment = Fragment.instantiate(mActivity, mClass.getName(), mArgs);
ft.add(android.R.id.content, mFragment, mTag);
} else {
ft.attach(mFragment);
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (mFragment != null) {
ft.detach(mFragment);
}
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
Toast.makeText(mActivity, "Reselected!", Toast.LENGTH_SHORT).show();
}
}
My question is ¿why all the tabs shows the same fragment when the replacement is done? and ¿how can i simulate a back button with the icon provided in the action bar, to load again fragment 1 in News Tab?
Any help will be appreciated
PD: Sorry for my english
Make sure you call getActivity() in or after onActivityCreated, as before then it will return null.
The Fragment will be attached to a null activity until onActivityCreated... that is, if you call getActivity() in onCreate or onCreateView, it will return null because the Activity hasn't been created yet. So make sure you have all of your calls to getActivity() in or after onActivityCreated

Android Sherlock ActionBar Tab can't detach SupportMapFragment properly

I have an Android project with Sherlock ActionBar and Support Library.
In the onCreate of SherlockFragmentActivity I initialized ActionBar with 2 tabs:
private void configureActionBar(){
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.Tab tab = actionBar.newTab()
.setText("Events")
.setTabListener(new TabListener<SampleListFragment>(
this, "events", SampleListFragment.class));
actionBar.addTab(tab);
tab = actionBar.newTab()
.setText("Map")
.setTabListener(new TabListener<SupportMapFragment>(
this, "map", SupportMapFragment.class));
actionBar.addTab(tab);
}
The problem is when I go back to the first tab, the screen is black with grayed Map controls. If I turn off\on the device screen, the Map completely removes and everyting is fine.
TabListener implementation is from the Google Manual:
public class TabListener<T extends Fragment> implements ActionBar.TabListener {
private Fragment mFragment;
private final Activity mActivity;
private final String mTag;
private final Class<T> mClass;
/** Constructor used each time a new tab is created.
* #param activity The host Activity, used to instantiate the fragment
* #param tag The identifier tag for the fragment
* #param clz The fragment's Class, used to instantiate the fragment
*/
public TabListener(Activity activity, String tag, Class<T> clz) {
mActivity = activity;
mTag = tag;
mClass = clz;
}
/* The following are each of the ActionBar.TabListener callbacks */
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
// Check if the fragment is already initialized
if (mFragment == null) {
// If not, instantiate and add it to the activity
mFragment = Fragment.instantiate(mActivity, mClass.getName());
ft.add(android.R.id.content, mFragment, mTag);
} else {
// If it exists, simply attach it in order to show it
ft.attach(mFragment);
}
}
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
if (mFragment != null) {
// Detach the fragment, because another one is being attached
ft.detach(mFragment);
}
}
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
// User selected the already selected tab. Usually do nothing.
}
}
I came across with similar issue once when implementing the SupportMapFragment with a SlidingMenu, after searching forums I found that it was an issue with surfaceView and that it could be fixed by setting the map transparent with this method:
private void setMapTransparent(ViewGroup group) {
int childCount = group.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = group.getChildAt(i);
if (child instanceof ViewGroup) {
setMapTransparent((ViewGroup) child);
} else if (child instanceof SurfaceView) {
child.setBackgroundColor(0x00000000);
}
}
}
Just call that method on your SupportMapFragment's onCreateView.

Android Actionbar Sherlock with Tabs

I am trying to implement ActionBar Sherlock with Tabs below that as shown in the above wire-frame.
Should i use TabActivity ? - since i saw that it is deprecated. Which is the best way to achieve the same.
I implemented this functionality with a SherlockFragmentActivity as tabview container and with SherlockFragment as tabs. Here is a sketch (I omitted the usual Android activity stuff):
This is the tabview activity with two tabs:
public class TabViewActivity extends SherlockFragmentActivity {
// store the active tab here
public static String ACTIVE_TAB = "activeTab";
#Override
public void onCreate(Bundle savedInstanceState) {
..
final ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// add the first tab which is an instance of TabFragment1
Tab tab1 = actionBar.newTab()
.setText("TabTitle1")
.setTabListener(new TabListener<TabFragment1>(
this, "tab1", TabFragment1.class));
actionBar.addTab(tab1);
// add the second tab which is an instance of TabFragment2
Tab tab2 = actionBar.newTab()
.setText("TabTitle2")
.setTabListener(new TabListener<TabFragment2>(
this, "tab2", TabFragment2.class));
actionBar.addTab(tab2);
// check if there is a saved state to select active tab
if( savedInstanceState != null ){
getSupportActionBar().setSelectedNavigationItem(
savedInstanceState.getInt(ACTIVE_TAB));
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
// save active tab
outState.putInt(ACTIVE_TAB,
getSupportActionBar().getSelectedNavigationIndex());
super.onSaveInstanceState(outState);
}
}
And this is the TabFragment that holds a tab's content:
public class TabFragment extends SherlockFragment {
// your member variables here
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_va_esh, container, false);
... // do your view initialization here
return view;
}
}
And finally this is the TabListener that handles tab switches:
public class TabListener<T extends Fragment> implements ActionBar.TabListener{
private TabFragment mFragment;
private final Activity mActivity;
private final String mTag;
private final Class<T> mClass;
public TabListener(Activity activity, String tag, Class<T> clz) {
mActivity = activity;
mTag = tag;
mClass = clz;
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// Check if the fragment is already initialized
if (mFragment == null) {
// If not, instantiate and add it to the activity
mFragment = (TabFragment) Fragment.instantiate(
mActivity, mClass.getName());
mFragment.setProviderId(mTag); // id for event provider
ft.add(android.R.id.content, mFragment, mTag);
} else {
// If it exists, simply attach it in order to show it
ft.attach(mFragment);
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (mFragment != null) {
// Detach the fragment, because another one is being attached
ft.detach(mFragment);
}
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// User selected the already selected tab. Usually do nothing.
}
}
I believe TabActivity is deprecated in favor of using Fragments -- not because tab navigation is a deprecated concept. Simply use Fragments and a TabWidget.
Also, here's a similar question.
Edit:
Here's an example courtesy of Google: Android Tabs the Fragment Way

Categories

Resources