Error in Fragment attach in SherlockBar - android

I using sherlock bar (http://actionbarsherlock.com/). There is code of TabListener:
public class TabListener implements ActionBar.TabListener {
private String mTag;
private Fragment mFragment;
public TabListener(String tag) {
mTag = tag;
// 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 = getSupportFragmentManager().findFragmentByTag(mTag);
if (mFragment != null && !mFragment.isDetached()) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.detach(mFragment);
ft.commit();
}
}
public void onTabSelected(Tab tab) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if (mFragment == null) {
if((tab.getPosition()==0) || (tab.getPosition()==1)) {
mFragment = new MainListFragment(ctx, ONLINE_TYPE);
} else {
mFragment = new SimpleFragmentf();
}
ft.add(com.lib.reader.R.id.root2, mFragment, mTag);
ft.addToBackStack(null);
ft.commit();
} else {
ft.attach(mFragment);
ft.commit();
}
}
public void onTabUnselected(Tab tab) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.detach(mFragment);
ft.commit();
}
#Override
public void onTabReselected(Tab tab) {
//To change body of implemented methods use File | Settings | File Templates.
}
}
There is part of View's code:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
LinearLayout v = (LinearLayout)inflater.inflate(R.layout.main, container, false);
v.addView(pager);
return v;
}
All work, but when I selected any tab in second time - I get error:
The specified child already has a parent. You must call removeView() on the child's parent first.
I think, that error in attach function, but how solve this?

You can not add a view to a viewpager like that. Check the demos of Jake Wharton for proper implementation of viewpagers for example.
https://github.com/JakeWharton/Android-ViewPagerIndicator

Related

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

Fragments not always being replaced when using back button

