Replace fragment in tab - android

I am trying to implement an Action Bar with Tabs navigation set using ActionBarSherlock. I currently have three tabs which I can switch between ok. On one of my tabs I am implementing a ListView. When one of the items in the list is selected I want to replace the list with another fragment which will be a detail view of the selection.
When I call the FragmentTransaction.replace method with the new detail fragment I can see the new fragment appear but it overlaps the ListView, meaning I can see both fragments. Is this kind of navigation possible using the ActionBar tabs navigation, or am I on completely the wrong lines. I feel I am missing something really fundamental here.
I have a SherlockFragmentActivity which is implementing a TabListener to handle moving between tabs. The fragment hosting the ListView inherits from SherlockListFragment and I have attached a OnItemClickListener to respond to the tap and to replace the fragment. I am using this code
numbersList.setOnItemClickListener(new ListView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> a, View v, int i, long l) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(android.R.id.content, new NumberSelectedNavigationMenuFragment());
ft.commit();
}
});
The fragment which is replacing the ListView is currently just a basic LinearLayout with a TextView.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Test"
android:id="#+id/textView"/>
</LinearLayout>
Any help appreciated with this as I am well and truly stuck ...

Related

How to replace parent fragment view with a child fragment's view?

I'm looking for some help in Android studio with replacing a parent fragment's view with the view of a child fragment when a view in the parent fragment is clicked. Thank you in advance for your help.
Right now I have a parent fragment which is a chat list, and a child fragment (the chat screen) that shows up when you click on an element of the chat screen (i.e. a button). The chat list looks like this:
<FrameLayout 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"
tools:context="com.example.myapplication.ChatListFragment">
<!-- Empty Container for Fragment to Live in -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ListView
android:id="#+id/chatListView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/moonstone">
</ListView>
</FrameLayout>
I have set the onClickListener for the chatListView as follows:
_chatListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
String chatName = _chatListAdapter.getItem(i).getChatTitle();
openChatScreen(chatName);
}
});
And the openChatScreenWindow() looks like this:
private void openChatScreen(String chatName)
{
_fragmentManager = getChildFragmentManager();
Log.i(CHAT_LIST_TAG, "starting chat screen fragment");
FragmentTransaction fragmentTransaction = _fragmentManager.beginTransaction();
ChatScreenFragment chatScreenFragment = ChatScreenFragment.newInstance(chatName);
fragmentTransaction.add(R.id.fragment_container, chatScreenFragment);
fragmentTransaction.addToBackStack(GlobalConstants.OPEN_CHAT_WINDOW_FRAGMENT_STRING + chatName);
fragmentTransaction.commit();
}
However, when I run this code, the child fragment is obscured, because both the frame layout (the view that the fragment is displayed in) and the chatListView have their widths and heights set to match_parent (I figured this out by testing the height and width of the chat list as 200dp, and I was able to see the child fragment behind it).
Is there a simple way to get the fragment to replace the chatListView whenever it is loaded?
For example, is there a way to change this view:
To this one:
... when an element in the chat list (the first one) is clicked?
I was thinking of changing the list view's visibility to invisible and visible based on whether the fragment is loaded, but that seems like a headache.
Please let me know what you think, thank you!
First off most modern way of managing fragments is - Navigation component
According your approach - you are adding child fragment on top of the prev fragment with fragmentTransaction.add, you can use fragmentTransaction.replace instead
Also, you might want to set child fragment background to solid color - to hide previous fragment, if you use this method - make child's fragment root clickable - to prevent fragments click through.
My recommendation - spend more time on learning Navigation component

Fragment only works correctly when going back to previous page

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

How to add static Fragments in Android activity

Trying to create Facebook / Gmail style Sliding Navigation Drawer. All I want is to create separate Fragments in XML, and show them when user clicks one of the list items from Drawer Menu. Each Fragment hooked up to one item in the list.
NavigationDrawer is great example app to start with, but it only demos loading fragment dynamically. I want even simpler, just loading those statically. How should (Code snippet please) I be instantiating Fragments within my activity on List menu item click? How would MainActivity XML look like ?
Please read the docs http://developer.android.com/guide/components/fragments.html
XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="+#id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
Java
FragmentManager fragmentManager = getFragmentManager()
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();

Replace ViewPager by another fragment

