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

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.

Related

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.

Android fragments overlap previous view and button listeners

I have an activity A with a fragment A inside.
Activity A uses layout X, and fragment A uses layout A.
code of layout X:
<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=".MainActivity" >
<fragment
android:id="#+id/fragment1"
android:name="android.app.DialogFragment"
android:layout_width="wrap_content"
android:layout_height="500dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="113dp"
class="com.example.fragtester.FragA" />
</RelativeLayout>
Layout A is just textview + linearlayout.
I set up another fragment B that uses layout B.
Now that I use the following code in activity A to change the fragments:
Fragment f = new FragB();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.fragment1, f);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
I end up having layout B displaying under layout A.
So I use a FrameLayout to wrap the fragment in layout X and use
ft.replace(R.id.FrameLayout1, f);
Now the view is working nicely. Though, another problem arises.
Although layout B covers layout A, but the buttons are still active.
That means when I am viewing layout B, I can still click buttons on layout A, even if I am not seeing it.
And even when I add fragment C/D/E..... (layouts C/D/E....), the buttons on layout A is still active.
Can anybody explain why is that? Am I using fragments wrongly? Thanks!
A way to get through is to make layout A blank, and use other layout to cover it. But it doesn't seems to be the "right" way??
Remove the fragment and add a FrameLayout
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff" >
</FrameLayout>
then add fragments programmatically.
In android fragment button click pass through the fragments (i dont know if the fragments are suppose to work like that). what I used to do in such a situation is to make the layout of the fragment clickable. so the clicks wont pass through.
Instead of having fragment in your xml, try to create empty container for a fragments. For example empty frame layout. And then programmatically put your fragments in there.
Add the following attribute to the XML root layout of the fragment that goes on top.
android:clickable="true"
This will ensure that touch events will not propagate further than the top layer.

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."

clarification on static vs dynamic fragment

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();

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