I'm using actionbar tabs because I need the navigation elements to be on every page. I'm using ActionBarSherlock for backwards compatibility (minimum API 8, target API 17). My MainActivity extends SherlockFragmentActivity. In my onCreate() for that, I have
ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
actionBar.setDisplayShowTitleEnabled(true);
Tab tab1 = actionBar.newTab().setText("My Pages")
.setTabListener(new MyPagesFragment());
Tab tab2 = actionBar.newTab().setText("Search")
.setTabListener(new SearchFragment());
Tab tab3 = actionBar.newTab().setText("About")
.setTabListener(new AboutFragment());
// Start with the second tab selected.
actionBar.addTab(tab1, 0, false);
actionBar.addTab(tab2, 1, true);
actionBar.addTab(tab3, 2, false);
All the tab fragments are SherlockListFragments that implement ActionBar.TabListener, and do this
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
ft.replace(android.R.id.content, this, "mypages");
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
ft.remove(this);
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// Force a complete reload.
onTabSelected(tab, ft);
}
The search page has an EditText and uses its value in an AsyncTask to fetch data from an API and add it to an SQLite database, before calling
((MainActivity) getActivity()).showDetailView(responseCode);
to show the details, which is a method in my MainActivity as follows:
protected void showDetailView(long codeID) {
SherlockFragment detailFragment = new DetailFragment();
Bundle args = new Bundle();
args.putLong("codeID", codeID);
detailFragment.setArguments(args);
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.replace(android.R.id.content, detailFragment);
ft.addToBackStack(null);
ft.commit();
}
DetailFragment is a SherlockFragment that uses getArguments() to retrieve the codeID--
Bundle args = getArguments();
if (null != args) {
codeRowID = args.getLong("codeID");
}
--and reads the matching data from the database to display it. Said data often contains links to more details, clicking which causes showDetailView to be called again with the new codeID.
MyPages is a list of all the cached details pages, and it too calls showDetailView:
#Override
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
((MainActivity) getActivity()).showDetailView(pages[position].codeId);
}
Going forward, this appears to work fine. However, when I use the back button, sometimes the fragments stick around, so they're still visible behind the restored fragment. How do I stop this happening?
I think the problem is maybe that the tabs are not being added to the backstack? But when I try to do that, they throw an exception telling me they can't be added to the backstack, so I don't understand how you are supposed to handle this. I don't understand why this thing, which it seems to be should be an incredibly basic navigation thing that lots of people want to do -- the back key has been on every android phone and table I've ever seen, physically or software! --apparently has no known solution. Have I just fundamentally misunderstood their use? Are fragments just not supposed to be used in this situation? How else do you do persistent navigation elements without repeating the same code on every page?
Logging - start app -
07-20 23:33:49.521: D/NAVIGATION_TRACE(7425): MAIN - onCreate
07-20 23:33:50.013: D/NAVIGATION_TRACE(7425): SEARCH - onTabSelected
07-20 23:33:50.021: D/NAVIGATION_TRACE(7425): SEARCH - onCreateView
07-20 23:33:50.060: D/NAVIGATION_TRACE(7425): SEARCH - onActivityCreated
07-20 23:33:50.060: D/NAVIGATION_TRACE(7425): MAIN - onResume
Search now visible. Search for an item to bring up detail view -
07-20 23:34:52.123: D/NAVIGATION_TRACE(7425): SEARCH - handleResponseCode
07-20 23:34:52.123: D/NAVIGATION_TRACE(7425): MAIN - showDetailView - 31
Detail now visible; Search gone. Click mypages tab -
07-20 23:35:37.787: D/NAVIGATION_TRACE(7425): SEARCH - onTabUnselected
07-20 23:35:37.787: D/NAVIGATION_TRACE(7425): MYPAGES - onTabSelected
07-20 23:35:37.826: D/NAVIGATION_TRACE(7425): MYPAGES - onCreateView
07-20 23:35:37.873: D/NAVIGATION_TRACE(7425): MYPAGES - onActivityCreated
MyPages now visible; Detail gone. Click back button -
07-20 23:36:12.130: D/NAVIGATION_TRACE(7425): SEARCH - onCreateView
07-20 23:36:12.201: D/NAVIGATION_TRACE(7425): SEARCH - onActivityCreated
Search and MyPages now both showing.
MainActivity:
public class MainActivity extends SherlockFragmentActivity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Log.d("NAVIGATION_TRACE", "MAIN - onCreate");
ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
actionBar.setDisplayShowTitleEnabled(true);
Tab tab1 = actionBar.newTab().setText("My Pages")
.setTabListener(new TabListener<MyPagesFragment>(
this, "mypages", MyPagesFragment.class));
Tab tab2 = actionBar.newTab().setText("Search")
.setTabListener(new TabListener<SearchFragment>(
this, "search", SearchFragment.class));
Tab tab3 = actionBar.newTab().setText("About")
.setTabListener(new TabListener<AboutFragment>(
this, "about", AboutFragment.class));
// Start with the second tab selected.
actionBar.addTab(tab1, 0, false);
actionBar.addTab(tab2, 1, true);
actionBar.addTab(tab3, 2, false);
}
#Override
public void onBackPressed()
{
FragmentManager fm = getSupportFragmentManager();
if (0 < fm.getBackStackEntryCount())
{
super.onBackPressed();
} else {
// prompt to quit
AlertDialog.Builder alertErrorResponse = new AlertDialog.Builder(this);
alertErrorResponse.setMessage("Close app?");
alertErrorResponse.setNegativeButton("Cancel", null);
alertErrorResponse.setPositiveButton("OK", new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which)
{
finish();
}
});
alertErrorResponse.show();
}
}
public void showDetailView(long codeID) {
Log.d("NAVIGATION_TRACE", "MAIN - showDetailView - "+String.valueOf(codeID));
lastShownCode = codeID;
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
SherlockFragment detailFragment = new DetailFragment();
Bundle args = new Bundle();
args.putLong("codeID", codeID);
detailFragment.setArguments(args);
ft.replace(android.R.id.content, detailFragment, "details");
ft.addToBackStack(null);
ft.commit();
}
public class TabListener<T extends SherlockListFragment> implements ActionBar.TabListener
{
private final SherlockFragmentActivity mActivity;
private final String mTag;
private final Class<T> mClass;
private SherlockListFragment mFragment;
public TabListener (SherlockFragmentActivity activity, String tag, Class<T> clz)
{
Log.d("NAVIGATION_TRACE", "TabListener - "+tag+" - "+clz.getCanonicalName());
mActivity = activity;
mTag = tag;
mClass = clz;
FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
mFragment = (SherlockListFragment) mActivity.getSupportFragmentManager().findFragmentByTag(mTag);
if (mFragment != null && !mFragment.isDetached())
{
Log.d("NAVIGATION_TRACE", "DETACH - "+mTag);
removeDetail(ft);
ft.detach(mFragment);
}
ft.commit();
}
public void clearBackStack()
{
Log.d("NAVIGATION_TRACE", "clearBackStack - "+mTag);
FragmentManager fm = mActivity.getSupportFragmentManager();
if (null != fm && 0 < fm.getBackStackEntryCount())
{
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft)
{
Log.d("NAVIGATION_TRACE", "onTabSelected - "+mTag);
clearBackStack();
ft = mActivity.getSupportFragmentManager().beginTransaction();
if (mFragment == null)
{
Log.d("NAVIGATION_TRACE", "ADD/SHOW - "+mClass.getName());
removeDetail(ft);
mFragment = (SherlockListFragment) SherlockListFragment.instantiate(mActivity, mClass.getName());
ft.add(android.R.id.content, mFragment, mTag);
ft.commit();
}
else
{
Log.d("NAVIGATION_TRACE", "ATTACH/SHOW - "+mClass.getName());
removeDetail(ft);
ft.attach(mFragment);
ft.show(mFragment);
ft.commit();
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft)
{
Log.d("NAVIGATION_TRACE", "onTabUnselected - "+mTag);
ft = mActivity.getSupportFragmentManager().beginTransaction();
if (null != mFragment)
{
Log.d("NAVIGATION_TRACE", "HIDE/DETACH - "+mTag);
removeDetail(ft);
ft.hide(mFragment);
ft.detach(mFragment);
ft.commitAllowingStateLoss();
}
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
public void removeDetail(FragmentTransaction ft) {
SherlockFragment detailFragment = (SherlockFragment) mActivity.getSupportFragmentManager().findFragmentByTag("details");
if (null != detailFragment && !detailFragment.isDetached()) {
Log.d("NAVIGATION_TRACE", "DETACH - details");
ft.detach(detailFragment);
}
}
}
}
Example fragment - MyPagesFragment :
public class MyPagesFragment extends SherlockListFragment implements
OnItemClickListener
{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
Log.d("NAVIGATION_TRACE", "MYPAGES - onCreateView");
View view = inflater.inflate(R.layout.mypages, null);
// code to set up list adapter here
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.d("NAVIGATION_TRACE", "MYPAGES - onActivityCreated");
getListView().setOnItemClickListener(this);
}
#Override
public void onItemClick(AdapterView<?> parent, View v, int position, long id)
{
Log.d("NAVIGATION_TRACE", "MYPAGES - onItemClick");
((MainActivity) getActivity()).showDetailView(pages[position].codeId);
}
}
DetailFragment
public class DetailFragment extends SherlockFragment implements
OnItemClickListener
{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.detail, null);
// bunch of display / list set up code goes here
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
lvLinks.setOnItemClickListener(this);
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
// Details page can open other details pages:
((MainActivity) getActivity()).showDetailView(pages[position].id);
}
}
Note: The changes added were made following an answer by Sheldon (who seems to have, annoyingly, deleted their answer and comments), which is why the TabListener code changed between the original section and the later posted code.
I've currently hacked a solution by emptying the backstack on every tab select, and treating back on a top tab as an exit-the-app request, which is okay, I guess, but I really would like users to be able to keep backing through the tabs if this is at all possible (because that way, eg, if I was five details pages deep and I stopped to quickly search for something which, it turned out, didn't exist, I can back to those detail pages and still go up one or more to follow different detail links.)
Try this..
FragmentManager manager = getSupportFragmentManager();
if (manager.getBackStackEntryCount() > 0)
getSupportFragmentManager().popBackStack();
else
finish();

