Вопрос по android – Android: использование ObjectAnimator для перевода представления с дробными значениями измерения представления

40

Похоже, что старый вид анимации (translate, scaleи т. д.) больше не принимаютсяAnimationInflaterПо крайней мере, как ICS. Я прочитал его код в 4.0.4, и он явно ожидает только элементы XMLset, objectAnimator, animator.

Хотя документация наhttp://developer.android.com/guide/topics/resources/animation-resource.html продолжает включать анимации вида, они выглядят устаревшими. Попытка их использования приводит, например, к ошибкеjava.lang.RuntimeException: Unknown animator name: translate.

Таким образом, становится необходимым использовать AndroidObjectAnimator, Однако он не принимает дробные значения соответствующего измерения самого себя или своего родителя (ширина для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] [1]:stackoverflow.com/questions/25699178/… mathheadinclouds
На самом деле, естьAnimatorInflater а такжеAnimationUtilsи оба они все еще поддерживаются (уровень API 22). Вы по-прежнему можете использовать «старый» анимация анимации, если хотите, но она не всегда работает, правда. Один пример - если вы используете нативные (то есть не поддерживающие) фрагменты - они требуют новых аниматоров, а затем вам нужно написать некоторый код. Для этого есть решения, такие как подклассы с «actionX / Y »; свойства, но я думаю, что лучше использовать ValueAnimator с пользовательским слушателем для обновления позиций - тогда вам не нужен подкласс. wujek

Ваш Ответ

5   ответов
8

gotcha для тех, кто пытается создать вид анимации, какtranslate а такжеscale.

Анимация свойств находится в каталоге с именем & quot;animator& Quot ;:res/animator/filename.xml

НО, анимации просмотра должны быть помещены в каталог, называемый просто & quot;anim& Quot ;: res/anim/filename.xml

Сначала я помещаю свою анимацию вида в «аниматор». папку, и был смущен из-за жалобы Android Studio на то, что перевод не был допустимым элементом. Так,NO, просмотр анимации не считается устаревшим. У них просто есть свое местоположение по какой-то непонятной причине.

50

возможно, вы не поняли основную концепцию объектного аниматора или, в более общем смысле, аниматора значений. Аниматор значений будет анимировать значение, связанное со свойством (например, цвет, положение на экране (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);

Надеюсь, это поможет вам!

Оливье,

Я нашел правильный способ сделать относительный перевод, setTranslationX ()
кто вызывает getXFraction и setXFraction здесь?
Теперь вопрос на миллион долларов: почему эти свойства не были добавлены в Android, когда они добавили новые свойства в 3.0? Это кажется мне серьезным упущением.
Вместо подкласса со свойствами frationX / Y можно использоватьValueAnimator и установитьAnimatorUpdateListener, чьяonAnimationUpdate() Метод будет выполнять необходимые расчеты и устанавливать свойства анимируемых вещей. Я думаю, что это лучше, чем создание подкласса вида / макета.
Просто добавьте для случая установки CustomAnimation для фрагмента транзакции для 3.0+, вам нужно расширить родительский макет представления вашего фрагмента. Например, если корневым макетом вашего фрагмента является RelativeLayout, вам потребуется расширить RelativeLayout и добавить установщик получателя для xFraction или любого другого свойства, которое вы хотите. Затем он будет применяться к фрагменту.
9

FragmentTransaction ожидаетAnimator в то время как по какой-то непонятной причине реализация библиотеки поддержки ожидаетAnimation, если вы используете реализацию фрагмента из библиотеки поддержки, ваша анимация перевода будет работать

Да, вы не можете выбирать. Если вы хотите использовать библиотеку поддержки, необходимо использовать анимацию анимации, в противном случае необходимо использовать свойство animation !!
Причина в том, что API 4 не поддерживает Animator без девятилетних андроидов.
4

как указано автором принятого ответа.)

Нажатие кнопки переключает между 2 фрагментами 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) {
        supe,r(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 (аним)

<?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>
0

вы можете найти их в анимации анимации как тип ресурса при создании нового XML-файла Android.

Похожие вопросы