Here is the image screenshot:
My query is how can I implement the Stack layout shown? I have scoured the resource files and most only show how to implement two fragments.
Would anyone please give me any example of how I can create the Stack fragment as shown?
Will appreciate it. Thanks.
If your fragments are closely tied together, just don't run them in separate activities. For the single pane case you can just switch fragments within one activity.
Otherwise, if you do want to separate them between activities, you need to use the onActivityResult() model for propagating results back, and in the dual-pane case "emulate" it by just having the second call onActivityResult() of the first fragment. Note that Fragment.setTargetFragment() includes a request code argument to facilitate this.
I have activity A loading Fragment F1 which loads fragment F2
IMHO, fragments should not load other fragments. Activities load fragments, based upon available screen space. Fragments should neither know nor care whether any other fragment exists in the current activity, or if other fragments are in other activities.
I have F2 calling back to activity A to pop it off of the stack. Should I then be looking at passing a message to F1 to do what it needs to do?
Yes.
What I'm wondering is whether I'm on the right track with regards passing messages back and forwards via the parent activity or is there a more direct way of F1 responding to F2 performing something that requires it to be closed and F1 do what it needs to do.
I would not have F1 even know that F2 exists, or vice versa. When the user does something in F1 that should result in a major context shift (e.g., display some other fragment/activity), F1 should let the hosting activity know, perhaps via a listener interface registered with F1 (to support multiple possible hosting activities). The activity would then arrange for F2 to appear, either in its own activity or in another activity. Similarly, when F2 wraps up, it would let its hosting activity know via a listener interface, and that activity can route control back to the appropriate spot.
I am somewhat skeptical of your whole "F2 performs an action which should result in it being closed" approach, unless F2 is a DialogFragment.
One possible solution is given below
Please tweak width and heights according to the use case
For Landscape use
<LinearLayout android:orientation="horizontal" ..>
<fragment android:name="com.example.FragmentA"
android:id="#+id/fa"
android:layout_width="xdp"
android:layout_height="match_parent" />
<LinearLayout android:orientation="vertical" ...>
<fragment android:name="com.example.FragmentB"
android:id="#+id/fb"
android:layout_width="ydp"
android:layout_height="wrap_content" />
<fragment android:name="com.example.FragmentC"
android:id="#+id/fc"
android:layout_width="zdp"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
For Portrait view use
<LinearLayout android:orientation="vertical" ..>
<fragment android:name="com.example.FragmentA"
android:id="#+id/fa"
android:layout_width="match_parent"
android:layout_height="Xdp" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<fragment android:name="com.example.FragmentB"
android:id="#+id/fb"
android:layout_width="ydp"
android:layout_height="wrap_content" />
<fragment android:name="com.example.FragmentC"
android:id="#+id/fc"
android:layout_width="wrap_cotent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
Related
I have an application with a main menu that when clicked, navigate to different activities.
One of these activities its a Search, with container that i update with many fragments. Its a kind of search, with 3 steps. (Step 1, Step 2, Step 3)
When i go for other activity and back to the Search Activity, the state is lost.
Whats is the best way to restore the activity with the right fragment ?
I have tried android:launchMode="singleInstance" and also intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT or Intent.FLAG_ACTIVITY_CLEAR_TOP) to force one instance of activity, and actually works but is taking time to open the activity for the first time (the app kind of stop works and then start again)
I think i can't just use savedInstanceState() because, each fragment need some information chosen on the previous fragment
Any suggestion ?
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android">
<!--Top bar Menu-->
<include layout="#layout/partials_top_bar"/>
<FrameLayout
android:windowSoftInputMode="adjustNothing"
android:id="#+id/container"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</FrameLayout>
<!--Bottom Bar Menu-->
<include layout="#layout/partials_bottom_bar"/>
</LinearLayout>
When the user choose some action, them i update the actual fragment with
activity.supportFragmentManager
.beginTransaction()
.replace(R.id.container, fragment)
.addToBackStack(null)
.commit()
EDIT: Found a solution. The "delay" / App freeze showed when i open SingleInstance was caused by removing the transition animation of all activities. But only the single instance activity presents this delay. So i'm gonna use this. Thank you so much guys.
You can create a static variable "state" in your activity, could be String, and when you change Fragment, you change de variable value, for example, when you change to the StepOneFragment you put the value to
"step_one", StepTwoFragment -> "step_two", StepThreeFragment -> "step_three", and if you get back you change the variable value depending in what fragment are you on, then in onCreate of SearchActivity, you make a switch in that variable, and depending of the value, you load the desired Fragment.
Hope it helps
On Android 3.0 and above, the android team is driving hard that you should use fragments over activities. And I see this being useful, but I want to be able to handle click events in my app. I'm using a list fragment on the right side of my app, so doing an onclick (or any click listeners) happens in the activity that hosts the fragment. So I had to move from putting a item in XML to using the fragment manager.
In the design documents they show this picture:
http://developer.android.com/training/basics/fragments/fragment-ui.html
What I want is the Fragment A/B tablet UI. However, nowhere in this page does it actually give you an example of doing this - it seems that fragment manager only works with ONE fragment at a time - which is entirely opposite of what the picture portrays. Which makes me think it uses in XML... but then how would I get an onclick? These documents don't make a lot of sense to me. It shows one thing and then says something else. What if I wanted to remove fragment A on the tablet? Add fragment C that doesn't yet exist? Is that even possible if you tried to use Fragment Manager????
I guess I don't get if Fragment manager uses more than 1 fragment, and if it does, how am I supposed to use this to get an item in the picture like the tablet - the left (A) being a listview, and the right (B) being whatever. Without an ID of the fragment I don't how to access it.
Not sure if this is relevant but here is some of my code:
Adds a fragment to the single framelayout I made like in the guide
//Activity
FragLaunch launchPane = new FragLaunch();
// In case this activity was started with special instructions from an Intent,
// pass the Intent's extras to the fragment as arguments
// firstFragment.setArguments(getIntent().getExtras());
// Add the fragment to the 'fragment_container' FrameLayout
getFragmentManager().beginTransaction()
.add(R.id.launch_frag_container, launchPane).commit();
}
Also, in portrait mode of 7" tablets, I want it to use a viewpager that is swipeable. It worked like a charm when I designed it in XML but now that I have to access the listfragment it doesn't work (no way to access since I can't have two fragments)
XML of FragLaunch's content view:
<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:paddingLeft="16dp"
android:paddingRight="16dp"
android:gravity="center_vertical"
android:orientation="vertical" >
<TextView
android:id="#+id/initial_directions"
style="#style/textScalar.Roboto.Light"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="#string/initial_directions"
android:layout_marginBottom="30dp"
tools:context=".Launch" />
</LinearLayout>
I want to have this one appear as Fragment A in the photo:
FragHistory.java/xml for fragment:
<?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" >
<Button
android:id="#+id/spamhistory"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Spam History" />
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:drawSelectorOnTop="false" />
</LinearLayout>
Does anyone have any insight on this?
If you want your fragments to be able to communicate then you need to use interfaces, like this.
For onClick events you simply set an onClickListener for the view that you need to receive the onClick event from. Like so:
sampleView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Your code here
}
});
As for fragment transactions, it says somewhere in there (I can't remember exactly where) that when two fragments are displayed on the screen at once (as with larger screens) that instead of swapping the fragments it simply updates it. All you have to worry about is making the correct calls. So if you want to remove fragment A just call remove(). Or if you want to replace it with fragment C call replace() and pass fragment C in as the parameter.
Can you clarify your question about the ViewPager? What do you mean "have to access it"?
Hope this helps!
EDIT: I apoplogize, I misunderstood your question. Here's kind of a quick run down of how to add more than one fragment to the screen at once.
1. Perform a runtime check to make sure that the device screen is big enough to display more than one fragment.
2. If the screen is big enough, set the content view to use a layout that has a FrameLayout for each fragment that you want to add.
3. After that grab a reference to each fragment that you want to use.
4. Then use the FragmentManager to add a fragment to each layout. Like this:
FirstExampleFragment fragment1 = new FirstExampleFragment();
SecondExampleFragment fragment2 = new SecondExampleFragment();
getSupportFragmentManager().beginTransaction().add(R.id.example_framelayout1, fragment1)
.add(R.id.example_framelayout2, fragment2).commit();
Another great way to allow communication between fragments is to use an event bus, such as the Otto event bus. Otto allows components to publish events and subscribe to events in a decoupled manner.
In your particular case, when a user selects an item in the list, your list fragment can publish an event (which can include the item that has been selected) and your content fragment can subscribe for these events and update its content accordingly when it receives a new event. This all being done without the two fragments being directly coupled and without having to define additional interfaces.
I know this doesn't answer your entire question, but thought it might be useful when it comes to the communications between your fragments....YMMV.
I am developing an applications that is aimed at Tablets and Google TVs. It will be like many standard Google TV applications with a LeftNavBar and a top Search bar that is common to all application screens. It will look something like the following image:
Main Screen
The RED area will be different for all other screens. It may contain data like following screens mockups:
Activity One loaded into main container
Activity Two loaded into main container
So you can see that completely different sections can be loaded in the main area.
Screen 3 can be loaded as a detailed section when selecting any list item in Screen 2 (say in fragment list) OR it can be loaded as a result of selecting a tab (which will appear in LeftNavBar).
Here is how I am trying to implement it.
Step 1. I Created a main Activity with the following 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" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#9ccc" >
<!-- Top Bar -->
</LinearLayout>
<FrameLayout
android:id="#+id/mainContainer"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<!-- main Red Container that will load other Activities -->
</FrameLayout>
</LinearLayout>
mainContainer is the RED container where I want to load the Activities. LeftNavBar will be added to this Activity as its the parent of All.
Step 2 I created ActivityOne & ActivityTwo with two & three Fragments in them respectively (as shown in above second & third image).
*Step 3 I am trying to load the ActivityOne in main page's mainContainer FrameLayout... But I cannot add it.
I tried by adding the ActivityOne to mainContainer as follows:
View v = (new ActivityOne()).getWindow().getDecorView();
FrameLayout mainContainer = (FrameLayout) findViewById(R.id.mainContainer);
mainContainer.addView(v);
but the getWindow() returns null....
Other issue occurs because all the data comes from a remote services .. so please also suggest how would I be able to hold references to all the loaded Activities in mainContainer in a some kind of stack ... so I can just reload the already loaded activity instead of creating its new instance.. This will be used on BACK button press.
OR
Instead of loading an activity into the above RED container, I should create two Activities each with their own Fragments & a LeftNavBar. This might be easier than the aforementioned approach. or this might be the only solution.... however I feel that saving state for BACK buttons might get messy .. but I will try implementing this
What would you do if you had to create this type of application?
How would you design the UI layout for best performance/practice?
Your suggestions in helping me setting this app's layout are much appreciated.
Disclaimer
This is where fragments can get tricky. The problem would be simple if Activity 1 & 2 had identical layouts so that you could simply attach/detach fragments and use the fragment back stack to unwind.
Because you want 2 unique layouts to house your fragments, things are going to be a little more involved. If at all possible I would try to use the same layout so that you can take the easy path.
As another option, you could use two activities as you outline above and send data back and forth with Intents.
That said, if I really had to implement this solution as written, here is what I would do. Note that I am not advocating this solution but myself do not know of a better way of doing things.
The Solution
Create a FragmentActivity whose view would be Main Screen as you've defined above. The layout for the Main Screen would contain:
Left nav bar
Top bar
2 layouts. layout1 and layout2. These would be contained in a parent layout i.e. RelativeLayout or LinearLayout and would contain the necessary FrameLayout elements for your fragments.
Example using your XML (note, tags are a bit brief):
<?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" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#9ccc" >
<!-- Top Bar -->
</LinearLayout>
<LinearLayout android:id="#+id/layout1">
<FrameLayout android:id="#+id/listFragment" />
<FrameLayout android:id="#+id/contentFragment" />
</LinearLayout>
<LinearLayout android:id="#+id/layout2">
<FrameLayout android:id="#+id/imageFragment" />
<FrameLayout android:id="#+id/boxFragment1" />
<FrameLayout android:id="#+id/boxFragment2" />
<FrameLayout android:id="#+id/boxFragment3" />
</LinearLayout>
</LinearLayout>
The main idea is that you then show/hide layout1 & layout2 i.e. set android:visibility="gone" based on the state of your app.
The disadvantages of this method are:
Using fragment backstack may be impossible, instead you'll have to track where the user is in your UI flow and manage the back button to show/hide layout
You may need to take special care to attach/detach fragments when you show/hide their parent view to reduce resource consumption while the fragments are invisible
The advantages are:
Easy communication between fragments and the base activity since only 1 activity is used
Re: The nested Fragments problem
To get around the 'nested Fragments' problem in our application where (as you correctly note) Fragments cannot add Fragments I hosted a single templating Fragment under the activity whose only purpose was to define a set of place holders for other fragments to anchor to. When adding further Fragments to the activity past this point I used the templating Fragment's view place holder +#ids to identify the "root" or parent view Id for the Fragment being added.
getSupportFragmentManager().beginTransaction().add(#someIdFromTheTemplateFrag, fragment, fragmentTag).commit();
The Fragment I was adding then knew where to anchor itself in the current layout and of course then went about it's merry way of add it's view. This had the effect of attaching a Fragment to another Fragment hence achieving the desired visual 'nesting'...
I read some questions like it, but I dont understand well what should I do in my hiearchy?
I have
<fragment
android:id="#+id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
class="com.****.****.ui.TabsFragment" />
for tab menu on bottom of screen
and
<FrameLayout
android:id="#+id/details"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="#+id/tickerLL"
android:layout_below="#id/header"
android:background="#drawable/background" />
for other will created fragments.
I have 9 tab menus, everyone is a fragment.
Some fragments's landscape are another activity. And I rotate back phone, fragments are working well. But if I rotate fast after and after, My fragment Activty, TabsFragment and and other created fragments are recreated and my fragments are overlapping.
I manage my fragments in TabsFragment. And they works dynamicly, my abstract fragment class, has a previous fragment and subfragment. When I press back, previous fragment closes its subfragment and null it.
What should I do?
During a configuration change, Android restores or recreates all fragments that the old activity had when setting up the new activity. Hence, you need to take that into account when working with the new activity instance -- do not assume that you are starting with a clean slate.
I'm trying to embed the fragments API to an application but I can't control the order of fragments being loaded and thus getting some exceptions.
I configure my layout this way:
<fragment class="org.me.myListFragment"
android:id="#+id/frag_title"
android:layout_marginTop="20dp"
android:layout_width="#dimen/titles_size"
android:layout_height="match_parent"
android:layout_weight="1"
/>
<fragment class="org.me.DetailsFragment"
android:id="#+id/details"
android:layout_marginTop="20dp"
android:layout_width="#dimen/titles_size"
android:layout_height="match_parent" android:layout_weight="1"
/>
</FrameLayout>
But the DetailsFragment is being loaded before the list fragment and this causes trubles.
I don't want to break the old code, controlling the order here would be the quickest way to fix it.
Is there a way I can make the second fragment to be initialized only after the first one?
No, you cannot control the order if you use <fragment> elements. If you switch to dynamic fragments (e.g., FragmentTransaction), you control when fragments are created, because you create them.
IMHO, one fragment should not depend upon another fragment in the manner that you describe.