Android:使用 ObjectAnimator 使用 View 维度的分数转换 View

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10854940/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 05:15:10  来源:igfitidea点击:

Android: Using ObjectAnimator to translate a View with fractional values of the View's dimension

androidanimation

提问by orospakr

It appears that the old view animations (translate, scale, and so on) are no longer accepted by the AnimationInflater, at least as of ICS. I read its code in 4.0.4, and it explicitly expects only the XML elements set, objectAnimator, animator.

似乎旧的视图动画(translatescale等)不再被 接受AnimationInflater,至少从 ICS 开始。我在 4.0.4 中阅读了它的代码,它明确地只需要 XML 元素set, objectAnimator, animator

Even though the documentation at http://developer.android.com/guide/topics/resources/animation-resource.htmlcontinues to include the view animations, they appear to be deprecated. Trying to use them results in, for instance, the error java.lang.RuntimeException: Unknown animator name: translate.

尽管http://developer.android.com/guide/topics/resources/animation-resource.html 上的文档继续包含视图动画,但它们似乎已被弃用。例如,尝试使用它们会导致错误java.lang.RuntimeException: Unknown animator name: translate

As such, it becomes necessary to use Android's ObjectAnimator. However, it does not accept fractional values of the associated dimension of itself or its parent (width for translationX, for example) as the old view animations did in the form "75%p".

因此,有必要使用 Android 的ObjectAnimator. 但是,它不接受其自身或其父级(translationX例如,宽度)的相关维度的分数值,就像旧视图动画在表单中所做的那样"75%p"

Constructing the ObjectAnimatormanually at runtime, by programmatically fetching the size of the Fragment, isn't feasible because the FragmentTransactiononly accepts declarative animations specified by a resid.

ObjectAnimator通过以编程方式获取 Fragment 的大小在运行时手动构建是不可行的,因为FragmentTransaction仅接受由 resid 指定的声明性动画。

My goal is to translate offscreen a Fragment that is filling up an entire Activity (I'm basically doing a shift transition between two fragments). This is the existing TranslationAnimationimplementation (slide_in_right.xml, which along with its counterpart slide_out_left.xmlis for some reason not exposed in android.R.anim, and I therefore have to duplicate them in my codebase):

我的目标是在屏幕外翻译一个填满整个 Activity 的 Fragment(我基本上是在两个 Fragment 之间进行转换转换)。这是现有的TranslationAnimation实现(slide_in_right.xmlslide_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>

My API level is set to 14.

我的 API 级别设置为 14。

Thanks!

谢谢!

回答by Olivier Marty

Actually object animators accept fractional values. But maybe you didn't understand the underlying concept of an objectAnimator or more generally a value animator. A value animator will animate a value related to a property (such as a color, a position on screen (X,Y), an alpha parameter or whatever you want). To create such a property (in your case xFraction and yFraction) you need to build your own getters and setters associated to this property name. Lets say you want to translate a FrameLayout from 0% to 25% of the size of your whole screen. Then you need to build a custom View that wraps the FrameLayout objects and write your getters and setters.

实际上对象动画师接受小数值。但也许您不了解 objectAnimator 或更一般的值动画师的基本概念。值动画师将动画与属性相关的值(例如颜色、屏幕上的位置 (X,Y)、alpha 参数或任何你想要的)。要创建这样的属性(在您的情况下为 xFraction 和 yFraction),您需要构建与此属性名称相关联的自己的 getter 和 setter。假设您想将 FrameLayout 从整个屏幕大小的 0% 转换为 25%。然后您需要构建一个自定义 View 来包装 FrameLayout 对象并编写您的 getter 和 setter。

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);
    }
}

Then You can use the xml way to declare the object animator putting xFraction under the property xml attribute and inflate it with a AnimatorInflater

然后您可以使用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"/>

or you can just use the java line code

或者你可以只使用java行代码

ObjectAnimator oa = ObjectAnimator.ofFloat(menuFragmentContainer, "xFraction", 0, 0.25f);

Hope it helps you!

希望对你有帮助!

Olivier,

奥利维尔,

回答by sherpya

Android SDK implementation of FragmentTransactionexpects an Animatorwhile, for some obscure reason, the support library implementation expects an Animation, if you use Fragment implementation from support library your translate animation will work

Android SDK 实现FragmentTransaction需要一段Animator时间,由于某些晦涩的原因,支持库实现需要一个Animation,如果您使用支持库中的 Fragment 实现,您的翻译动画将起作用

回答by Johannes

Here is an important gotchafor those who are trying to create view animations like translateand scale.

对于那些试图创建和 之类的视图动画的人来说,这是一个重要的问题translatescale

Property animations are located in a directory named "animator": res/animator/filename.xml

属性动画位于名为“ animator”的目录中:res/animator/filename.xml

BUT, view animations must be put in a directory simply called "anim": res/anim/filename.xml

但是,视图动画必须放在一个名为“ anim”的目录中: res/anim/filename.xml

I first put my view animation in an "animator" folder, and was confused about Android Studio complaining about how translate was not a valid element. So, NO, view animations are not deprecated. They just have their own location for some confusing reason.

我首先将我的视图动画放在“animator”文件夹中,并且对 Android Studio 抱怨 translate 不是有效元素感到困惑。因此,,不推荐使用视图动画。由于某些令人困惑的原因,他们只是拥有自己的位置。

回答by mathheadinclouds

here is complete working example (works as outlined by author of accepted answer.)

这是完整的工作示例(工作如已接受答案的作者所概述。)

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.

按下按钮在 2 个片段 A 和 B 之间切换(通过从右到左的幻灯片动画)。这些片段只是具有不同背景的愚蠢文本(AAAAAA 和 BBBBB)。

MainActivity.java

主活动.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 (layout)

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 (layout)

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 (layout)

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)

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)

out.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="0.0"
    android:valueTo="-1.0"
    android:valueType="floatType" />

</set>

回答by Ahmad Al-Ibrahim

View animations are not deprecated. If you are using Eclipse you can find them under tween animation as a resource type when creating a new Android XML file.

不推荐使用视图动画。如果您使用 Eclipse,您可以在创建新的 Android XML 文件时在补间动画下找到它们作为资源类型。