So I found this
great example of the implementation of Swipey tabs (the tabs UI like in the Android Market).
Is it possible to set an activity as its content? Is there anything like an "Activity Container" that I can set up in the XML and put an activity in it? So basically I want to have multiple activities set as content in the ViewPager. Let me know if anyone has some good solution on this problem.
From what I understand, what you are looking for are fragments, but they are only available for Android SDK 3.0 and above.
EDIT: I was under the impression that an Activity could not be placed inside a View. Apparently I was wrong. Here is an old thread about using a LocalActivityManager to place an activity inside a container view.
In case the thread disappears, the most useful post contains this code fragment:
void createInnerActivity(ViewGroup container, Class<?> activityClass)
{
if (container.getChildCount() != 0) {
container.removeViewAt(0);
}
final Intent intent = new Intent(this, activityClass);
final Window window =
getLocalActivityManager().startActivity(activityClass.toString(),
intent);
container.addView(
window.getDecorView(),
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT));
}
Related
Edited for a little clarity
So ... I must be misunderstanding how to properly use TabHosts, because my code crashes completely during setup when I try to add some TabSpecs.. I would like to have a view that has some UI interface with graphics associated with it and animations, and then a menu system that uses a tab setup. My code looks something along the lines of:
public void myView extends RelativeLayout {
// Other Views ...
private TabHost myTabHost;
private ExpandableListView listView1; // content for tab 1
private ExpandableListView listView2; // content for tab 2
public myView(Context context) {
super(context);
// some other stuff
myTabHost = new TabHost(context);
myTabHost.setId(R.id.myTabHost);
listView1 = new ExpandableListView(context);
listView1.setId(R.id.myExpandableListView1);
listView2 = new ExpandableListView(context);
listView2.setId(R.id.myExpandableListView2);
TabSpec tab1 = myTabHost.getTabSpec(res.getString(R.string.tab1));
tab1.setIndicator(res.getString(R.string.tab1), res.getDrawable(R.drawable.tab1));
tab1.setContent(R.id.myExpandableListView1); // *********
myTabHost.addTab(tab1);
// do something similar for tab2..
}
}
Here's the Activity I'm currently using..
public void myActivity extends Activity {
#Override
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
// do a little stuff..
TabHost myTabHost = (TabHost) findViewById(R.id.myTabHost); // not sure if I'm supposed to set up the tabs in my activity, or not..
// I tried it after it crashing in the view, and it still crashed in the activity..
ExpandableListView myListView1 = (ExpandableListView) findViewById(R.id.myExpandableListView1);
// set up expandable list view the way I want from data sources..
// do something similar for myListView2
}
}
From what I understand, I don't want to extend TabActivity because that assumes the whole screen is going to be one giant TabHost, right? I only want the TabHost to be a small portion of the Activity... The problem is that the system crashes where I have indicated by the *********'s.. I guess I just don't understand properly how to go about setting up the tabs? Could someone please enlighten me as to the proper way to do it, or maybe suggest why it's crashing? I guess I should also add the question .. to use a TabHost, do I HAVE to use a TabActivity? (I don't see why I would have to, but Android can be funny that way..)
BONUS
I was poking around and found this stackoverflow link regarding tabhosts without tabactivities.. They reference a LocalActivityManager. I'll have to read about that..
I'm pretty sure that you need an Activity to use the TabHost like you want to. Also, TabHost requires a very specific layout to be present for it to work, which you don't have either. I believe you need to rethink your approach.
I'm pretty sure you've seen this, but just in case.
Edit
You can extend from Activity (instead of TabActivity) and place your tab widgets wherever you want. However, you MUST call tabHostVariable.setup() before you add any TabSpecs.
You want to extend TabActivity to do this properly. Check out http://developer.android.com/resources/tutorials/views/hello-tabwidget.html for a great tutorial.
I'd like to recreate a functionality similar to a Swing GlassPane to be able to display animations while the user uses the app "below" normally. I cannot simply create a separate layout and attach it to each activity since the animation state would be lost when switching activities.
Is there a way to keep a persistent view over all the activities of an Android application ?
Thanks.
No its not. Every Activity runs in its own thread and is by design supposed to be runnable standalone.
But you could persist the animation state into the DB or into sharedPreferences and start it over at the new activity.
What you could also do is to use a Spinner or another control instead of seperate activitys. Then you could have a persistent view.
why not think in a TabActivity?
hi! i do this before with a TabActivity, never with an only activity, always with many activitys wich i started, get theirs windows and setting as my TabActivity window´s decor view... i dont tested the code below, since is an idea, but maybe more lately (when i'll be on home) i'll write an example...
So, my idea...
a TabActivity is composed by a TabWidget and a FrameLayout where the activity´s windows is allocated.
the TabWidget can be any view, so, you can put the animated view here.
the most difficult thing is the fact that, if you start an activity from the TabActivity´s child, then the new activity will be on top of the TabActivity. In order to overrides this behavior the TabActivity must know when a nested activity wants to start another activity. When this happens the TabActivity must clear his decor view (with the old window activity) and put the decor view of new one. Something like this:
on the child activity, launch a new activity when we click on a button:
... on click listener...
((MyTabActivity)getParent()).createNewActivity("NewActivity", NewActivity.class);
now, we´re saying the TabActivity that it has to start a new activity, get the new activity decor view and put that view inside the TabActivity decor view... so, the createNewActivity will perform something like this:
public void createNewActivity(String activityId, Class<?> class1) {
Intent intent = new Intent( getIntent().getAction() ).setClass(MyTabActivity.this, class1);
Window wList = getLocalActivityManager().startActivity(activityId, intent);
getWindow().setContentView(wList.getDecorView());
}
hope you understand me.
i'll write an example later
In Android, the TabHost object renders activities in a type of inline way. I'm wondering if there's any way I can do a similar type of thing, without using the tab-host. Suppose, i want to have a toolbar or sliding drawer that allows me to switch between the activities in the same way that the TabHost does this. In other words, I'd like to render an activity inline inside of another activity, sort of like an iframe for activities...
Basically you need to play with LocalActivityManager and the ActvityGroup class:
Suppose you have your DashBoard class:
public class Dashboard extends ActivityGroup implements View.OnClickListener {
super.onCreate(savedInstanceState);
//Your view with the activity launcher buttons on the bottom for instance
setContentView(R.layout.frame);
#Override
public void onClick(View v) {
Intent intent = new Intent().setClassName(context,YourActivity.class);
intent.setAction(Intent.ACTION_VIEW);
LocalActivityManager localActivityManager = getLocalActivityManager();
final Window w = localActivityManager.startActivity("uniqueID", intent);
final View wd = w != null ? w.getDecorView() : null;
//the content of your activity goes here
FrameLayout frameLayout = (FrameLayout) findViewById(R.id.tabcontent);
frameLayout.removeAllViews();
frameLayout.addView(wd);
}
}
This may not be exactly loading separate Activities, but...
Instead of Activities, you could achieve that functionality from a user's perspective by by dynamically loading layouts inside a single Activity. That way you could have a slider and update the layout(s) on screen as needed.
No and even use of activities in tabs is discouraged in favor of views. You can do other searches here or on the android google groups to read why.
If you must have separate activities you should start them the proper way with Intents and let Android manage their lifecycle or do tabs with a view per tab.
Currently I have a TabHost implemented with 3 tabs each containing a separate activity. My question is how do I switch between tabs from within one of the activities that is located inside the tab host. I've looked everywhere and have been unsuccessful in finding a real answer to this problem.
After a long time of battling with this problem I've been able to find a solution to switching tabs when using activity based tabs.
In the parent activity class where the tabhost is created I implemented a method like the one below:
public void switchTab(int tab){
tabHost.setCurrentTab(tab);
}
Inside of the tab that I would like to be able to switch internally to another tab I created the method below:
public void switchTabInActivity(int indexTabToSwitchTo){
MintTrack parentActivity;
parentActivity = (MintTrack) this.getParent();
parentActivity.switchTab(indexTabToSwitchTo);
}
If you would like a good example of this code, you can take a look at my MintTrack project here and here.
As a side note, please be very careful when deciding whether to use view or activity based TabHost.
Activity based tabs are great because they can be separated into there own XML file. Activities can also be organized into there own Java file instead of being cluttered into one. That being said some of the things you would think would be easy become complicated with activity based tabs. Its hard to pass information between tabs without creating overhead. Activity based tabs also use more memory/CPU time as they have the overhead of the Activity around each of them. Please consider this and the many more trade offs before diving into using an Activity based TabHost. I know now that I would personally go with a view based TabHost if I ever used them again.
I encountered the same problem. While a single activity for all tabs would be better, sometimes taking the easy way out is the rational choice.
To avoid creating a new tab activity when a tab wants to change to another tab, I put this in my AndroidManifest.xml:
<activity android:name=".MyTabsActivity"
android:label="Tabs!"
android:launchMode="singleTask">
Send an intent with the tab you want:
class OneTabContentActivity {
void switchTab() {
final Intent intent = new Intent(mContext, MyTabsActivity.class);
intent.setAction("Switch to tab 1, please");
mContext.startActivity(intent);
}
class MyTabsActivity {
#Override
protected void onNewIntent (Intent intent) {
super.onNewIntent(intent);
getTabHost().setCurrentTab(1);
}
}
This solution has drawbacks but I'm not clear over the details. Someone else might know enough to point them out.
First, I set a method to my main class, which extends TabActivity let's call it "MainActivity"
public TabHost getMyTabHost() { return tabHost; }
Then, I add my tab activity class;
MainActivity ta = (MainActivity) this.getParent();
TabHost th = ta.getMyTabHost();
th.setCurrentTab(0);
It worked for me.
Step #1: Replace the tabs-holding-activities with tabs-holding-views by using a better form of setContent() on TabSpec
Step #2: Call setCurrentTab() on your TabHost from within your single Activity
I have yet to see any benefit to having an Activity be the content of a tab rather than a simple View. Having an Activity as the content of the tab wastes CPU time and memory (and, hence, battery life) and makes things like you're trying to do much more difficult.
I had a slightly different problem and thought I'd add this for anyone else facing a similar situation. I have an activity-based tabbed application and one of the tab activities launches another activity which is not controlled by the tabHost. I needed to have a button on this activity finish() (ie: return back to the main Tab view) and switch to a different tab at the same time.
I decided to handle it with a BroadcastReceiver. In the class that sets up the TabHost, I added this class:
class ChangeTabReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "ChangeTabReceiver: received");
TabHost tabHost = getTabHost();
tabHost.setCurrentTab(1);
}
}
..then defined the vars:
ChangeTabReceiver changeTabReceiver;
IntentFilter changeTabFilter;
..then added to onCreate():
changeTabReceiver = new ChangeTabReceiver();
changeTabFilter = new IntentFilter(myApplication.CHANGE_TAB);
registerReceiver(changeTabReceiver, changeTabFilter);
Finally in the new activity when you want to close that activity and switch the tabs, do this:
Intent intent = new Intent(myApplication.CHANGE_TAB);
this.sendBroadcast(intent);
this.finish();
Of course you could make a method to switch to various tabs by passing the tab index -- but in my case this behavior only occurs in one activity so I decided to keep it simple...
public void switchTab(int index){
MintTrack ParentActivity;
ParentActivity = (MintTrack) this.getParent();
ParentActivity.getTabHost().setCurrentTab(index);
}
I just put a public static TabHost tabHost;
in my TabActivity.
Then from any other tab I can do a MyTabActivity.tabHost.setCurrentTab(tabNumber);
Works fine for me (but I wish I'd used Fragments from the start.. I was just following the Tab tutorial in the Android documentation and working from there)
There are 4 Tabs in a TabHost, let them be A, B, C, and D. Now each one is just an index page and clicking on any of them shows a different activity.
The problem is that I need to start another activity when the user selects something from the content displayed in the tab. The other activity should also be displayed in the parent tab itself. Is it possible? Or will I have to try something else?
Try this, found this solution in android cookbook,
http://androidcookbook.com/Recipe.seam;jsessionid=5424397F3130CE7769FF47DD67742911?recipeId=1693&recipeFrom=ViewTOC
Can't you change the contentView of your tab instead of starting a new Activity ?
Maybe I'm wrong but I think also that starting an activity in a tab isn't possible because the TabView is hosted in a activity and not the opposite (Tabview don't host an activity per Tab).
I think the common consensus is that it is best not to use individual Activities as tab content due to these limitations. See these questions and answers for pointers to alternatives:
Android: Why shouldn't I use activities inside tabs?
Android - Tabs, MapView, activities within tabs
To summarize the link that Rukmal Dias provided. Here's what you do:
Change your current Activity (that's in a tab) to derive from ActivityGroup
Create a new intent for the Activity you want to switch to
Copy/Paste and call this function in your current activity where "id" is the "android:id" for the layout of the new activity you want to switch to
public void replaceContentView(String id, Intent newIntent){
View view = getLocalActivityManager().startActivity(id,newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)) .getDecorView();
this.setContentView(view);}
Here's an example of how I make the call to switch views from my current Tabbed Activity:
public void switchToNextActivity(View view)
{
Intent myIntent = new Intent(getApplicationContext(), MyNextActivity.class);
replaceContentView("next_activity", myIntent);
}
It looses the view hierarchy. When you press the back button, in my case, the app closes.