CustomAnimations on FragmentTransaction not working for the old fragment - android

My FragmentActivity displays one Fragment at the beginning and a second when I press a Button. Until here, it's easy. But I got one problem with the animations.
I add the second fragment with:
mTChild.add(R.id.container, mFragChild).addToBackStack(null).commit();
And to make it more "alive", I declare a CustomAnimations before adding the Fragment, it looks like this:
mTChild.setCustomAnimations(R.anim.slide_in, R.anim.alpha_out, R.anim.alpha_in, R.anim.slide_out);
mTChild.add(R.id.container, mFragChild).addToBackStack(null).commit();
I used this method setCustomAnimations(int,int,int,int) (parameters: enter, exit, popBack enter, popBack exit) as you can see on setCustomAnimations Documentation. Just to understand my (basic) animations xml:
slide_in > the new fragment slide from right to left.
slide_out > back stack = fragment slide from left to right.
alpha_out > the old fragment disappears with alpha 100 --> 0.
alpha_in > back stack = old fragment appears with alpha 0 --> 100.
At this step, I got what I want a slide in/slide out from right for the new fragment which takes place above the old fragment. But the effect for the old fragment which normally stays behind and disappears/appears with the alpha not happens.
What I am doing wrong? Because, the CustomAnimations happens but not for the old fragment (which it not removed).
Thanks for your answers.

I feel shame, I did a stupid mistake!
First of all:
Obviously I can't do this like I did, because the old fragment stays behind. So it can't make an out animation.
I answered at my own question when I asked it: "the old fragment (which it not removed)"... my god! So instead of:
mTChild.add(R.id.container, mFragChild).addToBackStack(null).commit();
I should do:
// REPLACE (remove+add) and not ADD only !
mTChild.replace(R.id.container, mFragChild).addToBackStack(null).commit();
If I want an out animation.
Nice effect:
I found an elegant way! Indeed, the goal was to keep the first Fragment visible, overlapping with a new Fragment (a ListView) and make the older less visible to 10% (for giving a shadow/under effect). I was wrong on the way to do this.
Inspired by SlidingMenu and this answer Generate an overlay slide in and move existing Fragment to left, I created a FrameLayout to add() (this time no doubt) the new Fragment which have a View to the left with a gradient background to make the shadow effect.
With this:
mTransaction.add(R.id.container, mChildA, null).hide(mChildA)
.add(R.id.container2, mFrag, null).commit();
And after, when I press my Button, I do as below:
mTChild.setCustomAnimations(R.anim.slide_in, 0, 0, R.anim.slide_out);
mTChild.show(mChildA).addToBackStack(null).commit();
In fact, I have the slide in and the reverse effect with the BackStack, and I overlay my content with a shadow on the left side. The xml of my Fragment it's now:
<RelativeLayout
android:layout_width="match_parent" android:layout_height="match_parent" >
<View
android:id="#+id/shadowLeft"
android:layout_width="50dip" android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:background="#drawable/fragment_shadow_left" />
<ListView
android:id="#+id/list"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_toRightOf="#id/shadowLeft" />
</RelativeLayout>
Finally, I make the FrameLayout to "host" this layout above, with a background transparent and it works perfectly.
If someone wants to edit or give a better answer, I'm always listening. Hope this will be useful for someone who searches the same effect.

Have you considered using the method called "replace" instead of "add" in order to change your fragments?

Related

Restore activity with the right fragment and state

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

Fitting second fragment to an activity

