Can't get objectAnimator working with xFraction
F

3

2

I'm trying to animate a slide-in/slide-out animation between Fragments. I know there're tons of similiar question out there on StackOverflow, but believe me - I tried all of them and none is working.

Following my code (basically taken from similiar questions):

Custom Layout

public class SlidingFrameLayout extends FrameLayout {

    public SlidingFrameLayout(Context context) {
        super(context);
    }

    public SlidingFrameLayout(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();
        setX((width > 0) ? (xFraction * width) : -9999);
    }
}

Fragment Transaction

FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.setCustomAnimations(R.animator.card_enter_right, R.animator.card_out_left);
ft.replace(R.id.quiz_container, CardFragment.newInstance());
ft.commit();

Object animator

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:interpolator="@android:anim/linear_interpolator"
    android:propertyName="xFraction"
    android:valueFrom="1.0"
    android:valueTo="0.0"
    android:valueType="floatType" />

Layout file

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.my.package.views.SlidingFrameLayout
        android:id="@+id/quiz_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- Other views -->

</FrameLayout>

So when I'm running this code nothing happens. The Fragments get replaced but without an animation.
What am doing wrong?

Note: If I'm running the animation with "x" instead of "xFraction" and changing the values to let's say from:1280 to:0 it's working. Unfortunately this isn't a solution for me, since I need a "percentage value" because of the broad range of display resolutions.


Solution

Thanks to pskink who led me to the solution. I always thought that the container of my Fragment needs to implement the getXFraction()/setXFraction() method. But that's not true. You're Fragments layout needs to implement getXFraction()/setXFraction. So basically I changed my Fragment-Layout from something like this:

<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:prefix="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="40dp"
    prefix:cardCornerRadius="4dp">

<!-- Content -->
</android.support.v7.widget.CardView>

to:

<com.my.package.views.SlidingFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:prefix="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="40dp"
        prefix:cardCornerRadius="4dp">

<!-- Content -->
    </android.support.v7.widget.CardView>
</com.my.package.views.SlidingFrameLayout>
Furthermore answered 6/9, 2014 at 10:13 Comment(11)
setXFraction and getXFraction should be defined in the root view: the view you return from onCreateView, test it by removing root FrameLayoutPing
That's something I tried as well, unfortunately the problem remains. I just edited my question.Furthermore
in this case replace objectAnimator with animator in xml file, override Fragment.onCreateAnimator, load your animator and setup update listenerPing
I've just tried this. Everything gets called properly though nothing has changed. And honestly saying I don't know what's the purpose of this?!Furthermore
is your listener called or not?Ping
It's called, please see my edit / additional note. Btw: Thanks so far for your efforts.Furthermore
no no no, your "animator" is actually ValueAnimator, so use addUpdateListener, not addListenerPing
Ok, just changed that (see edited post). onAnimationUpdate is called as well. Isn't it strange that the getXFraction method isn't called ever?Furthermore
it is called, on the root view in your hierarchy, in your case CardView, what is strange you say you dont have a CardView as a root in your FragmentPing
your previous edit was ok: use AnimatorInflater but cast the result to ValueAnimatorPing
Now I'm feeling kinda stupid. The CardView is actually the root-view of my CardFragment. I just wrapped the CardView inside my SlidingFrameLayout and now it works flawlessly. Would you mind posting this as an answer so that I can accept it? Note: I always thought that the container of my Fragment needs to implemented the getXFraction()/setXFraction() method.Furthermore
P
2

setXFraction and getXFraction should be defined in the root view: the view you return from onCreateView, in your case custom CardView

Ping answered 6/9, 2014 at 14:41 Comment(0)
V
3

since above code listings are only partial, I thought I'd share with you a complete working example. It works as outlined in the question.

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>
Vancevancleave answered 13/1, 2015 at 14:56 Comment(0)
P
2

setXFraction and getXFraction should be defined in the root view: the view you return from onCreateView, in your case custom CardView

Ping answered 6/9, 2014 at 14:41 Comment(0)
U
1

The example provided by @mathheadinclouds worked for me using "R.animator.in" instead of R.anim.in in the line:

transaction.setCustomAnimations(R.anim.in, R.anim.out);
Unharness answered 1/9, 2015 at 9:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.