I have an application which has a TabHost set up with 5 tabs. These tabs are fragment activities. In each of these fragment activities, there is are several fragments set up.
My Main class sets up the tabHost and fragment activities like so
public class Main extends TabActivity
{
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);
Resources res = getResources();
tabHost = getTabHost();
TabHost.TabSpec spec;
Intent intent;
intent = new Intent().setClass(this,
Tab1.class);
spec = tabHost
.newTabSpec("home")
.setIndicator("Home",
res.getDrawable(R.drawable.tabhome))
.setContent(intent);
tabHost.addTab(spec);
//and do this for the other 4 tabs
tabHost.setCurrentTab(0);
}
}
Then my fragmentActivities are set up like this
public class Tab1 extends FragmentActivity
{
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.home);
FragmentTransaction fragmentTransaction = getSupportFragmentManager()
.beginTransaction();
// Fragments
Fragment fragOne = new FragmentOne();
Fragment fragTwo = new FragmentTwo();
Fragment fragThree = new FragmentThree();
fragmentTransaction.replace(R.id.fragmentOne, fragOne);
fragmentTransaction.replace(R.id.fragmentTwo, fragTwo);
fragmentTransaction.replace(R.id.fragmentThree, fragThree);
fragmentTransaction.commit();
}
}
Tab1 Fragment Activity has 3 fragments as you can see above. Each Fragment, FragmentOne, FragmentTwo and FragmentThree each contain a next button inside the fragments.
What I would like to know is how do I set it up so they transition between each fragment within the class. E.g.
Frag1 (in Frag1 click next button ), Frag 2 transitions from the right (in Frag2 here click next button) Frag3 transitions in from the right (in Frag3, click next button) Frag1 transitions in from the right.
Any assistance would be much appreciated!!!
Edit: Will also paste how the fragments are set up in the home.xml layout file incase your wondering how I set it up.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/homeMain"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<RelativeLayout
android:id="#+id/FragmentOneRL"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:orientation="vertical" >
<FrameLayout
android:id="#+id/fragmentOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</FrameLayout>
</RelativeLayout>
<RelativeLayout
android:id="#+id/FragmentTwoRL"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:layout_below="#+id/FragmentOneRL"
android:orientation="vertical" >
<FrameLayout
android:id="#+id/fragmentTwo"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</FrameLayout>
</RelativeLayout>
<RelativeLayout
android:id="#+id/FragmentThreeRL"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:layout_below="#+id/FragmentTwoRL"
android:orientation="vertical" >
<FrameLayout
android:id="#+id/fragmentThree"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</FrameLayout>
</RelativeLayout>
</RelativeLayout>
I eventually figured it out, I changed the XML file to this
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<FrameLayout
android:id="#+id/TheFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</FrameLayout>
</RelativeLayout>
And then in the FragmentActivity I created this method
protected void changeFragment(Fragment removeFrag, Fragment f)
{
FragmentTransaction ft = fm.beginTransaction();
ft.setCustomAnimations(R.anim.view_transition_in_left,
R.anim.view_transition_out_left);
ft.replace(R.id.TheFragment, f);
ft.remove(removeFrag);
ft.addToBackStack(null);
ft.commit();
}
Then in each fragment when user clicked next button would do something like this
Fragment f = ((Tab1) getActivity()).fragTwo;
Fragment rf = ((Tab1) getActivity()).fragOne;
((Tab1) getActivity()).changeFragment(rf, f);
Related
I am trying to go to another fragment when clicking a button but i need to keep the button even when i am in the other fragment. I came out with this but it doesn't go to the other fragment when i click the button.in the activity nothing happens at all except the first fragment is shown:
public class Signupnew extends AppCompatActivity {
Button next;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_signupnew);
getSupportActionBar().hide();
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
next = (Button) findViewById(R.id.nextf);
final Fragment fragment = new f1();
final Fragment fragment2 = new f2();
FragmentManager fm = getSupportFragmentManager();
final FragmentTransaction transaction = fm.beginTransaction();
transaction.replace(R.id.contentFragment, fragment);
transaction.commit();
next.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (fragment.isAdded()){
System.out.println("added");
transaction.replace(R.id.contentFragment,fragment2);
}
if (fragment2.isAdded()){
System.out.println("added2");
transaction.replace(R.id.contentFragment, fragment);
}
}
});
}
}
XML:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="match_parent"
android:background="#drawable/signupmorenew"
tools:context=".Signupnew">
<FrameLayout
android:id="#+id/contentFragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<Button
android:id="#+id/nextf"
android:layout_width="350dp"
android:layout_height="60dp"
android:layout_marginLeft="28dp"
android:layout_marginTop="540dp"
android:background="#drawable/nextsignupandsignin"
android:fontFamily="#font/varroxfont"
android:text="التالي"
android:textColor="#FDBC30"
android:textSize="20dp" />
</FrameLayout>
</LinearLayout>
You have to call FragmentTransaction#commit to apply changes. Also I think it is a good practice to call the whole stack of operations for fragment transaction.
getSupportFragmentManager().beginTransaction()
.replace()
.commit()
I am trying to create tab layout with fragments. When i add another fragment on item click it should show another fragment above it. I am unable to get the goal. Fragment just goes above the existing one but both the fragments content are visible. Please don't throw the link towards any developer page for explanation.
Here is my code
home_activity.xml
<TabHost
android:id="#android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TabWidget
android:id="#android:id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</TabWidget>
<FrameLayout
android:id="#android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
android:id="#+id/tab1"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.example.tabsfragment.School_Fragment" >
</fragment>
<fragment
android:id="#+id/tab2"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.example.tabsfragment.Sports_Fragment" >
</fragment>
</FrameLayout>
</LinearLayout>
</TabHost>
Home_Activity.java
public class Home_Activity extends FragmentActivity {
TabHost mHost;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.home_activity);
mHost = (TabHost) findViewById(android.R.id.tabhost);
mHost.setup();
TabSpec schoolSpec = mHost.newTabSpec("School").setIndicator("School")
.setContent(R.id.tab1);
mHost.addTab(schoolSpec);
TabSpec sportSpec = mHost.newTabSpec("Sports").setIndicator("Sportss")
.setContent(R.id.tab2);
mHost.addTab(sportSpec);
mHost.setCurrentTab(1);
}
entertainment.xml
<FrameLayout
android:id="#+id/frameContainer"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
</FrameLayout>
I am adding another fragment on list_item_click inside Sports_Fragment
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
// TODO Auto-generated method stub
FragmentTransaction ft = getFragmentManager().beginTransaction();
Entertainment_Fragment enFragment = new Entertainment_Fragment();
ft.replace(android.R.id.tabcontent, enFragment);
ft.commit();
}
Here is the snapshot :
Any ideas/help with explanation would be highly appreciated.
Thanks!!
First of all, I think it's worth mentioning...
"You cannot replace a fragment defined statically in the layout file. You can only replace fragments that you added dynamically via a FragmentTransaction"
Please see
Android: can't replace one fragment with another
How can I show a new Fragment within a single tab?
Here's the solution.
In home_activity.xml, you should leave your tabcontent empty.
<FrameLayout
android:id="#+id/tabcontent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
Your Home_Activity
private FragmentTabHost mHost;
public void changeFragment() {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
EntertainmentFragment enFragment = new EntertainmentFragment();
ft.replace(R.id.tabcontent, enFragment);
ft.commit();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
mHost.setup(this, getSupportFragmentManager(), R.id.tabcontent);
mHost.addTab(mHost.newTabSpec("School")
.setIndicator("School"), SchoolFragment.class, null);
mHost.addTab(mHost.newTabSpec("Sport")
.setIndicator("Sport"), SportsFragment.class, null);
}
In your onIemClick (Sports_Fragment), add this
MainActivity mainAct = (MainActivity)getActivity();
mainAct.changeFragment();
My full project, which is based on your code, is here.
I haven't had a chance to really check why TabHost doesn't work when I tested your code.
But FragmentTabHost works fine for me.
Edit: To fix the overlap problem, you can set OnTabChangeListener:
mHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
#Override
public void onTabChanged(String tabId) {
// TODO Auto-generated method stub
if (tabId.equalsIgnoreCase("School")) {
Log.v(TAG, "school");
FragmentTransaction ft = getSupportFragmentManager()
.beginTransaction();
schoolFrag = new SchoolFragment();
ft.replace(R.id.tabcontent, schoolFrag);
ft.commit();
}
if (tabId.equalsIgnoreCase("Sport")) {
Log.v(TAG, "Sport");
FragmentTransaction ft = getSupportFragmentManager()
.beginTransaction();
SportsFragment sportFrag = new SportsFragment();
ft.replace(R.id.tabcontent, sportFrag);
ft.commit();
}
}
});
About the backpress, you can try
ft.addToBackStack(null);
I have a Button in Fragment. If Button is clicked it has to replace the Fragment with another Fragment. The Fragments in activity_main.xml is created statically.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#efefef"
android:orientation="vertical"
tools:context=".MainActivity" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="3" >
<Button
android:id="#+id/bHome"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_weight="1"
android:background="#000000"
android:padding="3dp"
android:text="Home"
android:textColor="#ffffff" />
<Button
android:id="#+id/bEvents"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_weight="1"
android:background="#f8bd0e"
android:padding="3dp"
android:text="Events" />
<Button
android:id="#+id/bNearby"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_weight="1"
android:background="#f8bd0e"
android:padding="3dp"
android:text="Nearby" />
</LinearLayout>
<LinearLayout
android:id="#+id/llFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal" >
<fragment
android:id="#+id/fHome"
android:name="com.example.fragmentstack.Home"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp" />
<fragment
android:id="#+id/fEvents"
android:name="com.example.fragmentstack.Events"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp" />
<fragment
android:id="#+id/fNear"
android:name="com.example.fragmentstack.NearBy"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp" />
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</FrameLayout>
</LinearLayout>
The output of activity_main.xml is
Main Activity:
public class MainActivity extends FragmentActivity implements OnClickListener {
Button home, events, near;
Fragment f1, f2, f3, f4;
FragmentManager manager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
home = (Button) findViewById(R.id.bHome);
events = (Button) findViewById(R.id.bEvents);
near = (Button) findViewById(R.id.bNearby);
home.setOnClickListener(this);
events.setOnClickListener(this);
near.setOnClickListener(this);
manager = getSupportFragmentManager();
f1 = manager.findFragmentById(R.id.fHome);
f2 = manager.findFragmentById(R.id.fEvents);
f3 = manager.findFragmentById(R.id.fNear);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bHome:
if (home.isPressed()) {
home.setBackgroundColor(Color.BLACK);
home.setTextColor(Color.WHITE);
events.setBackgroundResource(R.color.Yellow);
near.setBackgroundResource(R.color.Yellow);
events.setTextColor(Color.BLACK);
near.setTextColor(Color.BLACK);
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
transaction.hide(f2);
transaction.hide(f3);
transaction.show(f1);
transaction.commit();
}
break;
case R.id.bEvents:
if (events.isPressed()) {
events.setBackgroundColor(Color.BLACK);
events.setTextColor(Color.WHITE);
home.setBackgroundResource(R.color.Yellow);
near.setBackgroundResource(R.color.Yellow);
home.setTextColor(Color.BLACK);
near.setTextColor(Color.BLACK);
FragmentTransaction transaction1 = getSupportFragmentManager()
.beginTransaction();
transaction1.hide(f1);
transaction1.hide(f3);
transaction1.show(f2);
transaction1.commit();
}
break;
case R.id.bNearby:
if (near.isPressed()) {
near.setBackgroundColor(Color.BLACK);
near.setTextColor(Color.WHITE);
home.setBackgroundResource(R.color.Yellow);
events.setBackgroundResource(R.color.Yellow);
home.setTextColor(Color.BLACK);
events.setTextColor(Color.BLACK);
FragmentTransaction transaction2 = getSupportFragmentManager()
.beginTransaction();
transaction2.hide(f1);
transaction2.hide(f2);
transaction2.show(f3);
transaction2.commit();
}
break;
}
}
}
Now Home extends Fragment. the xml layout of home has one Button and one TextView.Here onClicking Button I'm replacing the Home Fragment with new Update Profile Fragment.
public class Home extends Fragment {
Button btn;
View view;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
view = inflater.inflate(R.layout.home, container, false);
init();
return view;
}
private void init() {
btn = (Button) view.findViewById(R.id.bUpdate);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Fragment fg = new UpdateProfile();
FragmentTransaction fragmentTransaction = getFragmentManager()
.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fg);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
});
}
}
R.id.fragment_container is present in activity_main.xml. Now the problem I'm facing is when clicking the button it is not replacing the fragment with new Fragment.
Now the problem I'm facing is when clicking the button it is not
replacing the fragment with new Fragment.
The transaction does occur but it's not visible as you add that fragment to a container that will be pushed out of the screen(all of your layout's fragments have width set to match_parent so they will fill the LinearLayout's width and the FrameLayout will be pushed out of the screen).
Also you do the replace transaction on a container that doesn't hold the previous fragments, this means that the old fragments will still be visible on the screen(plus the new added fragment).
The system you setup is not the proper way to handle your scenario. From the images it seems you have a tab like layout and in this case you should have only one container in which all of your fragments will reside(to avoid the extra work of showing/hiding the proper fragment and also provide a decent BACK button experience).
Secondly if you're going to work(do transactions) with those fragments you should really add them programmatically as replace will not go well with a static fragments. There are a lot of tutorials out there on how to make a tab like layout with fragments.
I have got some sample FragmentTabHost project. And I made some modifications which are required for my project.
my tab bar xml (bottom_tabs.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<FrameLayout
android:id="#+id/realtabcontent"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1" />
<android.support.v4.app.FragmentTabHost
android:id="#android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<FrameLayout
android:id="#android:id/tabcontent"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="0" />
</android.support.v4.app.FragmentTabHost>
</LinearLayout>
oncreate() - FragmentActivity
mTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
Bundle b = new Bundle();
b.putString("key", "Simple");
mTabHost.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"),
Fragment1.class, b);
//
b = new Bundle();
b.putString("key", "Contacts");
mTabHost.addTab(mTabHost.newTabSpec("contacts")
.setIndicator("Contacts"), Fragment2.class, b);
b = new Bundle();
b.putString("key", "Custom");
mTabHost.addTab(mTabHost.newTabSpec("custom").setIndicator("Custom"),
Fragment3.class, b);
Fragment3 class
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_3,
null);
Button b = (Button) root.findViewById(R.id.button1);
b.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Fragment f;
f = (Fragment) new Fragment4();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.realtabcontent, f);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
}
});
return root;
}
The Problems:
**
1) If I press goto1 button in Fragment3 , It redirects to Fragment4.
No Issues
2) Then I press the tabs, the layout of the Fragment4 is overlapped
in all the screens
3) If I press goto 2nd tab button, How to redirect to Fragment2 and
same time 2nd tab should be highlighted.
**
Please provide me the best way to do this.
To change tabs your should use the FragmentTabHost.setCurrentTab() method instead of using FragmentTransaction yourself (it is handled internally). The reason your Fragment4 is appearing overlapped is because it is never removed when you change tabs.
This is what is happening:
You navigate to tab 3.
You press the goto fragment4 button which causes your code to replace fragment3 with fragment4
You press another tab indicator. This causes the FragmentTabHost to remove the current fragment (which it still thinks is Fragment3) and add the new Fragment. The Fragment4, which you added manually, is still there. To avoid this you could add a listener for tab change events and explicitly remove Fragment4 if it is there.. Or even better you could add Fragment4 as a child fragment of Fragment3. That way when you leave Tab3 it will go away, and it will appear again when you return to Tab3. It just depends on what you are trying to accomplish.
I used ActionBarSherlock to get some Holo Themed Tabs and an ActionBar on my app and created a Fragment to handle the behavior on each tab. I wanted the tabs and a button along the bottom to "sandwich" the fragments do at the bottom of the screen there would be a button that would have one click listener across both fragments.
In my Activity I created the tabs like this.
public class InviteFriendsActivity extends SherlockFragmentActivity implements ActionBar.TabListener
{
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
ActionBar bar = getSupportActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.Tab tab1 = bar.newTab();
tab1.setText("Tab 1");
tab1.setTabListener(this);
ActionBar.Tab tab2 = bar.newTab();
tab2.setText("Tab 2");
tab2.setTabListener(this);
bar.addTab(tab1);
bar.addTab(tab2);
}
}
And then I created the onTabSelected
public void onTabSelected(Tab tab, FragmentTransaction ft)
{
if (tab.getPosition() == 0)
{
Fragment1 frag = new Fragment1();
ft.replace(android.R.id.content, frag);
}
else if (tab.getPosition() == 1)
{
Fragment2 frag = new Fragment2();
ft.replace(android.R.id.content, frag);
}
}
I have no problem getting the tabs to display or change, but I can't seem to figure out how to get a button the would line the bottom of the screen and stay static while inside this activity and still allow me to switch between the two fragments.
You want a button which is displayed through every fragment and each tab?
This can easily done by using a fragmentcontainer which displays your fragments.
For example use a layout like this:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
android:name="com.example.yourfragmentcontainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/button1"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" />
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:text="Button" />
</RelativeLayout>
For help how to setup a ActonBar using a fragmentcontainer take a look at this tutorial: http://arvid-g.de/12/android-4-actionbar-with-tabs-example