In my Activity I ad a fragment dynamically which occupies a dynamic porportion of the screen (you can slide it up or down to cover the entire screen or just the bottom ~250dp).
I now want to dynamically add another fragment to the same activity but I need this new fragment to fit next to the first one. Meaning you can slide the first one still up and down but the second will then either stay behind the first or move to make room.
Google tells me to use the same fragment manager and just add a fragment but the same fragment manager has already done a commit (with the adding of the first).
Is there any way to achieve this? Thank you!
CODE:
In my activity onCreate I added a fragment called buildingFragment (blue)
fragmentTransaction = getFragmentManager().beginTransaction().add(R.id.fragment_container, buildingFragment, "BUILDINGPAGE");
fragmentTransaction.hide(buildingFragment);
fragmentTransaction.commit();
The buildingFragment animates itself in onCreateView so that most of its content is out of screen (bottom direction):
// ANIMATE THE BUILDING PAGE TO PEAK FROM BOTTOM
ObjectAnimator anim = ObjectAnimator.ofFloat(buildingPageView, "y", USEABLE_HEIGHT, USEABLE_HEIGHT-TOOLBAR_HEIGHT-VIRT_NAV_BAR);
anim.setDuration(500);
anim.start();
Now this BuildingFragment works and it can be slided up or down.
With a push of a button I want to add another fargment (red) to the activity but I need it to take the rest of the space on the screen that the BuildingFragment (blue) is currently not occupying.
No when I slide the BuildingFragment (blue) I need the second fragment (red) either to stay behind the Building Fragment or just make room by moving up or down. Either way is acceptable.
Here is an illustration:
Second question:
If I DONT want to replace fragments but add a new one, how can I bring the older fragment on top of the new one?
Check this lib its may be help you that you want achieve.
<com.sothree.slidinguppanel.SlidingUpPanelLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:sothree="http://schemas.android.com/apk/res-auto"
android:id="#+id/sliding_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
sothree:umanoPanelHeight="68dp"
sothree:umanoShadowHeight="4dp"
sothree:umanoParallaxOffset="100dp"
sothree:umanoDragView="#+id/dragView"
sothree:umanoOverlay="true"
sothree:umanoScrollableView="#+id/list">
<!-- MAIN CONTENT -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!--LOAD FIRST FRAGMENT-->
</FrameLayout>
<!-- SLIDING LAYOUT -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!--LOAD SECOND FRAGMENT-->
</FrameLayout>
</com.sothree.slidinguppanel.SlidingUpPanelLayout>
You can do commit as many times as you wish on a FragmentManager, BTW there is only one instance of FragmentManager that getFragmentManager() returns on each call. You can add a Fragment to any view any no of times.
So even if you have added a fragment, you can add same Fragment again to a view.
It is nothing but another instance of Fragment that will work as a isolated entity.

Android UI navigation within Activity Advice and best practice

I'am stuck!
I am developing my first Android App, so I am considered as a beginner. I have some programming background, so I managed to solve the first problems myself. But now I am at a point where I don't know how to solve several problems. So please share your eternal wisdom with me.
I am developing a game. I want the menu to be in a virtual phone. The picture below describes best what I want to achieve. Don't be confused by the words, I am from Germany.
Einstellungen = preferences ...
http://www.directupload.net/file/d/3565/2xwgz3al_png.htm
When I am pressing the menu-button a fragment gets called. At the moment the layout of the fragment contains relative layout with android : background set to that entire image. What I want to achieve is that the phoneframe stays all the time, only the view (RED) will change. With up and down buttons I want to be able to move the chooser (BLUE) to the different menuitems. If I press OK (YELLOW) the selected item is called an e new view slides from the right side in the RED area. Hope that's clear.
So my questions are:
How do I get the RED area to that phoneframe? Maybe a LinearLayout with fixed Width and Height? But i cant image that as a good solution.
How do I animate the chooser (Blue) to the different menupoints by clicking up and down?
How would you perform the switch between the views inside of the phone Frame.
I want to perform all of that in that only fragment. Or is there a better solution?
I do not need the code for that all, only a push, a start or ideas so I can start googleing in the right directions.
Big Text an many questions, I hope you can take a little time for me, THANKS for answers.
Greetings from Germany (sorry if my English is not perfect)!
Well you are asking a lot of question at once so it's difficult for me to give a clear answer. I am just going to explain to you how I would build a screen like that:
1) The Layout:
You Layout can simply be built with a RelativeLayout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/flFragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_marginTop="64dp"
android:layout_marginLeft="64dp"
android:layout_marginRight="64dp"
android:layout_marginBottom="128dp"
android:background="#ff0000"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<Button
android:id="#+id/btnDown"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:layout_marginBottom="15dp"
android:text="#string/fragment_main_button_down_text"/>
<Button
android:id="#+id/btnUp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#id/btnDown"
android:layout_centerHorizontal="true"
android:text="#string/fragment_main_button_up_text"/>
<Button
android:id="#+id/btnClose"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="#id/btnDown"
android:layout_alignParentBottom="true"
android:text="#string/fragment_main_button_close_text"/>
<Button
android:id="#+id/btnOk"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/btnDown"
android:layout_alignParentBottom="true"
android:text="#string/fragment_main_button_ok_text"/>
</RelativeLayout>
</RelativeLayout>
So the layout is not that complicated, I set the background color of the FrameLayout to white so you can see were the fragment will be placed. Here is the Result:
This layout contains the buttons ok, close, up and down and of course a FrameLayout where our fragment is going to go. The layout in this example is by far not optimal, the problem is the positioning of the FrameLayout. It is as big as the screen with a fixed margin on all sides, so on different phones with different aspect ratios the FrameLayout is also going to have a different aspect ratio.
2) The FragmentTransaction
Now comes the interesting part, we are going to put our fragment into the FrameLayout container. But first, since we want the fragment to slide in from the right we have to write an ObjectAnimator like this:
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator"
android:propertyName="xFraction"
android:valueType="floatType"
android:valueFrom="1.0"
android:valueTo="0.0"
android:duration="750" />
This describes a translation animation from right to left, if you want more information on that feel free to ask.
Now with that animation we have everything we need, now whenever you want to change the Fragment inside the phone you just have to perform a FragmentTransaction like this:
// We get our FragmentManager and begin our transaction
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
// Here we set our animations, to make the effect nicer I added a fade out animation for the old fragment
// The fade out animation is already built into Android
transaction.setCustomAnimations(R.animator.slide_in_right, android.R.animator.fade_out);
// We specify were we want the Fragment to go and pass along our new fragment instance.
// Calls to replace(), add(), remove()... always have to take place AFTER setCustomAnimations()
// Otherwise the animations are not applied to the fragments
transaction.replace(R.id.flFragmentContainer, fragment);
// With commit() the transaction is actually executed. You can replace multiple fragments in a single transaction
transaction.commit();
And here is the result, in my example app the FragmentTransaction is executed every time I press OK:

