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.
Related
I need show a TextView in all Activities, but is much work to do it one by one, because I have +10 Activities.
My objective is when I click in a button, show a textview ("Importing ...") at the bottom of the application. This textview will disappear when I receive a push notification, and I owe a pop up with the response (the pop up also has to appear in any activity).
My project has a custom abstract BaseActivity and all activities extends it.
public abstract class BaseActivity extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
protected void setActionBar(#IdRes int idResToolbar) {
Toolbar toolbar = (Toolbar) findViewById(idResToolbar);
setSupportActionBar(toolbar);
updateFont(toolbar);
}
// ...
}
I think I could use for my purpose but not how to do it.
If anyone has any suggestions I will be happy to hear it.
Thanks in advance.
Use fragments for your content (instead of different activites) you then can add global views to the activity, which holds the fragments.
If you don't want to do that, you'd have to modify the layout(s) in your Base class.
I would suggest you to use a PopupWindow that contains the text view and create a separate class that initializes the PopupWindow on the basis of context given to it.
Now in all your Activities you will have the control of showing and hiding the window as you want. Make sure to make all utility methods required in the separate class to avoid coherence for example hiding and showing the window. setting text of text view of the window and etc.
You can write in onCreate() of your base activity something like
setContentView(R.layout.base_layout);
And in every other Activity at start of onCreate() method, just use super.onCreate()
And more than that to support different layouts add something like this in onCreate() (example for one of activities)
LayoutInflater inflater = getLayoutInflater();
inflater.inflate(R.layout.activity_1_layout,rootGroup)
where rootGroup is a ViewGroup in your Base Activity, in which you will add additional components for every other activity
Create a service, which creates a View which can be drawn over other apps (will require the relevant permission in the manifest)
You could use one of the open source libraries available like this or refer to this example
It's better you use fragments instead of using many activities. However, if you don't wanna do so, I suggest you create a factory which will generate a textview to all activities. Then you must add it into each activity's view.
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));
}
I have an app that can create tabs dynamically. And when I create a tab I initiate an activity as an intent. Like so:
private void addTab(Context packageContext, Class<?> newClass, TabHost mTabHost, String tabId, String tabLabel){
// newClass is my Activity class that I want to start in the tab
Intent intent = new Intent().setClass(packageContext, newClass);
TabHost.TabSpec spec;
spec = mTabHost.newTabSpec(tabId).setIndicator(tabLabel)
.setContent(intent);
mTabHost.addTab(spec);
mTabHost.setCurrentTabByTag(tabId);
}
Pretty standard. And it works great. Now, suppose that I have a button (or menuitem, whatever) in the activity that I instantiated inside of my tab. When the user presses this button, I want the activity, and the tab it is inside of, to be removed and destroyed.
I can't seem to find a simple way to do this. I have found the TabHost.clearAllTabs() function, but this destroys all tabs and activities, I just want to remove one.
Someone suggested I save a list of all Tabs that I have opened, and then call clearAllTabs(), after which I recreate all of my other tabs except for the one I don't want.
Something like this:
public static ArrayList<TabHost.TabSpec> list = new ArrayList<TabHost.TabSpec>();
I add this line to my addTab() function so that every tab I create is remember in my ArrayList:
list.add(spec);
And then when I want to remove my tab I run this function:
public static void removeTab(){
list.remove(list.size()-1); // remove it from memory
mTabHost.clearAllTabs(); // clear all tabs from the tabhost
for(TabHost.TabSpec spec : list) // add all that you remember back
mTabHost.addTab(spec);
}
This removes my tab from my ArrayList, removes all tabs, then recreates all the tabs remaining using my ArrayList. In theory it should work, but I get the following error when I try call this function:
FATAL EXCEPTION: main
java.lang.NullPointerException
at android.widget.TabWidget.setCurrentTab(TabWidget.java:342)
at android.widget.TabWidget.focusCurrentTab(TabWidget.java:366)
at android.widget.TabHost.setCurrentTab(TabHost.java:323)
at android.widget.TabHost.addTab(TabHost.java:216)
at com.example.myapp.TabManager.removeTab(QuikBrowser.java:86)
at com.example.myapp.TabManager.TabWindow.onOptionsItemSelected(TabWindow.java:91)
at android.app.Activity.onMenuItemSelected(Activity.java:2205)
For some reason, when adding a tab, it attempts to set the current tab, and it hits a null pointer exception.
If you guys could suggest another way of achieving what I want to do, or a way to fix my current method, I would appreciate it.
Try changing current tab to 0.
Something like:
getTabHost().setCurrentTab(0);
getTabHost().clearAllTabs();
I was reading that calling clearAllTabs(); will throw a nullpointerexception if you don't set the tabhost to the first tab (.setCurrentTab(0)) before calling (.clearAllTabs())
Also this answer may help? (How to remove tab from TabHost)
I would suggest a different approach. You can use an ActivityGroup to build your own TabControl. As you are using normal Buttons (or similar controls just as you like) you can easyly arrange/create/remove them as needed.
I can't dump the whole code here but that is basically what I did when I had the same problem:
Create an Activity inherited from ActivityGroup
Place a ViewGroup in your layout where you want to show the sub-activities
Setup your buttons as needed (LinearLayout works fine with a variable count of buttons)
Start activites thru getLocalActivityManager().startActivity() as needed
You can now add/remove buttons as you like. The Activites follow the Android lifecycle so you don't have to delete them yourself.
You might have to implement onBackPressed on your ActivityGroup to properly handle the history but that depends on the project.
I have an Android application which has four tabs (I use a main TabActivity with TabHost and TabSpecs).
In one of my sub activity (activity opened in a tab), i need to open a tab not by clicking on the tab title and i don't know how to do this.
For example, i have a button in my activity and when i click on it, it opens a different tab.
For the moment, it is what i do:
Intent intent = new Intent(myActivity.this, myTabActivity.class);
intent.putExtra("ComeFrom", true);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
Then in the TabActivity, if i get true reading the "ComeFrom" extra i open the wished tab but the problem is that it kills all the other activies. So, if someone knows a better (cleaner) way to do that trick, please tell me...
Found an easier (I think) answer:
on the TabActivity declare a public, static and self variable and populate it on the onCreate method. F.e.:
public class TheActivity extends TabActivity {
public static TheActivity self;
...
#Override
public void onCreate(Bundle savedInstanceState) {
self=this;
on any Activity running in a tab, when you want to change the one shown on your app. you can do this:
TabHost tabHost = TheActivity.self.getTabHost();
tabHost.setCurrentTab(0);
Worked ok for me, hope serves someone else!
You have to use TabHost's "setCurrentTab(...)" for that. In one of my projects, I created a static method in the main Activity (the one with the TabHost), named "swtichToTab(int tab)". In my subactivites (those inside the tabs) could then just call "MainActivity.switchToTab()" to trigger switching.
It may not be the cleanest method, I'm sure you can achieve this using broadcast intents too.
You can create a BroadcastReceiver and send a broadcast with the index of the tab as extra
You can use views instead of activities for the content of the tabs. This way, the code is simpler and doesn't use as much memory. Plus, you then can use the setCurrentTab(tabIndex) method to easily switch between views.
I have a simple tutorial here. It has a tab activity with a list and map view. When you you click on an item in the list, the activity dynamically goes to the map view (using the setCurrentTab(tabIndex) method). You can easily modify this to have a button switch views.
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)