I'am build an app with an ActionBar and two Tabs below.
Everything works fine if the device / emulator isnt rotated. If rotated, tab state switches automaticale to tab1 (normal, because onCreate get called) but the content dont get changed. If I select a tab in the new orientation, the onCreateView() method from the selected Fragment get called but the view dont get updated (stay always the same). Any Tips?
The code.
Main Activity:
ActionBar actionbar = getActionBar();
actionbar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.Tab ATab = actionbar.newTab().setText(R.string.player);
ActionBar.Tab BTab = actionbar.newTab().setText(R.string.stations);
Fragment AFragment = new AFragment();
Fragment BFragment = new BFragment();
PlayerTab.setTabListener(new MyTabsListener(AFragment));
StationsTab.setTabListener(new MyTabsListener(BFragment));
actionbar.addTab(ATab);
actionbar.addTab(BTab);
With identical tabs that display a simple textview. The textview simple say which tab is selected.
Fragments:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.a, container, false);
}
The Fragment layout, mentioned above, only contains a TextView with hardcoded Text. (Only for testing purposes)
The Main layout looks like this.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</LinearLayout>
</LinearLayout>
Solved. I have recreated the fragment everytime, doesnt do that anymore solved it.
Changed in my TabListener and onTabSelected(Tab tab, FragmentTransaction ft), ft.add() to ft.replace()
Related
I have the problem that the tab content does not change when I use tabHost.setCurrentTab(...). One can see, that the corresponding tab is marked as active, the content stays the same. When I click on the tab, the content changes.
To the Setup.
I have different functionalities in one app using fragments. One fragment contains a tabhost. Each tab has its own layout and the fragment should switch between those tabs and show a selection of tabs depending on the state of the app.
I'll try to quote the important code passages.
The main xml file of the fragment:
<TabHost
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/tabHost"
xmlns:android="http://schemas.android.com/apk/res/android">
<TabWidget
android:id="#android:id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="fill"
android:background="#color/colorPrimary"/>
<FrameLayout
android:id="#android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<include layout="#layout/fragment_master_emg_start"
android:layout_height="445dp"
android:layout_width="fill_parent"
android:layout_gravity="center|bottom"/>
<include layout="#layout/fragment_master_emg_setup"
android:layout_height="445dp"
android:layout_width="fill_parent"
android:layout_gravity="center|bottom"/>
... some more includes
</FrameLayout>
</TabHost>
The xml files included just contain a relative layout and a bunch of buttons and textviews.
The Fragments onCreate Method:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Get View
View rootView = inflater.inflate(R.layout.fragment_master_emg, container, false);
Button button= (Button)rootView.findViewById(R.id.button);
button.setText("test");
TabHost tabHost=(TabHost)rootView.findViewById(R.id.tabHost);
tabHost.setup();
// Tabs
// Setup - Start Tab
TabHost.TabSpec t=tabHost.newTabSpec("Tab0");
t.setContent(R.id.master_emg_start);
t.setIndicator("EMG Measurement - Setup");
tabHost.addTab(t);
TabHost.TabSpec t0=tabHost.newTabSpec("Tab1");
t0.setContent(R.id.master_emg_setup);
t0.setIndicator("Setup");
tabHost.addTab(t0);
.... more tabs
....
// Set initial visibility
tabHost.getTabWidget().getChildAt(0).setVisibility(View.VISIBLE);
tabHost.getTabWidget().getChildAt(1).setVisibility(View.GONE);
// Buttons to switch tabs
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
TabHost tabHost=(TabHost)getActivity().findViewById(R.id.tabHost);
tabHost.getTabWidget().getChildAt(0).setVisibility(View.GONE);
tabHost.getTabWidget().getChildAt(1).setVisibility(View.VISIBLE);
tabHost.getTabWidget().setCurrentTab(1);
}
});
I've just included two tabs in this excerpt, but this would be the basic procedure.
I've tried to invalidade the tab host in order to have everythin redrawn. This did not change anything.
For anyone landing here for this problem solution:
Use :
tabHost.setCurrentTab(tabNumber);
Instead of :
tabHost.getTabWidget().setCurrentTab(tabNumber);
I'm trying to create a Fragment composed of multiple other fragments.
First I have one fragment covering the entire layout, which you could swipe left or right to go the the other fragments using a PagerAdapter.
Each of these Fragments will be composed of other fragments. At the moment it is composed of one textView, one Button and one Fragment (will be more repeats of this same fragment with small adjustments).
On each fullscreen-fragment I show which page I'm on by appending it to the TextView. This works.
I want to add the smaller Fragment dynamically. This doesn't work. It works on the first page that gets loaded, and it seems to be working when you go back to the previous page (only the exact previous) even when it didn't show the square when the page was first opened. This behaviour is demonstrated here:
You can see the text displays the fragment number. But the blue square should be on every one of the fragments. What could be wrong here?
CreateView() method of the fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_level_selector, container, false);
Bundle bundle=getArguments();
levelNumber=bundle.getInt("levelNumber");
textView = (TextView) view.findViewById(R.id.text);
textView.append(" " + levelNumber.toString());
String[] colors = {"#0000ff", "#00ff00", "#ff0000", "#ffff00"};
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.replace(R.id.include1, PictureFragment.newInstance(1, "#0000ff" ));
ft.commit();
return view;
}
Fragment layout xml
<TextView android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, I am a TextView" />
<FrameLayout
android:id="#+id/include1"
android:transitionName="pic1"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<Button android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:transitionName="pos1"
android:text="Hello, I am a Button"
android:onClick="sendMessage"/>
EDIT: this behaviour is only when setOffscreenPageLimit(0). If I set it higher only the first opened page has the blue square, all the others never have it. To me it seems like the getResources().getIdentifier() method always returns the object from the first page? Could this be true?
The problem was that ft.replace() replaces the first view it finds with the given id, as suggested by Code-Apprentice i the comment on the original question.
Changing
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
to
FragmentTransaction ft = getChildFragmentManager().beginTransaction();
Seems to have fixed the problem!
Solution from: ViewPager with multiple fragment instances of same class
I have a project I am working on in Android. I have one big fragment that covers the whole of the screen in my main activity. Normally I for each ui screen the user uses I would just do a replace command and swap the fragments for each screen.
In my current one I want to put a tablayout/viewpager combo with three different fragments and depending on what tab is pushed I will show a new fragment. Problem with this is that is a tablayout showing three different fragments inside another fragment. Is this even possible or recommended? and if I have to change it to a new activity. Would the navigation drawer act normally and just shut as I loaded the activity or is there going to be a problem there as well.
Thanks for your help
You can check below official documentation for the same or can use my demo snippet:
https://developer.android.com/reference/android/support/v4/app/FragmentTabHost.html
Try to do this to handle the Tabs in main fragment:
public class MainFragment extends Fragment {
private FragmentTabHost mTabHost;
//Mandatory Constructor
public MainFragment() {
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_tabs,container, false);
mTabHost = (FragmentTabHost)rootView.findViewById(android.R.id.tabhost);
mTabHost.setup(getActivity(), getChildFragmentManager(), R.id.realtabcontent);
mTabHost.addTab(mTabHost.newTabSpec("fragmentb").setIndicator("Fragment B"),
FragmentB.class, null);
mTabHost.addTab(mTabHost.newTabSpec("fragmentc").setIndicator("Fragment C"),
FragmentC.class, null);
mTabHost.addTab(mTabHost.newTabSpec("fragmentd").setIndicator("Fragment D"),
FragmentD.class, null);
return rootView;
}
}
With this tabs layout:
<android.support.v4.app.FragmentTabHost
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/realtabcontent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
Yes, TabLayout with viewPager will maintain it's different fragments in the memory.
Since, there are going to be only 3 tabs in your case it won't affect your memory performance, you can go with pagerAdapter.
You can reuse a single fragment for other tabs, but as i said since there are only 3 tabs, it won't affect your performance.
And Yes you can have tabLayout inside your main fragment, you main fragment is a part of your activity right, it will follow the same life cycle as the hosting activity except few other callbacks.
I am attempting to replace a nested fragment inside a tabLayout fragment.
My app structure follows this pattern.
Here is the XML for the Tab Fragment 2
<FrameLayout
android:id="#+id/scene_root"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".Home"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<FrameLayout
android:id="#+id/shows_fragment_list"
android:tag="list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<FrameLayout
android:id="#+id/shows_fragment_details"
android:tag="details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<FrameLayout
android:id="#+id/shows_fragment_info"
android:tag="info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</FrameLayout>
I am using this code to add the NestedFragment to the TabFragment FrameLayout
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View root = inflater.inflate(R.layout.shows_fragment_layout, container, false);
ShowDetailsFragment newNestedFragment = new ShowDetailsFragment();
android.support.v4.app.FragmentManager fragmentManager = getChildFragmentManager();
android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction
.add(R.id.show_fragment_details, newNestedFragment)
.addToBackStack("null")
.commit();
return root;
}
But when I add the Nested Fragment to the Tab Fragment, only the last part of my layout appears, in this case it is a list view (highlighted in red), but it always seems to be the which ever element is declared last when the layout is inflated by the corresponding Java file.
When I inflate these layouts as there own activity, there are no inflation problems, so it must relate to my implementation of fragments, any ideas where I am going wrong?
A good idea is always to use the Android Device Monitor to debug your layout.
I would also add some logging on the onCreateView of your fragments.
Ok so my problem was that in my XML layout for my ShowDetailsFragment (The Nested Fragment) I had a FrameLayout as the root, but there were two separate RelativeLayouts as children, meaning only the last element was being displayed, the problem was solved by nesting these two Relative Layouts in another single Relative Layout.
Props go to ctarabusi for pointing me in the right direction, although I am still unsure why this only caused a problem when inflating as a Fragment and not as an Activity.
I have great problems getting the Navigation Tabs work. I am aware of this guide http://developer.android.com/guide/topics/ui/actionbar.html#Tabs
but I have problems understanding the article. It says the following:
To get started, your layout must include a ViewGroup in which you place each Fragment associated with a tab. Be sure the ViewGroup has a resource ID so you can reference it from your code and swap the tabs within it. Alternatively, if the tab content will fill the activity layout, then your activity doesn't need a layout at all (you don't even need to call setContentView()). Instead, you can place each fragment in the default root view, which you can refer to with the android.R.id.content ID.
As I don't use a Fragment for my Main Layout, but for others, I think the "alternative" way is right for me (I would like Tab 1 to be the Main Layout I have right now and then 2 and 3 to be my fragments), but I don't know how to accomplish this. Can someone maybe help out on this?
I was able to set up the tabs and the TabListener, so that is not the problem. The problem is that the first tab is NOT supposed to be a fragment, but my main activity layout! This is where I need help!
I did try to use my main activity-layout for a fragment, but for some reason if I click that tab, the tab changes but the screen stays white. I cannot see my fragment view.
The old code was:
mListView = (ListView) findViewById(R.id.list_view);
mListView.setAdapter(mAdapter);
mListView.setTextFilterEnabled(true);
and I've changed it in the fragment to:
View view = inflater.inflate(R.layout.list, container, false);
mListView = (ListView) view.findViewById(R.id.list_view);
mListView.setAdapter(mAdapter);
mListView.setTextFilterEnabled(true);
// do stuff here //
return view;
and this is list.xml:
<FrameLayout xmlns:android:="http://schemas.android.com/apk/res/android"
android:id="#id/main_fragment"
android:layout_width="match_parent"
android:layout:height=match_parent">
<ListView android:id="#+id/list_view"
android:layout_width="match_parent"
android:layout:height=0dp"
android:layout_weight="1"
android:layout:marginTop="20dp"
android:descendantFocusability="blocksDescendants"/>
</FrameLayout>
how come I cannot see anything?
Solved: This was because I set the height to 0dp.
Please update your code by this:
<FrameLayout xmlns:android:="http://schemas.android.com/apk/res/android"
android:id="#+id/main_fragment"
android:layout_width="match_parent"
android:layout:height=match_parent">
<ListView android:id="#+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="20dp"
android:descendantFocusability="blocksDescendants"/>
</FrameLayout>