My main activity is a Swipe View with tabs in the action bar, which can be used to change to a particular fragment directly. I basically followed the developer guidelines on this. So far this works fine and as expected.
However, I now have a couple of items in the menu (Settings, About), which should not be displayed as part of the ViewPager, but rather should replace the ViewPager completely and set the "navigation up" affordance in the action bar. Following along with the answers to this question I know how to use the BackStack to manipulate the action bar and to show the "navigation up" affordance.
However I'm not sure what the best way to replace the ViewPager would be. As far as I know I can either try to disable all ViewPager functionality and make it appear as it would be a single fragment (e.g. disable tabs and swipe), or I could use nested fragments. Yet, I'm not convinced that either of this options is "clean".
Maybe I'm overlooking something here and there is a more intuitive way to achieve the same? What are you guys thinking about this and how do you implement something "basic" as this?
P.S.: Obviously I could use activities for this, but I think that an Activity is too heavy for a simple "About" text and in my understanding one should try to use Fragments wherever possible these days.
As I can understand, you could put the ViewPager inside a parent as FrameLayout and add() the "about" fragment with addToBackState() method above the ViewPager.
You will avoid to disable or refresh the ViewPager. Just add above it a new fragment.
UPDATE
I'm able to achieve it with add() method and a custom background on the added fragment to avoid the overlap issues. And finally make this background clickable to prevent the click events for the behind ViewPager.
See my activity layout:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.example.viewpageroverlap.MainActivity"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
My Menu item event:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, OverlapFragment.newInstance(990), null).addToBackStack(null).commit();
return true;
}
return super.onOptionsItemSelected(item);
}
My Overlap Fragment layout:
<RelativeLayout 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"
tools:context="com.example.viewpageroverlap.MainActivity$OverlapFragment"
android:background="#FF0000"
android:clickable="true" >
<TextView
android:id="#+id/section_label"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center" />
</RelativeLayout>
This gives me this output:
Note: I used a red background but you can try with Android Resources Color and avoid to use a color declared in your files as android:background="#android:color/white".
WITH TABS
You can do the same as above and reset the navigation with NAVIGATION_MODE_STANDARD:
if (id == R.id.action_settings) {
getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
getSupportFragmentManager().beginTransaction()
.add(R.id.container, OverlapFragment.newInstance(990), null).addToBackStack(null).commit();
return true;
}
Then, when the user come back to the ViewPager (when he presses the home button or hardware back button), reset the old navigation as:
// do the same with android.R.id.home inside onOptionsItemSelected
#Override
public void onBackPressed() {
// check if the "about" fragment is still displayed
if(this.getSupportFragmentManager().getBackStackEntryCount() > 0) {
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
this.getSupportFragmentManager().popBackStack();
}
}
Just have the ViewPager in its own fragment and replace that when you want to change to another fragment using regular fragment transactions.
If you turn on addToBackStack those transactions will react to the back button in a natrual way.

Fragment Layout List <--> Details

I want to implement a layout that has the following design:
Landscape:
List of items on the left, details on the right
Portrait:
List of items, only details after click
To get this working I followed those tutorials:
Tutorial 1
Tutorial 2
It worked as expected.
But instead of starting a new activity when in portrait and clicking a Listitem,
I want the fragment to be replaced by the detail, so that I can animate the transition.
So i played around and got problems with the views. After that I read the following article, and modified my layout to use placeholders an add the fragments programmatically:
Article
The action that is triggered when the listitem is clicked just replaces the list fragment in his container with the detail fragment.
But now if I revert to landscape, the list part of the layout is showing the detail instead of the list, because i replaced the content.
Is there any way to solve this problem?
At the moment I managed to get this working by using the two fragment placeholders in both layouts, landscape and portrait, with wrap content, and hiding and showing the fragments, but I don't know if this is the right approach? Perhaps a ViewFlipper would be better?
Also the animation here does not work properly, cause I hide and show in the same transaction.
Also if I am in Landscape mode and click a listitem and data is showing, and I return to portrait, I want the data view to be shown, not the list, but ONLY if data is already shown.
Atm I managed this with an flag passed to the intent data and again show/hide the correct view.
Any alternative ideas?
Thank you very much, have been trying for hours now!
EDIT
The main problem I have is, that the slide in/out animation I set is not played correctly, as i hide and show the fragments in one transaction. It just hides the one fragment and slides in the other, so the first fragment is not slided out :/
To see what I mean, here is how I implemented it in a fragment test app:
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">
<FrameLayout
android:id="#+id/details_Fragment_Placeholder"
android:layout_width="wrap_content"
android:layout_height="fill_parent" >
</FrameLayout>
<FrameLayout
android:id="#+id/main_Fragment_Placeholder"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</FrameLayout>
</LinearLayout>
The ListFragment onListItemClick:
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
FragmentManager fragmentManager = getFragmentManager();
Screen2Fragment fragment2 = (Screen2Fragment) fragmentManager
.findFragmentByTag(Screen2Fragment.TAG);
if (fragment != null) {
if ((getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT)) {
.beginTransaction();
transaction.setCustomAnimations(R.anim.slide_in_right,
R.anim.slide_out_left, android.R.anim.slide_in_left,
android.R.anim.slide_out_right);
Screen1ListFragment fragment1 = (Screen1ListFragment) fragmentManager
.findFragmentByTag(Screen1ListFragment.TAG);
transaction.hide(fragment1);
transaction.show(fragment2);
transaction.addToBackStack("ReturnToScreen1");
transaction.commit();
}
}
}
When you place the list fragment initially you need to put it into the back stack, then override the back button in the detail fragment to pop the list view off the back stack when pressed.

Categories

Resources