FragmentManager multiple on-screen fragments?

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.

Android: RelativeLayout background drawable disappears

I have an xml layout for a Fragment (android.support.v4.app.Fragment). When this Fragment is added for the first time, the background drawable displays fine. But when this Fragment is replaced with another Fragment, then later replaced back in again (by creating a new instance and using FragmentTransaction.replace()), the background drawable disappears (but not in all cases, see below). Here is the layout xml for the Fragment:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<include layout="#layout/footer_photos" />
<RelativeLayout
android:id="#+id/pageLayout"
android:background="#drawable/body_background2"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="#id/footer">
<ImageView
android:id="#+id/page"
android:layout_height="500dp"
android:layout_width="400dp"
android:layout_centerInParent="true"
android:background="#FFF" />
</RelativeLayout>
</RelativeLayout>
The background drawable in question is in the RelativeLayout with the id "pageLayout".
Possible clues:
When I remove the ImageView in there, the background drawable shows up fine.
The other Fragments have similar layout xmls (with the same background drawable), but without ImageViews inside of them, and they work fine.
One of these Fragments has a WebView and buttons inside of it, and this one's background shows up fine.
After replacing the "WebView Fragment" with the Fragment in question, the background shows up fine (!?).
EDIT: The same issue consistently occurs if an image is loaded into the ImageView then a dialog-themed activity is launched on top of it, then finished. My solution below fixes both cases.
Found a better solution than my last one. In onResume() for the Fragment, just need to do:
getView().post(new Runnable() {
#Override
public void run() {
View v = getView();
if (v != null)
v.invalidate();
}
});
It causes a flicker, but at least it seems to work consistently.
i had a similar problem. With a relativelayout, there was an imageView and a textView.
I resolved with a call to bringToFront method:
myImageView.bringToFront();
Hope this helped.
Okay, I fixed this issue while trying to fix another issue. The issue was solved by calling setLayoutParams() on the page ImageView (with whatever layout params). This caused the background of the pageLayout RelativeLayout to show up again. The cause of the issue remains unknown...
The fragments are replaced , along with their background, which means that
when a fragment A is replaced by fragment B, the background changes to the background of fragment B.
If you don't give any background to fragment B, then you can see fragment B over fragment A.

Categories

Resources