Tab navigation in new HoloEverywhere not displays fragment after screen rotation

Yesterday I downloaded new HoloEverywhere library.
Currently, I have problem with tab navigation after screen rotation.
My Home Activity:
public class MainActivity extends Activity implements TabListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setUpTabs();
}
private void setUpTabs() {
String[] titles = {
"First", "Second",
};
ActionBar supportActionBar = getSupportActionBar();
for (int i = 0; i < titles.length; i++) {
ActionBar.Tab tab = supportActionBar.newTab();
tab.setText(titles[i]);
tab.setTag(MyFragment.TAG);
tab.setTabListener(this);
supportActionBar.addTab(tab, false);
}
supportActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
supportActionBar.setSelectedNavigationItem(0);
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction fragmentTransaction) {
final String fragmentTag = tab.getTag().toString();
Fragment fragment = getSupportFragmentManager().findFragmentByTag(fragmentTag);
if (fragment == null) {
fragment = new MyFragment();
fragmentTransaction.add(android.R.id.content, fragment, fragmentTag);
} else {
fragmentTransaction.attach(fragment);
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction fragmentTransaction) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag((String) tab.getTag());
if (fragment != null) {
fragmentTransaction.detach(fragment);
}
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction fragmentTransaction) {
}
}
And my Fragment class.
public class MyFragment extends Fragment {
public static final String TAG = MyFragment.class.getCanonicalName();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = new View(getActivity());
view.setBackgroundColor(Color.BLACK);
return view;
}
}
When I rotate the screen fragment not displaying. It displays when i select tab (which is not currently selected) manually.
I just solve the problem.
I post my code here and see if those can help you :D
if (savedInstanceState == null){
TabHomeFragment homeFragment = new TabHomeFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.container, homeFragment, "home_fragment").commit();
}else{
TabHomeFragment homeFragment = (TabHomeFragment) getSupportFragmentManager().findFragmentByTag("home_fragment");
}
Those code are located in OnCreate method.
When the Device rotate and Ortiention change, the fragment will recreate again. So add a if clase to check if there is already one here.
But I am using normal Fragment in Android. Hope it can help you a little.

