Here's my problem:
I've have an application with tabs.
in each tab I have a list that list to an other list then to a screen with an image, clickable text etc.
In one word I have Tasks inside tabs.
Question
Despite long seek among forum and tutorials I still can't figure witch is the best pactice to do that : switching activity insde a tab
or changing the view.
Here my code
public class App extends TabActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Resources res = getResources(); // Resource object to get Drawables
TabHost tabHost = getTabHost(); // The activity TabHost
TabHost.TabSpec spec; // Reusable TabSpec for each tab
Intent intent; // Reusable Intent for each tab
// Create an Intent to launch an Activity for the tab (to be reused)
intent = new Intent().setClass(this, Activity0.class);
// Initialize a TabSpec for each tab and add it to the TabHost
spec = tabHost.newTabSpec("0").setIndicator("0",
res.getDrawable(R.drawable.ic_tab_0))
.setContent(intent);
tabHost.addTab(spec);
intent = new Intent().setClass(this, Activity1.class);
spec = tabHost.newTabSpec("1").setIndicator("1",
res.getDrawable(R.drawable.ic_tab_1))
.setContent(intent);
tabHost.addTab(spec);
then I have to switch activities (Activity0 -> Activity01) inside tab 0
public class Activity0 extends Activity{
..
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mainlist);
ListView l1 = (ListView) findViewById(R.id.ListView01);
l1.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// Toast.makeText(getBaseContext(), "You clciked "+parentTypes.get(arg2).getLibelle(), Toast.LENGTH_LONG).show();
/*TODO database method */
TypeEvenement parent = parentTypes.get(arg2);
if (parent.getChildren().size()!=0)
{
Intent i = new Intent(TypeParentList.this, TypeChildList.class);
int id= new Long(parentTypes.get(arg2).getId()).intValue();
i.putExtra("typeid", id);
View view = lam.startActivity("TypeChildList",i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)).getDecorView();
setContentView(view);
then go back to this activity from Activity01
public class Activity01 extends Activity{
tv.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Intent i = new Intent(TypeChildList.this, Activity0.class);
LocalActivityManager lam = pa.getLocalActivityManager();
View view2 = lam.startActivity("Activity0",i).getDecorView();
setContentView(view2);
}
});
After go and back I get an error java.lang.IllegalStateException The specified child already has a parent. You must call removeView() on the child's parent first.
I know it comes from my view but I can't figure out how to fix it
So is this the best practice to do multiple activity in one tab ?
Please help needed
If you use a ViewSwitcher or ViewFlipper you can keep the View attached to that and switch back and forth to your hearts desire.
One approach with a tab bar or a common shortcut bar is to have a separate class to handle the OnClickListeners that call startActivity(newIntent) and finish() back to back. I'm not too fond of what the default TabView looks like, so I tend to make a graphical toolbar and use this approach.
Related
I am adding a new tab layout to my app. My app has 4 activities.
Before, the navigation was done with buttons displayed in activities, for example a button in activity 1 make you go to section 4. Each button was starting a new activity with a new intent. To go back user could hit his native device back button.
Example of button:
Button b1= (Button) findViewById(R.id.b1);
b1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(this, ActivityTab4.class);
startActivity(i);
}
});
Now, with the tabhost, user goes straight to desire activity, each activity is a child of my tabhost. However, I still need in my layout to keep some buttons that jump directly to a particular activity.
The problem, with these buttons, is that when they start a new activity, the tabhost disappears. I need to keep it at all time.
So how can I use the tabhost normally, but on the top of it also use custom buttons inside the layout of my sections that would keep the tabhost when I hit them?
My tabhost structure is very basic:
public class TabWidget extends TabActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.global_tabs);
setTabs() ;
}
private void setTabs() {
addTab("Act1", R.drawable.tab1, ActivityTab1.class);
addTab("Act2", R.drawable.tab2, ActivityTab2.class);
addTab("Act3", R.drawable.tab1, ActivityTab3.class);
addTab("Act4", R.drawable.tab2, ActivityTab4.class);
}
private void addTab(String labelId, int drawableId, Class<?> c) {
TabHost tabHost = getTabHost();
Intent intent = new Intent(this, c);
TabHost.TabSpec spec = tabHost.newTabSpec("tab" + labelId);
// SET TITLETAB
View tabIndicator = LayoutInflater.from(this).inflate(R.layout.tab_indicator, getTabWidget(), false);
TextView title = (TextView) tabIndicator.findViewById(R.id.titleTab);
title.setText(labelId);
// SET IMAGETAB
ImageView icon = (ImageView) tabIndicator.findViewById(R.id.icon);
icon.setImageResource(drawableId);
spec.setIndicator(tabIndicator);
spec.setContent(intent);
tabHost.addTab(spec);
}}
Thanks for your help
EDIT: I would rather avoid fragments because it's going to take me a lot of time to implement them and on the top of that to make it compatible with API<11
All right, I've found it, thanks to this answer: setCurrentTab of a tabHost
BAsically in the main tabhost activity, add this
private static Main theInstance;
public static Main getInstance() {
return Main.theInstance;
}
public Main () {
Main.theInstance = this;
}
In the child, you can have a button sending the user to any tab + corresponding activity:
Button b1_3= (Button) findViewById(R.id.b1_3);
b1_3.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
TabWidget.getInstance().getTabHost().setCurrentTab(3);
}
});
Any reason why you use tabhost and activities instead of Fragments? I think you would find Fragments more suited to what you're trying to do.
As for your question - you can switch the displayed tab with
void setCurrentTab(int index)
void setCurrentTabByTag(String tag)
so there's no need to manually starting an activity on button press, just switch the displayed tab using these methods.
I want to create something like this
|Button|
item 1
item 2
item 3
.
.
.Items on a listview
I already have a tabhost with 3 tabs, so i don't want to change my main.xml because the button will appear on every tab! i want my first tab to show a calendar (this one is done, i'm not sure if its ok but it has be done), the second tab will show something diferrent and the last one the button and the item list underneath.
I donnot paste any code because everything i've done comes from android tutorials, so i don't want to ask someone to give me an already written code, just to guide me through what do i have to read and where to look to achieve that!
Thanks in advance!
Well this is what I've done so far
this is my main class
`public class HourPayActivity extends TabActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Resources res = getResources(); // Resource object to get Drawables
TabHost tabHost = getTabHost(); // The activity TabHost
TabHost.TabSpec spec; // Resusable TabSpec for each tab
Intent intent; // Reusable Intent for each tab
// Create an Intent to launch an //setContentView(R.layout.emptab); Activity for the tab (to be reused)
intent = new Intent().setClass(this, MonthsActivity.class);
// Initialize a TabSpec for each tab and add it to the TabHost
spec = tabHost.newTabSpec("Months").setIndicator("",
res.getDrawable(R.drawable.ic_tab_months))
.setContent(intent);
tabHost.addTab(spec);
// Do the same for the other tabs
intent = new Intent().setClass(this, EmployersActivity.class);
spec = tabHost.newTabSpec("Employers").setIndicator("",
res.getDrawable(R.drawable.ic_tab_employers))
.setContent(intent);
tabHost.addTab(spec);
intent = new Intent().setClass(this, PaymentsActivity.class);
spec = tabHost.newTabSpec("Payments").setIndicator("",
res.getDrawable(R.drawable.ic_tab_payments))
.setContent(intent);
tabHost.addTab(spec);
tabHost.setCurrentTab(0);
}
}
`
And this is the tab content that i want to show up
public class EmployersActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ListView employersList = getListView();
String[] employers = getResources().getStringArray(R.array.employers_list);
setListAdapter(new ArrayAdapter<String>(this, R.layout.list_item, employers));
employersList.setAdapter(getListAdapter());
employersList.setTextFilterEnabled(true);
employersList.setOnItemClickListener(new OnItemClickListener() {
//#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// When clicked, show a toast with the TextView text
Toast.makeText(getApplicationContext(), ((TextView) view).getText(),
Toast.LENGTH_LONG).show();
}
});
setContentView(employersList);
}
What you do is; You follow the android tutorial, which tells you to create an class that extends TabActivity if I remember correctly.
In this activity you load intents via
TabHost.TabSpec spec = tabHost.newTabSpec([title]);
....
Intent content = new Intent(this, activityToLoad.class);
spec.setContent(content);
tabHost.addTab(spec);
What this does is, it loads an activity in a tab.
This in turn means that you can use an activity like normal, you can use custom layouts with setContentView(R.layout.yourlayout); in the onCreate() method. You can call your components, attach a custom list adapter to your list and so on. For the 3 tabs create 3 different activities. Based on personal knowledge its the easiest way to maintain your tabs.
What you put in these layout is upto you. But those activities you put in the tabs are "normal" activities like you are (probably) familiar with.
To explain your view:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/btnId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/yourtext"
/>
<ListView
android:id="#android:id/android:list"
android:layout_height="fill_content"
android:layout_width="match_parent"
/>
</LinearLayout>
This will place a button at the top with a listview underneath it.
The id of the listview is android:list because in my activity i extend listActivity, which expects a listview with that id.
I use a TabHost.
The below code to call AActivity.
intent = new Intent().setClass(this, AActivity.class);
spec = tabHost.newTabSpec("A").setIndicator("A", res.getDrawable(R.drawable.icon)).setContent(intent);
tabHost.addTab(spec);
And it is in the tab.
But in AActivity I call BActivity.
The BActivity will open new page, but not in the tab.
How to let it on the tab frame?
AActivity use below code to call BActivity:
it = new Intent(this, BActivity.class);
startActivity(it);
If you want to open multiple activity in Tab then on Place of activity use Activity group for par tab and switch view in this activity group for open multiple Activity in single tab
you can take some help from this tutorial
You need to change the current selected tab. There's a method called setCurrentTabByTag(String tag) in the TabHost class that will do that, just pass the tag name of your tab (which in your case is B), or you can use the setCurrentTab(int index) and pass the tab index.
Example. Usually I have a MainActivity class, which is my TabActivity. Inside of this class, I will create all tabs that I need on the onCreate method.
First I set some static int with the tabs indexes.
// Tab index.
public static int FIRST_TAB = 0;
public static int SECOND_TAB = 1;
Later, I create my tabs in the onCreate method.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Setting the content view.
setContentView(R.layout.main);
// Getting the TabHost object.
mTabHost = getTabHost();
// Declaring the Intent object for the tabs.
Intent intent;
// Creating the First tab.
intent = new Intent().setClass(this, MyFirstActivity.class);
addTab(mTabHost, "First", FIRST_TAB, intent)
// Creating the Second tab.
intent = new Intent().setClass(this, MySecondActivity.class);
addTab(mTabHost, "Second", SECOND_TAB, intent);
// Setting the current tab.
switchTab(FIRST_TAB);
}
public void addTab(TabHost host, String title, String tag, Intent intent) {
TabHost.TabSpec spec = host.newTabSpec(tag);
spec.setContent(intent);
spec.setIndicator(title);
host.addTab(spec);
}
And last the method that will change the current tab.
public void switchTab(int index) {
mTabHost.setCurrentTab(index);
}
Later, inside of the MyFirstActivity you can call the MainActivity swichTab method and pass the index of the tab to change it.
You can retrieve the MainActivity calling the getParent() method of the Activity class.
MainActivity parent = (MainActivity)getParent();
In the tab activity class where the tabhost is created, implement the following method.
public void switchTab(int tab){
tabHost.setCurrentTab(tab);
}
In AActivity/BActivity implement the following method and call it on any event(that you need):
public void switchTabInActivity(long indexTabToSwitchTo){
TabActivity tabActivity;
tabActivity = (TabActivity) this.getParent();
tabActivity.switchTab(indexTabToSwitchTo);
}
Here TabActivity is the class where tabhost is created
I am currently in an Android project where our main view is a TabActivity and each tab is a separate Activity. One is a MapActivity and the other two are ordinary Activities.
First note that I think we must have each tab as separate activities, as there is too much code in the separate activities to just have the TabHost switch the content view on a tab change and have all of the code in the same class. Anyways, back to the problem.
One of the tabs include a button, which when pressed should make the TabActivity switch to the MapActivity and animate the map to a specific location.
The tutorial found on http://joshclemm.com/blog/?p=86 shows how to do it if the TabHost contains a mapview and a listview. If an item in the ListView is clicked, the TabHost switches to the mapview and animates to that location (those coordinates). This is exactly what i need to do when the button in the separate activity is pressed.
The MainView.java is created as follows:
public class MainView extends TabActivity implements OnTabChangeListener{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Resources res = getResources(); // Resource object to get Drawables
TabHost tabHost = getTabHost(); // The activity TabHost
TabHost.TabSpec spec; // Resusable TabSpec for each tab
Intent intent; // Reusable Intent for each tab
intent = new Intent().setClass(this, MapGUI.class);
spec = tabHost.newTabSpec("map").setIndicator("Map",
res.getDrawable(R.drawable.ic_tab_menu_item))
.setContent(intent);
tabHost.addTab(spec);
intent = new Intent().setClass(this, MissionView.class);
spec = tabHost.newTabSpec("mission").setIndicator("Mission",
res.getDrawable(R.drawable.ic_tab_menu_item))
.setContent(intent);
tabHost.addTab(spec);
intent = new Intent().setClass(this, SIPView.class);
spec = tabHost.newTabSpec("call").setIndicator("Call",
res.getDrawable(R.drawable.ic_tab_menu_item))
.setContent(intent);
tabHost.addTab(spec);
The MissionView.java is as follows:
public class MissionView extends Activity implements Observer{
MissionController mc;
private TextView missionheader, missiondescription, missionaddress,
missiontime, missioninjuries;
private Button changedesc, gotoadress;
private String[] mission;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.missiontablayout);
missionheader = (TextView)findViewById(R.id.missionheader2);
missiondescription = (TextView)findViewById(R.id.missiondescription2);
missionaddress = (TextView)findViewById(R.id.missionaddress2);
missiontime = (TextView)findViewById(R.id.missiontime2);
missioninjuries = (TextView)findViewById(R.id.missioninjuries2);
changedesc = (Button)findViewById(R.id.gotoaddress);
changedesc.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// DO SOMETHING HERE?
}
});
mc = new MissionController(MissionView.this);
}
public void update(Observable observable, Object data) {
if(data instanceof String[]){
mission = (String[]) data;
updateView(mission);
}
}
public void updateView(String[] missiontext){
missionheader.setText(missiontext[0]);
missiondescription.setText(missiontext[1]);
missionaddress.setText(missiontext[2]);
missiontime.setText(missiontext[3]);
missioninjuries.setText(missiontext[4]);
}
}
Anyone know how i could achieve this?
Note that the code supplied above has no implementation to actually draw to the actual location, but the question still remains, how do I make a button pressed in one activity to switch tab in the TabHost and fire a change on that tab activity?
changing tabs in a TabHostcan easily be done with setCurrentTab(int)
http://developer.android.com/reference/android/widget/TabHost.html#setCurrentTab(int)
Sending events to other Activities can simply be achieved by sending a broadcast intent and receiving/handling it in the other Activity.
Alternatively you could save static references to all your tab Activities (ugly...) and call methods directly.
Place the below line on button click where you want to switch to the Map activity
((MainView) getParent()).setTabMap();
and in MainView create the following function
public void setTabMap()
{
//as Map activity is your first tab so pass 0 as index
getTabHost().setCurrentTab(0);
}
Can someone please tell me how to change tab by clicking on element INSIDE the tab? I already tried it with global data. The code looks like this:
public class Tabs extends TabActivity {
int tabNumber = 0;
private TabHost tabHost;
int returnedTabNumber = 0;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Resources res = getResources(); // Resource object to get Drawables
tabHost = getTabHost(); // The activity TabHost
TabHost.TabSpec spec; // Resusable TabSpec for each tab
Intent intent; // Reusable Intent for each tab
// Create an Intent to launch an Activity for the tab (to be reused)
intent = new Intent().setClass(this, Tribocracy.class);
// Initialize a TabSpec for each tab and add it to the TabHost
spec = tabHost.newTabSpec("map").setIndicator("Map",
res.getDrawable(R.drawable.ic_tab_artists))
.setContent(intent);
tabHost.addTab(spec);
// Do the same for the other tabs
intent = new Intent().setClass(this, Areas.class);
spec = tabHost.newTabSpec("areas").setIndicator("Areas",
res.getDrawable(R.drawable.ic_tab_albums))
.setContent(intent);
tabHost.addTab(spec);
// Do the same for the other tabs
intent = new Intent().setClass(this, Settings.class);
spec = tabHost.newTabSpec("settings").setIndicator("Settings",
res.getDrawable(R.drawable.ic_tab_albums))
.setContent(intent);
tabHost.addTab(spec);
tabHost.setCurrentTab(tabNumber);
}
protected void onResume() {
super.onResume();
GlobalData globalData = ((GlobalData)getApplicationContext());
returnedTabNumber = globalData.getTabNumber();
tabHost.setCurrentTab(returnedTabNumber);
}
}
The global adapter looks like this:
public class GlobalData extends Application {
//----------------------------------------------------
private int Point1; //define the vars here
private int Point2; //define the vars here
private int Point3; //define the vars here
private int Point4; //define the vars here
private int Point5; //define the vars here
private int Point6; //define the vars here
private int tabNumber;
public int getTabNumber() //getter of the value
{
return tabNumber;
}
public int setTabNumber(int number) //setter of the value
{
tabNumber = number;
return tabNumber;
}
}
Now when I'm trying to change tab in my ListActivity tab by clicking on one of the items it doesn't do anything and stays on the ListActivity tab. Perhaps I shouldn't use onResume() here. Basically I want to go to first tab when I click on one of the items in the list. Please help!
One way to do this is to use Intents. And there are many ways to use Intents for this. This works especially well for some cases, for example where the activity is displaying some content from a content provider. I'll describe one possible method below:
For the Activity that hosts the tabs, give it an intent filter if it doesn't already have one. For example, if it's an 'item detail'-style Activity, maybe its intent filter can match for ACTION_VIEW on a certain content type like vnd.android.cursor.item/vnd.somecontent.
Have the Activity take an extra such as focus_tab, and in the Activity's onCreate, after setting up the tabs, set the active tab to the one specified by this focus_tab extra.
Override onNewIntent, and in that method, look for that same focus_tab extra and set the active to the one specified by that extra.
Now, in your button code (i.e. a button inside one of your tab content activities), create an Intent that will start your host Activity, and give it a focus_tab extra corresponding to the tab you want to switch to. Add the FLAG_ACTIVITY_SINGLE_TOP Intent flag so you don't create a new instance of the host Activity. And then, call startActivity on that Intent you just created.
Note: I haven't tried this myself, but it should work in theory.