I'm trying to put slide animation on a FragmentContainerView. However, the fragment that should appear flickers before starting the animation.
To summarize, when the transaction begins, the current fragment slides out, the next fragment flickers and then slides in.
I'm not asking for direct solutions, but if somebody knows what can cause this kind of bug, because I don't even know what to look at to solve this problem.
Edit: Code samples
FragmentContainerView (XML)
<androidx.fragment.app.FragmentContainerView
android:id="#+id/frame_cigarette"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="#id/toolbar_activity_filter"
app:layout_constraintBottom_toBottomOf="parent"
/>
Code for fragment transition
supportFragmentManager.beginTransaction()
.setCustomAnimations(
R.anim.slide_in_right,
R.anim.slide_out_left,
R.anim.slide_in_left,
R.anim.slide_out_right
)
.replace(
R.id.frame_cigarette,
CigaretteCravingFragment.newInstance(),
CigaretteCravingFragment::class.java.simpleName
)
.addToBackStack(CigaretteCravingFragment::class.java.simpleName)
.commit()
Code for an exit slide animation (slide out right)
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="#android:integer/config_mediumAnimTime"
android:fromXDelta="0"
android:toXDelta="100%p" />
</set>
Code for an enter slide animation (slide in left)
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="#android:integer/config_mediumAnimTime"
android:fromXDelta="-100%p"
android:toXDelta="0" />
</set>
I had the same problem and I solved this few moments ago. In my case Im using navigation graph to define all animation between fragments but in your case should work the same because setCustomAnimations also can take #AnimatorRes. You have to use ObjectAnimator and custom layout. Inspiration from: Animate the transition between fragments
CustomConstraintLayout.java
public class CustomConstraintLayout extends ConstraintLayout {
public float getXFraction() {
return getX() / getWidth();
}
public float getYFraction() {
return getY() / getHeight();
}
public void setXFraction(float xFraction) {
final int width = getWidth();
setX((width > 0) ? (xFraction * width) : -9999);
}
public void setYFraction(float yFraction) {
final int height = getHeight();
setY((height > 0) ? (yFraction * height) : -9999);
}
}
slide_in_from_bottom_animator.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:valueType="floatType"
android:propertyName="yFraction"
android:valueFrom="1.0"
android:valueTo="0.0"
android:interpolator="#android:anim/accelerate_decelerate_interpolator"
android:duration="#integer/change_view_anim_time"/>
</set>
YourFragment.xml
<?xml version="1.0" encoding="utf-8"?>
<com.yourapp.ui.CustomConstraintLayout 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">
<!-- some stuff -->
</com.yourapp.ui.CustomConstraintLayout>
Related
I want to implement enter and exit fragment animation during navigation in MVVMCross project.
[MvxFragmentPresentation(typeof(TestViewModel),
Resource.Id.content_frame, true,
Resource.Animation.enter_from_right,
Resource.Animation.exit_nothing_animation)]
enter_from_right
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:fromXDelta="100%p" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="#android:integer/config_mediumAnimTime" />
</set>
exit_nothing_animation
<?xml version="1.0" encoding="UTF-8" ?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="300"
android:fromAlpha="1"
android:toAlpha="1" />
I expect that new fragment slide from right over the old frgamnet and old fragment will remain in the same place.
But new fragment just instantly appears without animation
Other topics suggest use Add insted Replace, but what the right way in MVVMCross project?
Answer is override this method in base fragment class
public override Animation OnCreateAnimation(int transit, bool enter, int nextAnim)
{
if (nextAnim == Resource.Animation.enter_from_right)
{
ViewCompat.SetTranslationZ(view, 1f);
}
else
{
ViewCompat.SetTranslationZ(view, 0f);
}
return base.OnCreateAnimation(transit, enter, nextAnim);
}
First of all, please don't declare it as duplicate because i have been spending time on stackoverflow since last five days and i have read a lot of answers but still not able to achieve this.
I want card flip animation in my application. I tried https://developer.android.com/training/animation/cardflip.html also but exit animation is not being played there for me.
So i used two frame layouts for two fragments in a Linear Layout and then tried to rotate and translate first frame layout towards left out of screen while rotating and translating next frame layout in from right.First frame is rotating as required but translation is not there.
Please help to make frame layout translate also with rotation so that next fragment could enter the screen.
My code is:
activity_card.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/toolbar"
android:background="#color/colorPrimary"
>
</android.support.v7.widget.Toolbar>
<LinearLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="horizontal"
>
<FrameLayout
android:id="#+id/frame_layout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
>
</FrameLayout>
<FrameLayout
android:id="#+id/frame_layout2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
>
</FrameLayout>
</LinearLayout>
</LinearLayout>
card_flip_left_out.xml:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Rotate. -->
<objectAnimator
android:valueFrom="0"
android:valueTo="180"
android:propertyName="rotationY"
android:interpolator="#android:interpolator/accelerate_decelerate"
android:startOffset="0"
android:duration="1000" />
<!-- Half-way through the rotation (see startOffset), set the alpha to 0. -->
<objectAnimator
android:valueFrom="1.0"
android:valueTo="0.0"
android:propertyName="alpha"
android:startOffset="0"
android:duration="800" />
<objectAnimator
android:propertyName="translationX"
android:valueTo="-200"
android:interpolator="#android:interpolator/accelerate_decelerate"
android:startOffset="0"
android:duration="1000"
/>
</set>
card_flip_right_in.xml:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Before rotating, immediately set the alpha to 0. -->
<objectAnimator
android:valueFrom="1.0"
android:valueTo="0.0"
android:propertyName="alpha"
android:duration="0" />
<!-- Rotate. -->
<objectAnimator
android:valueFrom="180"
android:valueTo="0"
android:propertyName="rotationY"
android:interpolator="#android:interpolator/accelerate_decelerate"
android:duration="1000" />
<!-- Half-way through the rotation (see startOffset), set the alpha to 1. -->
<objectAnimator
android:valueFrom="0.0"
android:valueTo="1.0"
android:propertyName="alpha"
android:startOffset="0"
android:duration="800" />
<objectAnimator
android:propertyName="translationX"
android:valueTo="0"
android:interpolator="#android:interpolator/accelerate_decelerate"
android:startOffset="0"
android:duration="1000"
/>
</set>
CardActivity.java:
public class CardActivity extends AppCompatActivity implements
Toolbar.OnMenuItemClickListener {
FragmentTransaction fragmentTransaction;
FrameLayout layout1, layout2;
String visibleFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_card);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitle("Digital card");
toolbar.setTitleTextColor(Color.WHITE);
toolbar.inflateMenu(R.menu.menu);
toolbar.setOnMenuItemClickListener(this);
layout1 = (FrameLayout) findViewById(R.id.frame_layout1);
layout2 = (FrameLayout) findViewById(R.id.frame_layout2);
fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame_layout1, GeneralDetailsFragment.newInstance());
fragmentTransaction.replace(R.id.frame_layout2, AddMoreDetailsFragment.newInstance());
visibleFragment = "layout1";
fragmentTransaction.commit();
}
#Override
public boolean onMenuItemClick(MenuItem item) {
Animator anim1 = AnimatorInflater.loadAnimator(this,R.animator.card_flip_left_out);
Animator anim2 = AnimatorInflater.loadAnimator(this,R.animator.card_flip_right_in);
if(visibleFragment.equals("layout2"))
{
anim1.setTarget(layout2);
anim2.setTarget(layout1);
anim1.start();
anim2.start();
visibleFragment = "layout1";
}
else
{
anim1.setTarget(layout1);
anim2.setTarget(layout2);
anim1.start();
anim2.start();
visibleFragment = "layout2";
}
return true;
}
}
Try this way:
below is xml file for animation (left to right with rotation) and start animation on view. And make changes as per you need.
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator">
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="5"
android:toDegrees="359" />
<translate
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0%p" //For Y - android:fromYDelta="0%p" also -value
android:toXDelta="100%p" //For Y - android:toYDelta="50%p"
android:repeatCount="0"
android:duration="3000">
</translate>
</set>
Hope this will help you.
I found a different and pretty simple way to achieve card flip animation here . This animation is not for replacing or adding fragment using FragmentTransaction but for two frame layouts which already contain corresponding Fragment.
Sample code is:
public void flip(final View front, final View back, final int duration) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
AnimatorSet set = new AnimatorSet();
set.playSequentially(
ObjectAnimator.ofFloat(front, "rotationY", 90).setDuration(duration / 2),
ObjectAnimator.ofInt(front, "visibility", View.GONE).setDuration(0),
ObjectAnimator.ofFloat(back, "rotationY", -90).setDuration(0),
ObjectAnimator.ofInt(back, "visibility", View.VISIBLE).setDuration(0),
ObjectAnimator.ofFloat(back, "rotationY", 0).setDuration(duration / 2)
);
set.start();
}
else {
front.animate().rotationY(90).setDuration(duration / 2).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
front.setVisibility(View.GONE);
back.setRotationY(-90);
back.setVisibility(View.VISIBLE);
back.animate().rotationY(0).setDuration(duration / 2).setListener(null);
}
});
}
}
I have a layout like this:
And I animated this buttons in linearlayouts with this code:
public void animation(){
ust.animate().x(0).y(-5000).setDuration(500).start(); //My linear layout in the top of screen.
alt.animate().x(0).y(4000).setDuration(500).start(); //My linear layout in the bottom of screen.
}
I want to reverse this animation.
I tried this way but my linear layout in the bottom of screen, went to top.
Tried This Way:
public void animation(){
ust.animate().x(0).y(0).setDuration(500).start(); //My relative layout in the top of screen.
alt.animate().x(0).y(0).setDuration(500).start(); //My relative layout in the bottom of screen.
}
When I want to try anything like this:
public void animation(){
ust.animate().x(0).y(0).setDuration(500).start(); //My relative layout in the top of screen.
alt.animate().x(0).y(500).setDuration(500).start(); //My relative layout in the bottom of screen.
}
"alt" view dont coming to bottom of the screen in all devices.
And I want to reverse this animation. How can I do this?
Before animation, remember the y locations of your views, then reapply the y locations when reversing:
float ustY;
float altY;
public void animation(){
ustY=ust.getY();
ust.animate().x(0).y(-5000).setDuration(500).start(); //My linear layout in the top of screen.
altY=alt.getY();
alt.animate().x(0).y(4000).setDuration(500).start(); //My linear layout in the bottom of screen.
}
public void reverseAnimation(){
ust.animate().x(0).y(ustY).setDuration(500).start(); //My linear layout in the top of screen.
alt.animate().x(0).y(altY).setDuration(500).start(); //My linear layout in the bottom of screen.
}
that's how you give animations/transitions to layouts, views or widgets
public class MainActivity extends Activity {
Animation RL1, RL2, LR1, LR2, fadein, fadeout;
private View view1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.film1).setVisibility(View.GONE);
// Define all animations
new AnimationUtils();
RL1 = AnimationUtils.loadAnimation(getApplicationContext(),
R.anim.slide_right_to_left_1);
RL2 = AnimationUtils.loadAnimation(getApplicationContext(),
R.anim.slide_right_to_left_2);
LR1 = AnimationUtils.loadAnimation(getApplicationContext(),
R.anim.slide_left_to_right_2);
LR2 = AnimationUtils.loadAnimation(getApplicationContext(),
R.anim.slide_left_to_right_1);
fadein = AnimationUtils.loadAnimation(getApplicationContext(),
R.anim.fadeout);
fadeout = AnimationUtils.loadAnimation(getApplicationContext(),
R.anim.fix);
}
// **//
public void show(View view) {
findViewById(R.id.film1).setVisibility(View.VISIBLE);
view1 = (View) findViewById(R.id.film1);
view1.setAnimation(LR1);
view1.setAnimation(LR2);
}
//
}
create these xml files in the "anim" folder , these contain your animations.
slide_left_to_right_1.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<translate
android:duration="600"
android:fromXDelta="-100%"
android:toXDelta="0%" >
</translate>
</set>
slide_left_to_right_2.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<translate
android:duration="600"
android:fromXDelta="0%"
android:toXDelta="100%" >
</translate>
</set>
slide_right_to_left_1.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<translate
android:duration="600"
android:fromXDelta="100%"
android:toXDelta="0%" >
</translate>
</set>
slide_right_to_left_2.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<translate
android:duration="600"
android:fromXDelta="0%"
android:toXDelta="-100%" >
</translate>
</set>
fadeout.xml
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="800"
android:fromAlpha="0.0"
android:interpolator="#android:anim/accelerate_interpolator"
android:toAlpha="1.0" />
fix.xml
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="800"
android:fromAlpha="1.0"
android:interpolator="#android:anim/accelerate_interpolator"
android:toAlpha="0.0" />
Assuming that the view originally had no x or y offsets and by reverse you mean restore the view to its original position, call yourView.animate().y(0).setDuration(500).start()
I've check some tutorials for animate transaction between fragments. I've used this method for animation and it works:
fragmentTransaction.setCustomAnimations(android.R.anim.slide_in_left,
android.R.anim.slide_out_right);
But I want to invert this animation: old fragment slide out to the left, and new fragment slide in to the right, but no value of R.anim file seems to be useful for my scope.
How can I do it?
UPDATE For Android v19+ see this link via #Sandra
You can create your own animations. Place animation XML files in res > anim
enter_from_left.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:fromXDelta="-100%p" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="#android:integer/config_mediumAnimTime"/>
</set>
enter_from_right.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:fromXDelta="100%p" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="#android:integer/config_mediumAnimTime" />
</set>
exit_to_left.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:fromXDelta="0%" android:toXDelta="-100%p"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="#android:integer/config_mediumAnimTime"/>
</set>
exit_to_right.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:fromXDelta="0%" android:toXDelta="100%p"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="#android:integer/config_mediumAnimTime" />
</set>
you can change the duration to short animation time
android:duration="#android:integer/config_shortAnimTime"
or long animation time
android:duration="#android:integer/config_longAnimTime"
USAGE
(note that the order in which you call methods on the transaction matters. Add the animation before you call .replace, .commit):
FragmentTransaction transaction = supportFragmentManager.beginTransaction();
transaction.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right);
transaction.replace(R.id.content_frame, fragment);
transaction.addToBackStack(null);
transaction.commit();
There is three way to transaction animation in fragment.
Transitions
So need to use one of the built-in Transitions, use the setTranstion()
method:
getSupportFragmentManager()
.beginTransaction()
.setTransition( FragmentTransaction.TRANSIT_FRAGMENT_OPEN )
.show( m_topFragment )
.commit()
Custom Animations
You can also customize the animation by using the setCustomAnimations() method:
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations( R.anim.slide_up, 0, 0, R.anim.slide_down)
.show( m_topFragment )
.commit()
slide_up.xml
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/accelerate_decelerate_interpolator"
android:propertyName="translationY"
android:valueType="floatType"
android:valueFrom="1280"
android:valueTo="0"
android:duration="#android:integer/config_mediumAnimTime"/>
slide_down.xml
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/accelerate_decelerate_interpolator"
android:propertyName="translationY"
android:valueType="floatType"
android:valueFrom="0"
android:valueTo="1280"
android:duration="#android:integer/config_mediumAnimTime"/>
Multiple Animations
Finally, It's also possible to kick-off multiple fragment animations
in a single transaction. This allows for a pretty cool effect where
one fragment is sliding up and the other slides down at the same time:
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations( R.anim.abc_slide_in_top, R.anim.abc_slide_out_top ) // Top Fragment Animation
.show( m_topFragment )
.setCustomAnimations( R.anim.abc_slide_in_bottom, R.anim.abc_slide_out_bottom ) // Bottom Fragment Animation
.show( m_bottomFragment )
.commit()
To more detail you can visit URL
Note:- You can check animation according to your requirement because above may be have issue.
slide_in_down.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="#android:integer/config_longAnimTime"
android:fromYDelta="0%p"
android:toYDelta="100%p" />
</set>
slide_in_up.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="#android:integer/config_longAnimTime"
android:fromYDelta="100%p"
android:toYDelta="0%p" />
</set>
slide_out_down.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="#android:integer/config_longAnimTime"
android:fromYDelta="-100%"
android:toYDelta="0"
/>
</set>
slide_out_up.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="#android:integer/config_longAnimTime"
android:fromYDelta="0%p"
android:toYDelta="-100%p"
/>
</set>
direction = down
activity.getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(R.anim.slide_out_down, R.anim.slide_in_down)
.replace(R.id.container, new CardFrontFragment())
.commit();
direction = up
activity.getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(R.anim.slide_in_up, R.anim.slide_out_up)
.replace(R.id.container, new CardFrontFragment())
.commit();
I have same issue, i used simple solution
1)create sliding_out_right.xml in anim folder
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0" android:toXDelta="-50%p"
android:duration="#android:integer/config_mediumAnimTime"/>
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
android:duration="#android:integer/config_mediumAnimTime" />
</set>
2) create sliding_in_left.xml in anim folder
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="50%p" android:toXDelta="0"
android:duration="#android:integer/config_mediumAnimTime"/>
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
android:duration="#android:integer/config_mediumAnimTime" />
</set>
3) simply using fragment transaction setCustomeAnimations() with two custom xml and two default xml for animation as follows :-
fragmentTransaction.setCustomAnimations(R.anim.sliding_in_left, R.anim.sliding_out_right, android.R.anim.slide_in_left, android.R.anim.slide_out_right );
This is another solution which I use:
public class CustomAnimator {
private static final String TAG = "com.example.CustomAnimator";
private static Stack<AnimationEntry> animation_stack = new Stack<>();
public static final int DIRECTION_LEFT = 1;
public static final int DIRECTION_RIGHT = -1;
public static final int DIRECTION_UP = 2;
public static final int DIRECTION_DOWN = -2;
static class AnimationEntry {
View in;
View out;
int direction;
long duration;
}
public static boolean hasHistory() {
return !animation_stack.empty();
}
public static void reversePrevious() {
if (!animation_stack.empty()) {
AnimationEntry entry = animation_stack.pop();
slide(entry.out, entry.in, -entry.direction, entry.duration, false);
}
}
public static void clearHistory() {
animation_stack.clear();
}
public static void slide(final View in, View out, final int direction, long duration) {
slide(in, out, direction, duration, true);
}
private static void slide(final View in, final View out, final int direction, final long duration, final boolean save) {
ViewGroup in_parent = (ViewGroup) in.getParent();
ViewGroup out_parent = (ViewGroup) out.getParent();
if (!in_parent.equals(out_parent)) {
return;
}
int parent_width = in_parent.getWidth();
int parent_height = in_parent.getHeight();
ObjectAnimator slide_out;
ObjectAnimator slide_in;
switch (direction) {
case DIRECTION_LEFT:
default:
slide_in = ObjectAnimator.ofFloat(in, "translationX", parent_width, 0);
slide_out = ObjectAnimator.ofFloat(out, "translationX", 0, -out.getWidth());
break;
case DIRECTION_RIGHT:
slide_in = ObjectAnimator.ofFloat(in, "translationX", -out.getWidth(), 0);
slide_out = ObjectAnimator.ofFloat(out, "translationX", 0, parent_width);
break;
case DIRECTION_UP:
slide_in = ObjectAnimator.ofFloat(in, "translationY", parent_height, 0);
slide_out = ObjectAnimator.ofFloat(out, "translationY", 0, -out.getHeight());
break;
case DIRECTION_DOWN:
slide_in = ObjectAnimator.ofFloat(in, "translationY", -out.getHeight(), 0);
slide_out = ObjectAnimator.ofFloat(out, "translationY", 0, parent_height);
break;
}
AnimatorSet animations = new AnimatorSet();
animations.setDuration(duration);
animations.playTogether(slide_in, slide_out);
animations.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationCancel(Animator arg0) {
}
#Override
public void onAnimationEnd(Animator arg0) {
out.setVisibility(View.INVISIBLE);
if (save) {
AnimationEntry ae = new AnimationEntry();
ae.in = in;
ae.out = out;
ae.direction = direction;
ae.duration = duration;
animation_stack.push(ae);
}
}
#Override
public void onAnimationRepeat(Animator arg0) {
}
#Override
public void onAnimationStart(Animator arg0) {
in.setVisibility(View.VISIBLE);
}
});
animations.start();
}
}
The usage of class. Let's say you have two fragments (list and details fragments)as shown below
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/ui_container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout
android:id="#+id/list_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<FrameLayout
android:id="#+id/details_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
</FrameLayout>
Usage
View details_container = findViewById(R.id.details_container);
View list_container = findViewById(R.id.list_container);
// You can select the direction left/right/up/down and the duration
CustomAnimator.slide(list_container, details_container,CustomAnimator.DIRECTION_LEFT, 400);
You can use the function CustomAnimator.reversePrevious();to get the previous view when the user pressed back.
Have the same problem with white screen during transition from one fragment to another. Have navigation and animations set in action in navigation.xml.
Background in all fragments the same but white blank screen. So i set navOptions in fragment during executing transition
//Transition options
val options = navOptions {
anim {
enter = R.anim.slide_in_right
exit = R.anim.slide_out_left
popEnter = R.anim.slide_in_left
popExit = R.anim.slide_out_right
}
}
.......................
this.findNavController().navigate(SampleFragmentDirections.actionSampleFragmentToChartFragment(it),
options)
It worked for me. No white screen between transistion. Magic )
For me the only way I was able to get rid of the white background on the animation is if I changed to a DialogFragment instead of a Fragment and added the following code:
Created the following styles:
<style name="WindowSlideInAndOutAnimation">
<item name="android:windowEnterAnimation">#anim/slide_in_bottom</item>
<item name="android:windowExitAnimation">#anim/slide_out_top</item>
</style>
<style name="AppFullScreenDialogTransparentTitleBar" parent="Theme.MaterialComponents.Light.Dialog">
<item name="android:windowBackground">#android:color/transparent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">false</item>
<item name="colorPrimaryDark">#android:color/transparent</item>
</style>
Then reference these styles in the dialog fragment as such:
override fun getTheme() = R.style.AppFullScreenDialogTransparentTitleBar
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
dialog?.window?.setWindowAnimations(R.style.WindowSlideInAndOutAnimation)
//rest of code on view created here
}
Then I just navigate to the fragment as normal via the navigation component (also note to change the type in the navigation xml file for the fragment to be dialog)
I have a fragment that is to replace another fragment. I want to specify the animation. But the animation is ignored.
transaction.replace(R.id.my_fragment, newFrag);
transaction.addToBackStack(null);
transaction.setCustomAnimations(R.anim.slide_in_up, R.anim.slide_out_up);
slide_in_up
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="#android:integer/config_longAnimTime"
android:fromYDelta="0%p"
android:toYDelta="100%p" />
slide_out_up
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="#android:integer/config_longAnimTime"
android:fromYDelta="100%p"
android:toYDelta="0%p" />
All I am really trying to achieve is for the new fragment to slide in from the bottom. My animations are ignored. What is the code missing?
transaction.setCustomAnimations(R.anim.slide_in_up, R.anim.slide_out_up);
transaction.addToBackStack(null);
transaction.replace(R.id.my_fragment, newFrag);
slide_in_up
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="#android:integer/config_longAnimTime"
android:fromYDelta="100%p"
android:toYDelta="0%p" />
slide_out_up
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="#android:integer/config_longAnimTime"
android:fromYDelta="0%p"
android:toYDelta="-100%p" />
It's been some time since this question was asked but here is an answer for other people coming here:
e1da is right insofar as that setCustomAnimation() call has to be called before replace(). Otherwise the animation will not show.
The second problem is that you probably are using native fragments that cannot be animated with the view animations.
Use the following files:
slide_in_up.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true" >
<objectAnimator
android:duration="500"
android:propertyName="y"
android:valueFrom="1280"
android:valueTo="0"
android:valueType="floatType" />
</set>
slide_out_up.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true" >
<objectAnimator
android:duration="500"
android:propertyName="y"
android:valueFrom="0"
android:valueTo="-1280"
android:valueType="floatType" />
</set>
A little explanation:
You have to differentiate between view animation for support fragments on one hand and property animation for native fragments on the other hand.
View animation:
Is the pre-android 3.0 way to animate views. Sample code for this is the slide_in.xml and slide_up.xml by user3093402
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="#android:integer/config_longAnimTime"
android:fromYDelta="0%p"
android:toYDelta="100%p" />
It is worth mentioning you cannot animate fragments with view animation. The exception to this are fragments from the support library (android.support.v4.app.Fragment).
Property animation
This is the way to animate objects after android 3.0. It is also declared as .xml files but makes use of the "valueAnimator" tag (objectAnimator extends valueAnimator). Examples are in the answer to the question.
This is the way how native fragments (android.app.Fragment) can be animated.
See also:
http://developer.android.com/guide/topics/graphics/overview.html
swap fragment in an activity via animation
Hope this helps,
Kai
EDIT: As pointed out by Raphael Royer-Rivard the fixed screen size is bad practice. It would be better to use a constant from the OS like in
getWindowManager().getDefaultDisplay().getMetrics(metrics).xdpi
(see DisplayMetrics). But I haven't done any Android development for some time so I don't know which one.
code for slide_in_up :
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="#android:integer/config_mediumAnimTime"
android:fromYDelta="100%p"
android:toYDelta="0%p" />
</set>
code for slide_in_down:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="#android:integer/config_mediumAnimTime"
android:fromYDelta="0%p"
android:toYDelta="100%p" />
</set>
code for slide_out_up:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="#android:integer/config_mediumAnimTime"
android:fromXDelta="0"
android:toYDelta="100%" />
</set>
code for slide_out_down:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="#android:integer/config_mediumAnimTime"
android:fromXDelta="0"
android:toYDelta="-100%" />
</set>
and after that in your activity or fragment set animation like below:
Fragment fragment = new Fragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.setCustomAnimations(R.anim.slide_in_up, R.anim.slide_in_down, R.anim.slide_out_down, R.anim.slide_out_up);
transaction.replace(container, fragment).commit();
Currently with android.transition this is as simple as fragment.enterTransition = Slide() or fragment.enterTransition = Fade()
Note: Min version L.
R.anim will not work there but R.animator wil do.
for example
transaction.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out);
This answer is written in Kotlin. For sake of the example, I'm just hiding or showing it based on it's current isHidden attribute. I'm using androidx.transition.Slide
Link: https://developer.android.com/reference/androidx/transition/Slide
val frag = supportFragmentManager.findFragmentById(R.id.frag_id_from_xml_layout)
frag?.let {
val ft = supportFragmentManager.beginTransaction()
frag.enterTransition = Slide()
frag.exitTransition = Slide()
if (frag.isHidden) ft.show(frag) else ft.hide(frag)
ft.commit()
}
here is complete working example
Pressing the button toggles between 2 fragments A and B (by slide animation right to left). The fragments are just stupid text (AAAAAA and BBBBB) with different backgrounds.
MainActivity.java
package com.example.slidetrans;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
boolean showingA = true;
Button button;
A a;
B b;
private void incarnate(FragmentManager fm){
int layoutId = R.id.frame;
boolean fragmentWasNull = false;
Fragment f = fm.findFragmentById(layoutId);
if (f == null){
if (showingA){
f = a = new A();
} else {
f = b = new B();
}
fragmentWasNull = true;
}
if (fragmentWasNull){
FragmentTransaction ft = fm.beginTransaction();
ft.add(layoutId, showingA ? a : b, "main").commit();
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
FragmentManager fm = getFragmentManager();
incarnate(fm);
button = (Button)findViewById(R.id.button);
OnClickListener listener = new OnClickListener() {
#Override
public void onClick(View v) {
FragmentManager fm = getFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
transaction.setCustomAnimations(R.anim.in, R.anim.out);
transaction.replace(R.id.frame, showingA ? new B() : new A()).commit();
showingA = !showingA;
button.setText(showingA ? "slide in B" : "slide in A");
}
};
button.setOnClickListener(listener);
}
}
LL.java
package com.example.slidetrans;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.LinearLayout;
public class LL extends LinearLayout {
public LL(Context context) {
super(context);
}
public LL(Context context, AttributeSet attrs) {
super(context, attrs);
}
public float getXFraction() {
final int width = getWidth();
if (width != 0) return getX() / getWidth();
else return getX();
}
public void setXFraction(float xFraction) {
final int width = getWidth();
float newWidth = (width > 0) ? (xFraction * width) : -9999;
setX(newWidth);
}
}
main.xml (layout)
<?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/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="slide in B" />
<FrameLayout
android:id="#+id/frame"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</FrameLayout>
</LinearLayout>
a.xml (layout)
<?xml version="1.0" encoding="utf-8"?>
<com.example.slidetrans.LL xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#00FF00"
>
<TextView
android:id="#+id/aText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="AAAAAAAAAAAAAAAAAA"
android:textSize="30sp"
android:textStyle="bold"
/>
</com.example.slidetrans.LL>
b.xml (layout)
<?xml version="1.0" encoding="utf-8"?>
<com.example.slidetrans.LL xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#FFFF00"
>
<TextView
android:id="#+id/bText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30sp"
android:textStyle="bold"
android:text="BBBBBBBBBB"
/>
</com.example.slidetrans.LL>
in.xml (anim)
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="500"
android:interpolator="#android:anim/linear_interpolator"
android:propertyName="xFraction"
android:valueFrom="1.0"
android:valueTo="0.0"
android:valueType="floatType" />
</set>
out.xml (anim)
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="500"
android:interpolator="#android:anim/linear_interpolator"
android:propertyName="xFraction"
android:valueFrom="0.0"
android:valueTo="-1.0"
android:valueType="floatType" />
</set>