clarification on static vs dynamic fragment - android

Good day, trying to clarify this: if i have this layout for a portrait layout
main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<fragment
android:id="#+id/configFragment_id"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.example.settingsFragment">
</fragment>
and this for landscape(mainly for tablets), main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<fragment
android:id="#+id/configFragment_id"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.example.SettingsFragment" ></fragment>
<fragment
android:id="#+id/detailFragment_id"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.Example.DetailFragment" >
<!-- Preview: layout=#layout/details -->
</fragment>
</LinearLayout>
now within my SettingFragment, i implement a button to go to the DetailFragment:
DetailFragment fragment = (DetailFragment)getActivity().getSupportFragmentManager().findFragmentById(R.id.detailFragment_id);
FragmentTransaction fragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
if (fragment != null && fragment.isInLayout()) {
DetailFragment detailfragment = new WallpaperFragment();
fragmentTransaction.add(R.id.detailFragment_id, detailfragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}else{
Intent intent = new Intent(getActivity().getApplicationContext(),DetailActivity.class);
startActivity(intent);
}
Am i now implementing a dynamic fragment or am i still using static fragment?.. or do i only use dynamic fragment when i use a viewgroup like FrameLayout in place of the fragment tag element?
Idea is to have a single pane for phones and multi-pane for tablets.I know its a bad idea to mix static and dynamic fragments, but its kind of confusing. Thank you.

You know, I might be wrong here (so feel free to correct me) but it looks like you're using both static AND dynamic fragments. In your XML layouts you've added the fragments then you are re-instancing them via a fragment transaction in your activity. Alternatively, if you had declared a container (FrameLayout for instance) instead of a fragment in your XML you would have to use a FragmentTransaction to add the fragment at run time.
In your example you are just stepping on the fragment that you all ready have. Basically, the OS sees your fragment in the XML when inflating (I think that's when it calls the fragment code?) and executes the code associated with it via the tag in the fragment. Your app then adds that same fragment over the top of itself. A simple way to show this is to add a LogCat call in your Fragment class's onCreateView method. If you see it more than once, then your stepping on the previous fragment with the same fragment (which I'm 99% sure you are). Hope this helps to answer your question!

Static fragments are defined in the layout and are not generally added or removed at runtime. They are referenced by their id in your code. They are generally put as a child element of a layout like below. Once they are defined here, android will know to make a fragment, that's all you have to do.
<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:orientation="vertical"
android:weightSum="1">
<fragment
android:id="#+id/fooFragment"
android:name="com.example.myapplication.TestFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Dynamic fragments are defined in your code and can be manipulated, added, removed, etc during runtime. They look like this:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.your_placeholder, new TestFragment());
ft.commit();

Related

Change content_main XML in Basic Navigation Drawer Template

i am really new to android studio and struggle with a very basic problem.
I have seen a few threads regarding that issue but none really tacles my problem exactly.
Problem:
How am i able to change a fragment in the NavigationDrawer template? The template provides a environment in which the so-called content_main.xml should be changed to another fragment. I do not know how to accomblish that
What I tried: Since I was not able to change the content_main.xml I changed the whole xml, which includes the content_main.xml. It is easier understandble if you just have a short look at my code.
Template app_bar_main.xml that sets up how the fragments are suppose to look and includes content_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
android:id="#+id/content_main_frame"
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:layout_height="match_parent"
tools:context=".MainActivity"
tools:showIn="#layout/app_bar_main"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</FrameLayout>
In the Navigation Drawer main_activity I change my fragment like this:
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
Fragment newFragment;
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (id == ..) {
} else if (id == R.id.nav_emergencies) {
transaction.replace(R.id.content_main_frame, new Drawer_Emergencies());
transaction.addToBackStack(null);
transaction.commit();
}}
As you might see the transaction replaces the whole app_bar_main but i think i should just change the content_main.xml that is included in app_bar_main.xml. How do I accomblish that?
As I implemented the suggestion from Jude I got a updated result. The Fragment is at the right place, but somehow the content_main_frame.xml (hello world) is still shown.
maybe you should try to make a framelayout inside your content_main xml file.
then load the new fragment into the framelayout.this is like creating a frame for the new fragment.
then load it like:
transaction.add(R.id.yourframelayoutid, new Drawer_Emergencies()).commit();
From a Discussion with Mike.M I was able to solve my problem, whereas he provided the way. To make this thread closable I want to post the solution in here, citing Mike.M :
If you want to replace some Views with a FragmentTransaction, those Views should be in their own Fragment, one that you could load at startup, in the Activity's onCreate(). Your subsequent replace() transactions will then work as expected, provided that you're passing the same R.id for all of them; i.e., provided that you're swapping them out of the same ViewGroup. (Btw, please put # in front of my username when you'd like to ping me. When there's more than one other user in comments, we don't get notified unless you address it directly to a user.)
Which yields the following step-by-step solution:
I have to make empty Framelayout, e.g. make my content_main.xml empty.
Make a seperate Fragment for the inital content and load that in content_main.xml at the start..
After opening a new drawer I the fragment container, which is my Framelayout with a new fragment..
You can do something like this:
content_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:id="#+id/content_frame">
</FrameLayout>
and then
transaction.replace(R.id.content_frame, new Drawer_Emergencies());

How Would I Add A View/Fragment that Runs Another Activity?

I am interested in creating some kind of View or Fragment that takes up a small amount (~33%) of the current View. This overlayed View will use the camera as input. I think this is analogous to the YouTube app's small video playing in the corner.
I have a crude sketch of what I want (below). I don't need a full writeup, just a starting point.
Not sure it is the good way for it, but you can try with a FrameLayout to host a Fragment and make the FrameLayout with a background transparent (if you don't know what is FrameLayout, in few words it serves to overlap views. I writed an answer on this). The layout of your Parent Activity (FragmentActivity) may be something like this:
<FrameLayout
android:id="#+id/FragmentContainer"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:background="#android:color/transparent" >
<TextView
android:layout_width="match_parent" android:layout_height="match_parent"
android:text="I'm a text of the content" />
</FrameLayout>
And the Fragment may be as below:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent" >
<LinearLayout
android:layout_width="match_parent" android:layout_height="250dip"
android:background="#color/blue"
android:layout_alignParentTop="true" >
<TextView
android:id="#+id/ReaderEdit"
android:layout_width="match_parent" android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="I'm a text in a fragment" >
</LinearLayout>
</RelativeLayout>
And then when you initialise your Fragment in the FrameLayout, you set hide() and show() methods for display it. For this, use FragmentSupportManager in your FragmentActivity and add() or replace() methods like the example below:
// Initialize your fragment:
FragmentTransaction mTransaction = this.getSupportFragmentManager().beginTransaction();
Fragment mFrag = new MyFragment(); // call your Fragment Class
mTransaction.add(R.id.FragmentContainer, mFrag, null).hide(mFrag).commit(); // add to the Container (FrameLayout) and hide it
// don't forget to commit at the end of every FragmentTransaction
// To display your fragment:
FragmentTransaction mTranDisplay = this.getSupportFragmentManager().beginTransaction();
mTranDisplay.show(mFrag).addToBackStack(null).commit(); // pass the Fragment to show + add the BackStack method (when the user press back button, the Fragment disappears without quit the Activity)
mTranDisplay.setCustomAnimations(R.anim.slide_in, 0, 0, R.anim.slide_out); // you can make an animation to the BackStack method, here it's a slide in/out from top to bottom
I think there is a proper way to do this. Maybe you can check this library and see, break, rebuild,... the code.
Hope this helps.

How can I declare a Fragment as hidden in an XML layout

My activity declares all of its GUI fragments in a single XML layout. It only needs to display a few of the fragments at launch time; the rest get shown as the user interacts with the app. A portion of the layout is as follows:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
android:id="#+id/map_panel"
android:name="com.example.MapPanel"
android:layout_width="match_parent"
android:layout_height="#dimen/map_panel_height" />
<fragment
android:id="#+id/list_panel"
android:name="com.example.ListPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/map_panel" />
<fragment
android:id="#+id/detail_panel"
android:name="com.example.DetailPanel"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/map_panel"
android:visibility="gone" />
My intention is that the list_panel fragment is visible at startup, and the detail_panel fragment is hidden until the user selects something from the list.
By default, a fragment starts out with the isHidden attribute as false. That means my activity has to iterate through the loaded fragments and manually call isHidden(true) on fragments like detail_panel at startup time.
I would prefer to declare the isHidden status in the XML layout. However, setting android:visibility="gone" in a <fragment> declaration does not change the isHidden status, and I can't find any documentation on another attribute that would do the trick.
Is it possible to set an XML attribute on a <fragment> to cause it to be hidden?
Note: I'm not concerned with view visibility, I'm concerned with the fragment.isHidden() value. That affects how FragmentManager manipulates the back stack and performs animations. If you call transaction.show(fragment) on a fragment whose view is invisible or gone, but the fragment.isHidden() value is false, then the FragmentManager will not make the view visible. See http://developer.android.com/reference/android/app/Fragment.html#isHidden() for reference.
I faced a similar situation, where I had to hide a fragment.
I simply included the fragment inside a LinearLayout and marked the layout to be visible/gone.
<LinearLayout
android:id="#+id/map_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible" >
<fragment
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.MapFragment" />
</LinearLayout>
Based off Jyo's post, use this:
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.hide(mFragment);
fragmentTransaction.commit();
This has worked for me on API Level 23. mFragment is the fragment that you want to hide.
This answer is a tad late thought it may be helpful for future reference. Visibility is part of the View class - Fragment extends object though not having access to the visibility values. A possibility is making the Fragment a child of a FrameLayout and calling invisible or gone on the layout. This will cause the fragment to appear to be hidden.
Hope it helps!
public void showHideFrgament(final Fragment fragment){
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.setCustomAnimations(android.R.animator.fade_in,
android.R.animator.fade_out);
if (fragment.isHidden()) {
ft.show(fragment);
Log.d("hidden","Show");
} else {
ft.hide(fragment);
Log.d("Shown","Hide");
}
ft.commit();
}
we have isVisible Method for fragment
seeting visibilty to Gone does not take any space
Where as Invisble takes the actual view space.

How to center a dialog within a fragment?

In a scenario where I've got multiple fragments on display (e.g. list fragment and detail fragment), and one of the fragments is showing an alert dialog (a DialogFrament), I'd like the dialog to be centered within the fragment that is showing it, not centered within the whole screen. Is there a way to do that without a whole lot of pixel calculations involving the dimensions of the screen, the dimensions and position of the fragment, etc.?
You can do this by using a FrameLayout, as Joe Simpson mentions. Say you want to put your dialog fragment over the top of the Details fragment that you mention. Put a FrameLayout around the details fragment in your activity layout, then embed the dialog fragment within the FrameLayout too (with layout_gravity="center"). Set the visibility="gone" until you need it. E.g.:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
android:id="#+id/my_details_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.my.fragment.DetailsFragment" />
<fragment
android:id="#+id/my_dialog_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.my.fragment.DialogFragment"
android:layout_gravity="center" />
</FrameLayout>
You can also start it programmatically. Put a holder view (e.g. a LinearLayout) in the xml:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
android:id="#+id/my_details_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.my.fragment.DetailsFragment" />
<LinearLayout
android:id="#+id/myfragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</FrameLayout>
... and then replace it in code like so:
final MyDialogFragment dialog = MyDialogFragment.getInstance();
// get an instance of FragmentTransaction from your Activity
FragmentTransaction fragmentTransaction = getSupportFragmentManager()
.beginTransaction();
fragmentTransaction.add(R.id.myfragment, dialog);
fragmentTransaction.commit();
Note that the docs on DialogFragment say it's fine to embed it like this: "A DialogFragment can still optionally be used as a normal fragment, if desired. This is useful if you have a fragment that in some cases should be shown as a dialog and others embedded in a larger UI."

Android Fragment Not Replacing Properly

I am trying to build an app for 3.0 using fragments. On the left side of the application there is a static fragment, and on the right side there is a dynamic one. Each of my fragments in the dynamic portion have a title. Whenever I go to replace the initial fragment, The title of the first is still shown above the title of the first. Successive replacements replace the lower portion but the initial title is still shown (sorry I cannot post images yet).
Best I can do for image:
Initial Header
New Header
Content(displays fine)
main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<fragment
android:id="#+id/static_fragment"
android:name="ruleout.android.History_Fragment"
android:layout_width="500dp"
android:layout_height="match_parent" />
<fragment
android:id="#+id/dynamic_fragment"
android:name="ruleout.android.New_Screen_Fragment"
android:layout_width="fill_parent"
android:layout_height="match_parent" />
</LinearLayout>
Partial MainActivity used to change fragments
private void open(Fragment toShow)
{
FragmentTransaction fragmentTransaction = FragMag.beginTransaction();
fragmentTransaction.replace(R.id.dynamic_fragment, toShow);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
Please let me know if you need any additional information and thanks in advance for your help.
If you want to dynamically change fragments, you can't declare them in your layout. The Fragment documentation has an example of doing just what I think you are describing, where a layout has a static fragment declared in it along with a FrameLayout for holding a Fragment that will be dynamically added and replaced.

Categories

Resources