animations - android object animator
Android: utilizando ObjectAnimator para traducir una vista con valores fraccionarios de la dimensiĆ³n de la vista (5)
Aquí hay un mensaje importante para aquellos que intentan crear animaciones de vista como translate
y scale
.
Las animaciones de propiedades se encuentran en un directorio llamado " animator ": res/animator/filename.xml
PERO, las animaciones de vista deben colocarse en un directorio llamado simplemente " anim ": res/anim/filename.xml
Primero coloqué la animación de mi vista en una carpeta "animator" y me confundí acerca de que Android Studio se quejaba de que la traducción no era un elemento válido. Entonces, NO , las animaciones de vista no están en desuso. Simplemente tienen su propia ubicación por alguna razón confusa.
Parece que las animaciones de vistas antiguas ( translate
, scale
, etc.) ya no son aceptadas por AnimationInflater
, al menos desde ICS. Leí su código en 4.0.4, y espera explícitamente solo los elementos XML set
, objectAnimator
, animator
.
Aunque la documentación en http://developer.android.com/guide/topics/resources/animation-resource.html continúa incluyendo las animaciones de la vista, parecen estar en desuso. Intentar utilizarlos da como resultado, por ejemplo, el error java.lang.RuntimeException: Unknown animator name: translate
.
Como tal, se hace necesario usar el ObjectAnimator
de Android. Sin embargo, no acepta valores fraccionarios de la dimensión asociada de sí misma o su elemento principal (ancho para la translationX
, por ejemplo) como las antiguas animaciones de vista lo hicieron en la forma "75%p"
.
La construcción manual del ObjectAnimator
en tiempo de ejecución, mediante la ObjectAnimator
del tamaño del Fragment mediante programación, no es posible porque FragmentTransaction
solo acepta las animaciones declarativas especificadas por un resid.
Mi objetivo es traducir fuera de pantalla un Fragmento que está llenando una Actividad completa (básicamente estoy haciendo una transición de cambio entre dos fragmentos). Esta es la implementación de TranslationAnimation
existente ( slide_in_right.xml
, que junto con su contraparte slide_out_left.xml
es por alguna razón no expuesta en android.R.anim
, y por lo tanto tengo que duplicarlas en mi base de código):
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="100%p"
android:toXDelta="0"
android:duration="@android:integer/config_mediumAnimTime"/>
</set>
Mi nivel de API está establecido en 14.
¡Gracias!
En realidad, los animadores de objeto aceptan valores fraccionarios. Pero tal vez no entendiste el concepto subyacente de un ObjectAnimator o, más en general, un animador de valor. Un animador de valores animará un valor relacionado con una propiedad (como un color, una posición en la pantalla (X, Y), un parámetro alfa o lo que quieras). Para crear dicha propiedad (en su caso xFraction e yFraction) necesita construir sus propios getters y setters asociados a este nombre de propiedad. Digamos que quieres traducir un FrameLayout de 0% a 25% del tamaño de toda tu pantalla. Luego, debe crear una vista personalizada que ajuste los objetos FrameLayout y escriba sus captadores y decodificadores.
public class SlidingFrameLayout extends FrameLayout
{
private static final String TAG = SlidingFrameLayout.class.getName();
public SlidingFrameLayout(Context context) {
super(context);
}
public SlidingFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public float getXFraction()
{
int width = getWindowManager().getDefaultDisplay().getWidth();
return (width == 0) ? 0 : getX() / (float) width;
}
public void setXFraction(float xFraction) {
int width = getWindowManager().getDefaultDisplay().getWidth();
setX((width > 0) ? (xFraction * width) : 0);
}
}
Luego, puede usar la forma xml para declarar el animador de objetos poniendo xFraction bajo el atributo property xml e inflarlo con un AnimatorInflater
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="xFraction"
android:valueType="floatType"
android:valueFrom="0"
android:valueTo="0.25"
android:duration="500"/>
o simplemente puedes usar el código de la línea java
ObjectAnimator oa = ObjectAnimator.ofFloat(menuFragmentContainer, "xFraction", 0, 0.25f);
Espero que te ayude!
Olivier,
La implementación de Android SDK de FragmentTransaction
espera un Animator
mientras, por alguna razón oscura, la implementación de la biblioteca de soporte espera una Animation
, si usas la implementación de Fragment desde la biblioteca de soporte, tu animación de traducción funcionará
Las animaciones de vista no están en desuso. Si está utilizando Eclipse, puede encontrarlos en animación Tween como un tipo de recurso al crear un nuevo archivo XML de Android.
aquí está el ejemplo completo de trabajo (funciona según lo delineado por el autor de la respuesta aceptada).
Al presionar el botón, se alterna entre 2 fragmentos A y B (mediante la animación de diapositivas de derecha a izquierda). Los fragmentos son solo texto estúpido (AAAAAA y BBBBB) con diferentes antecedentes.
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.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
private static final String TAG = "Main";
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){
Log.i(TAG, "fragment is null");
if (showingA){
f = a = new A();
} else {
f = b = new B();
}
fragmentWasNull = true;
} else {
Log.i(TAG, "fragment is not null");
showingA = (f instanceof A);
updateButtonText();
}
if (fragmentWasNull){
FragmentTransaction ft = fm.beginTransaction();
ft.add(layoutId, showingA ? a : b, "main").commit();
}
}
private void updateButtonText(){
button.setText(showingA ? "slide in B" : "slide in A");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
FragmentManager fm = getFragmentManager();
button = (Button)findViewById(R.id.button);
incarnate(fm);
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;
updateButtonText();
}
};
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 (diseño)
<?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 (diseño)
<?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 (diseño)
<?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>