Custom Back Stack for each Fragment in TabHost in Android

Since the TabActivity is deprecated I tried to replace it with Fragments which has been already mentioned in developer android website. But as you guys already know there was an issue about replacing tabs with fragments, since there will be only one activity ,which is Fragment Activity, there is no back stack for each of the fragments and as you can see in the other SO questions most of the developers were saying that you need to manage your own custom back stack as a solution.
I have created and implemented my own custom back stack as you can see below, it works perfect I can track each fragment in each tab.
Tab1
Fragment1 > Fragment2 > Fragment3
Tab2
Fragment5 > Fragment6
According to navigation above, if I navigate from Fragment1 through Fragment 3 and After that If I change the tab to Tab2 to and come back to Tab1, I can still see the Fragment3 and I can even navigate back to Fragment1 with my custom back stack.
But the issue is, When I come back to Tab1 and see the Fragment3, the Fragment3 is re-created and I can not see the changes as I left behind before I change the tab to Tab2.
Here is my Custom back stack;
public static HashMap<String, Stack<Fragment>> customBackStack;
public static Stack<Fragment> simpleStack;
public static Stack<Fragment> contactStack;
public static Stack<Fragment> customStack;
public static Stack<Fragment> throttleStack;
public static Stack<Fragment> homeStack;
customBackStack = new HashMap<String, Stack<Fragment>>();
homeStack = new Stack<Fragment>();
simpleStack = new Stack<Fragment>();
contactStack = new Stack<Fragment>();
customStack = new Stack<Fragment>();
throttleStack = new Stack<Fragment>();
customBackStack.put("home", homeStack);
customBackStack.put("simple", simpleStack);
customBackStack.put("contacts", contactStack);
customBackStack.put("custom", customStack);
customBackStack.put("throttle", throttleStack);
And here is onTabChanged method;
public void onTabChanged(String tabId) {
TabInfo newTab = mTabs.get(tabId);
if (mLastTab != newTab) {
FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
if (mLastTab != null) {
if (mLastTab.fragment != null) {
ft.detach(mLastTab.fragment);
}
}
if (newTab != null) {
if (newTab.fragment == null) {
if (!customBackStack.get(tabId).isEmpty()) {
Fragment fragment = customBackStack.get(tabId).pop();
customBackStack.get(tabId).push(fragment);
ft.replace(mContainerId, fragment);
}
} else {
if (!customBackStack.get(tabId).isEmpty()) {
Fragment fragment = customBackStack.get(tabId).pop();
customBackStack.get(tabId).push(fragment);
ft.replace(mContainerId, fragment);
}
}
}
mLastTab = newTab;
ft.commit();
mActivity.getSupportFragmentManager().executePendingTransactions();
}
}
And here is onBackPressed;
public void onBackPressed() {
Stack<Fragment> stack = customBackStack.get(mTabHost.getCurrentTabTag());
if (stack.isEmpty()) {
super.onBackPressed();
} else {
Fragment fragment = stack.pop();
if (fragment.isVisible()) {
if (stack.isEmpty()) {
super.onBackPressed();
} else {
Fragment frg = stack.pop();
customBackStack.get(mTabHost.getCurrentTabTag()).push(frg);
transaction = getSupportFragmentManager().beginTransaction();
transaction.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right,
R.anim.slide_in_right, R.anim.slide_out_left);
transaction.replace(R.id.realtabcontent, frg).commit();
}
} else {
getSupportFragmentManager().beginTransaction().replace(R.id.realtabcontent, fragment).commit();
}
}
}
As a result, custom back stack works fine except the last fragment before changing the tab is getting re-created after coming back to the tab, its not resuming as like in tab activity.
Any idea how to solve it ?
EDIT
You can find my sample Application here as a solution regarding to this issue.
GitHub
I modified googles sample tablistener to following:
public static class TabListener<T extends SherlockFragment> implements ActionBar.TabListener {
private final SherlockFragmentActivity mActivity;
private final String mTag;
private final Class<T> mClass;
private final Bundle mArgs;
public SherlockFragment mFragment;
private final Stack<SherlockFragment> mStack;
public TabListener(SherlockFragmentActivity activity, String tag, Class<T> clz) {
this(activity, tag, clz, null, null);
}
public TabListener(SherlockFragmentActivity activity, String tag, Class<T> clz, Bundle args, Stack<SherlockFragment> stack) {
mActivity = activity;
mTag = tag;
mClass = clz;
mArgs = args;
mStack = stack;
// 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 = (SherlockFragment) mActivity.getSupportFragmentManager().findFragmentByTag(mTag);
if (mFragment != null && !mFragment.isDetached()) {
FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
ft.detach(mFragment);
ft.commit();
}
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// we need to reattach ALL fragments thats in the custom stack, if we don't we'll have problems with setCustomAnimation for fragments.
if (mFragment == null) {
mFragment = (SherlockFragment) SherlockFragment.instantiate(mActivity, mClass.getName(), mArgs);
ft.replace(android.R.id.content, mFragment, mTag);
} else {
ft.attach(mFragment);
}
if(mStack != null) {
for(SherlockFragment fragment: mStack) {
ft.attach(fragment);
}
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (mFragment != null) {
ft.detach(mFragment);
}
if(mStack != null) {
for(SherlockFragment fragment: mStack) {
if(fragment!= null && !fragment.isDetached()) {
ft.detach(fragment);
}
}
}
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
}
And the activity onKeyDown methode I override to following:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
int index = getSupportActionBar().getSelectedNavigationIndex();
Stack<SherlockFragment> stack = null;
SherlockFragment fragment = null;
String rootTag = null;
switch(index) {
case 0:
stack = mWatersTabListener.mStack;
fragment = mWatersTabListener.mFragment;
rootTag = mWatersTabListener.mTag;
break;
case 1:
stack = mHarborTabListener.mStack;
fragment = mHarborTabListener.mFragment;
rootTag = mHarborTabListener.mTag;
break;
}
if(stack.isEmpty()) {
return super.onKeyDown(keyCode, event);
} else {
SherlockFragment topFragment = stack.pop();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.setCustomAnimations(R.anim.fragment_slide_right_enter,
R.anim.fragment_slide_right_exit);
if(topFragment != null && !topFragment.isDetached()) {
ft.detach(topFragment);
}
if(stack.isEmpty()) {
ft.replace(android.R.id.content, fragment, rootTag);
ft.commit();
return true;
} else {
SherlockFragment nextFragment = stack.peek();
ft.replace(android.R.id.content, nextFragment);
ft.commit();
return true;
}
}
}
return super.onKeyDown(keyCode, event);
}
The important things to take note of is that you have to attach all fragments in your custom stack when selected and you have to detach all as well when unselected. If there is problem with understanding the code snippets just ask.

