Android: использование ObjectAnimator для преобразования представления с дробными значениями параметра View
Похоже, что старые анимации просмотра (translate
, scale
и т.д.) больше не принимаются AnimationInflater
, по крайней мере, с ICS. Я прочитал его код в 4.0.4, и он явно ожидает только элементы XML set
, objectAnimator
, animator
.
Несмотря на то, что документация на http://developer.android.com/guide/topics/resources/animation-resource.html продолжает включать анимацию вида, они выглядят устаревшими. Попытка использовать их приводит, например, к ошибке java.lang.RuntimeException: Unknown animator name: translate
.
Таким образом, становится необходимо использовать Android objectAnimator
. Тем не менее, он не принимает дробные значения связанного измерения самого себя или своего родителя (например, ширина для translationX
), поскольку старые анимации вида выполнялись в форме "75%p"
.
Построение objectAnimator
вручную во время выполнения, путем программной выборки Фрагмента, нецелесообразно, поскольку FragmentTransaction
принимает только декларативные анимации, заданные остатком.
Моя цель состоит в том, чтобы перевести на экран Фрагмент, заполняющий всю активность (я в основном делаю переход смены между двумя фрагментами). Это существующая реализация TranslationAnimation
(slide_in_right.xml
, которая, как и ее коллега slide_out_left.xml
, почему-то не отображается в android.R.anim
, поэтому мне приходится дублировать их в моей кодовой базе):
<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>
Мой уровень API равен 14.
Спасибо!
Ответы
Ответ 1
Фактически объектные аниматоры принимают дробные значения. Но, возможно, вы не поняли базовую концепцию objectAnimator или, в более общем смысле, аниматора ценности. Аниматор значений будет анимировать значение, относящееся к свойству (например, цвет, положение на экране (X, Y), альфа-параметр или все, что вы хотите). Чтобы создать такое свойство (в вашем случае xFraction и yFraction), вам нужно создать собственные геттеры и сеттеры, связанные с этим именем свойства. Допустим, вы хотите перевести FrameLayout с 0% до 25% от размера всего экрана. Затем вам нужно создать пользовательский вид, который обертывает объекты FrameLayout и записывает ваши получатели и сеттеры.
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);
}
}
Затем вы можете использовать способ xml, чтобы объявить аниматор объекта, поместив xFraction под атрибут свойства xml и раздувая его с помощью 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"/>
или вы можете просто использовать код строки java
ObjectAnimator oa = ObjectAnimator.ofFloat(menuFragmentContainer, "xFraction", 0, 0.25f);
Надеюсь, это поможет вам!
Оливье,
Ответ 2
Android SDK для реализации FragmentTransaction
ожидает Animator
, хотя по какой-то неясной причине реализация библиотеки поддержки ожидает Animation
, если вы используете реализацию Fragment из библиотеки поддержки, ваша анимация перевода будет работать
Ответ 3
Вот важный вопрос для тех, кто пытается создать анимацию вида, например translate
и scale
.
Анимации свойств расположены в каталоге с именем "аниматор": res/animator/filename.xml
НО, просмотр анимаций должен быть помещен в каталог, просто называемый "anim":
res/anim/filename.xml
Сначала я поместил анимацию в анимационную папку и был смущен тем, что Android Studio жалуется, что перевод не является допустимым элементом. Таким образом, НЕТ, просмотр анимации не устарел. У них просто есть свое место для какой-то непонятной причины.
Ответ 4
вот полный рабочий пример (работы, описанные автором принятого ответа.)
Нажатие кнопки переключает между двумя фрагментами A и B (с помощью слайд-анимации справа налево). Фрагменты - это просто глупый текст (AAAAAA и BBBBB) с разным фоном.
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(макет)
<?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(макет)
<?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(макет)
<?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>
Ответ 5
Просмотр анимаций не устаревает. Если вы используете Eclipse, вы можете найти их под анимацией анимации в качестве типа ресурса при создании нового файла Android XML.