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

Похоже, что старый вид анимации (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.

Спасибо!

 mathheadinclouds13 янв. 2015 г., 16:05
полный рабочий пример кода здесь [введите описание ссылки здесь] [1] [1]:stackoverflow.com/questions/25699178/…
 wujek28 июн. 2015 г., 00:13
На самом деле, естьAnimatorInflater а такжеAnimationUtilsи оба они все еще поддерживаются (уровень API 22). Вы по-прежнему можете использовать «старый» анимация анимации, если хотите, но она не всегда работает, правда. Один пример - если вы используете нативные (то есть не поддерживающие) фрагменты - они требуют новых аниматоров, а затем вам нужно написать некоторый код. Для этого есть решения, такие как подклассы с «actionX / Y »; свойства, но я думаю, что лучше использовать ValueAnimator с пользовательским слушателем для обновления позиций - тогда вам не нужен подкласс.

Ответы на вопрос(5)

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

 10 окт. 2014 г., 11:32
Да, вы не можете выбирать. Если вы хотите использовать библиотеку поддержки, необходимо использовать анимацию анимации, в противном случае необходимо использовать свойство animation !!
 15 дек. 2014 г., 00:45
Причина в том, что API 4 не поддерживает Animator без девятилетних андроидов.
Решение Вопроса

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

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

Оливье,

 05 сент. 2014 г., 23:44
кто вызывает getXFraction и setXFraction здесь?
 20 мая 2014 г., 21:33
Просто добавьте для случая установки CustomAnimation для фрагмента транзакции для 3.0+, вам нужно расширить родительский макет представления вашего фрагмента. Например, если корневым макетом вашего фрагмента является RelativeLayout, вам потребуется расширить RelativeLayout и добавить установщик получателя для xFraction или любого другого свойства, которое вы хотите. Затем он будет применяться к фрагменту.
 16 авг. 2015 г., 15:19
Я нашел правильный способ сделать относительный перевод, setTranslationX ()
 28 февр. 2013 г., 01:44
Теперь вопрос на миллион долларов: почему эти свойства не были добавлены в Android, когда они добавили новые свойства в 3.0? Это кажется мне серьезным упущением.
 28 июн. 2015 г., 00:09
Вместо подкласса со свойствами frationX / Y можно использоватьValueAnimator и установитьAnimatorUpdateListener, чьяonAnimationUpdate() Метод будет выполнять необходимые расчеты и устанавливать свойства анимируемых вещей. Я думаю, что это лучше, чем создание подкласса вида / макета.

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

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

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

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

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

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

Нажатие кнопки переключает между 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>

Ваш ответ на вопрос