Changing an activities content view based on actionbar tabs

I am wondering if this can be done. Basically I have a layout with 2 fragments in it that I use for most of my tabs but on 2 of the tabs I want to add a couple more fragments to display more things. Is it possible to change the content view to a different layout when changing tabs?
If that cant be done I thought about creating a layout with all the fragment parts that I would need and just changing the layouts of the fragments so the ones I dont use wont "show". I dont mean using FragmentTransaction.hide() because I want the fragments to fill the screen when others are not used. Would that be a bad idea or is there an easier way to do what I want?
here is my code for the activity and tabs
public class Tabs extends Activity{
long deleteID;
#Override
public void onCreate(Bundle create){
super.onCreate(create);
setContentView(R.layout.main_layout);
createTabs();
ActionBar bar = getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
bar.setDisplayHomeAsUpEnabled(true);
if(create != null){
bar.setSelectedNavigationItem(create.getInt("Home",0));
}
}
I also add tabs a whatnot but thats not important
this is the actionbar subclass
private class TabListener implements ActionBar.TabListener{
TabContent mFragment;
public TabListener(TabContent fragment) {
mFragment = fragment;
}
#Override
public void onTabReselected(Tab tab, android.app.FragmentTransaction ft) {
}
#Override
public void onTabSelected(Tab tab, android.app.FragmentTransaction ft) {
ListFragment newListFragment = new BowlersListFragment();
Fragment newFragment = new BowlerEntryFrag();
ft = getFragmentManager().beginTransaction();
ft.replace(R.id.frameOne, newListFragment);
ft.replace(R.id.frameTwo, newFragment);
ft.addToBackStack(null);
ft.commit();
}
#Override
public void onTabUnselected(Tab tab, android.app.FragmentTransaction ft) {
if(ft != null){
ft.remove(mFragment);
}
}
}
}
I tried doing Activity.setContentView(r.layout.newView) but that won't work
I had similar problem, so implemented it like this. I have a mainActivity that holds and creates the tabs. That activity uses a layout with one fragment container, main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:orientation="vertical" >
<LinearLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
In my activity I have the following code for creating the tabs and fragments:
historyTab = actionbar.newTab().setText("History");
historyTab.setTabListener(new MyTabsListener(new HistoryFragment()));
actionbar.addTab(historyTab);
My tabListener looks something like this:
private class MyTabsListener implements ActionBar.TabListener {
public Fragment fragment;
private boolean isFragmentAdded = false;
public MyTabsListener(Fragment fragment) {
this.fragment = fragment;
}
#Override
public void onTabSelected(Tab tab, android.app.FragmentTransaction ft) {
FragmentManager fragMgr = getSupportFragmentManager();
FragmentTransaction xaction = fragMgr.beginTransaction();
if (fragment instanceof HistoryFragment) {
fragment = new HistoryFragment();
xaction.add(R.id.fragment_container, fragment);
} else if (fragment instanceof .. some other fragment..) {
fragment = new .. some other fragment();
xaction.add(R.id.fragment_container, fragment);
}
}
xaction.commit();
}
#Override
public void onTabUnselected(Tab tab, android.app.FragmentTransaction ft) {
FragmentManager fragMgr = getSupportFragmentManager();
FragmentTransaction xaction;
xaction = fragMgr.beginTransaction();
Fragment fragment = fragMgr.findFragmentById(R.id.fragment_container);
xaction.remove(fragment);
xaction.commit();
}
}
The layout for the History fragment in my example, can be anything, even a layout that contains two fragments, or as much you need. Just be careful, and in onCreateview method in the fragment, use this:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
if (view == null) { // this line is very important!
view = inflater.inflate(R.layout.history_fragment_layout, container, false);
listView = (ListView) view.findViewById(R.id.historyList);
}
return view;
}
Hope that helps!:)

Categories

Resources