精确控制Android的VectorDrawable动画 [英] Precise control over Androids VectorDrawable animations

本文介绍了精确控制Android的VectorDrawable动画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新:找到解决方案!向下滚动以查看我接受的答案!

我想为一个图像的多个元素设置动画,并将动画链接到ViewPagers的位置(因此,多个元素正在变形或飞入/飞出,具体取决于所拖动的当前页面).

那么,有没有一种方法可以精确地控制动画的当前帧?例如,假设我有这个设置:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <objectAnimator
        android:interpolator="@android:anim/decelerate_interpolator"
        android:duration="800"
        android:propertyName="scaleY"
        android:valueFrom="0"
        android:valueTo="1" />
    <objectAnimator
        android:interpolator="@android:anim/decelerate_interpolator"
        android:duration="800"
        android:propertyName="scaleX"
        android:valueFrom="0"
        android:valueTo="1" />
    <objectAnimator
        android:interpolator="@android:anim/decelerate_interpolator"
        android:duration="800"
        android:propertyName="rotation"
        android:valueFrom="0"
        android:valueTo="360" />
</set>

动画矢量文件:

<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/pre_signup_1" >
    <target
        android:name="plus_button"
        android:animation="@anim/pre_signup_1_plus_container" />
    <target
        android:name="plus"
        android:animation="@anim/pre_signup_1_plus_sign" />
</animated-vector>

运行动画的Java代码:

ImageView mImage1 = (ImageView) findViewById(R.id.image_1);
AnimatedVectorDrawableCompat animated = (AnimatedVectorDrawableCompat) mImage1.getDrawable();

animated.start();

是否有一种方法可以控制动画,例如setCurrentDuration(400),它可能会将动画的当前状态设置为一半?也许有一种方法可以将可绘制矢量拆分为图层并以编程方式对其进行动画处理?预先感谢!

解决方案

看起来可以访问VectorDrawableCompat内部的路径和组,并根据需要为其设置动画或变形!

经过一些研究,我最终从android.support.graphics.drawable包中复制了以下类:AndroidResourcesPathParserTypedArrayUtilsVectorDrawableCommonVectorDrawableCompat.

接下来,我们需要在VectorDrawableCompat类内部公开以下方法和类:getTargetByNameVGroupVFullPath.

下一步,在VectorDrawableCompat类中,删除检查Android版本(Build.VERSION.SDK_INT >= 23)的块.不知道为什么,但是如果您不这样做,动画将无法在android API 23及更高版本上运行(需要更多研究).

我可能错过了几种私有方法,但是如果遇到问题,只是将它们公开即可.

因此,现在我们可以访问VectorDrawable的各个层了!这是一个根据ViewPager的位置缩放向量组的小示例:

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="276dp"
    android:height="359dp"
    android:viewportWidth="276"
    android:viewportHeight="359">

    <group
        android:pivotX="205.5"
        android:pivotY="214.5"
        android:name="my_group">
        <path
            android:strokeColor="#4D394B"
            android:strokeWidth="7"
            android:strokeLineJoin="bevel"
            android:fillColor="#1ED761"
            android:pathData="M206.5,180 C186.9,180,171,195.9,171,215.5 S186.9,251,206.5,251
C226.1,251,242,235.1,242,215.5 S226.1,180,206.5,180 Z" />
        <path
            android:fillColor="#4D394B"
            android:pathData="M210,211 L210,190 L202,190 L202,211 L181,211 L181,219 L202,219 L202,241 L210,241
L210,219 L232,219 L232,211 Z" />
    </group>
</vector>

这是用于为组设置动画的代码:

ImageView myImageView;
VectorDrawableCompat.VGroup myVectorGroup;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_welcome);

    myImageView = (ImageView) findViewById(R.id.image_1);

    VectorDrawableCompat vectorDrawable = VectorDrawableCompat.create(getResources(), R.drawable.my_vector_drawable, null);
    vectorDrawable.setAllowCaching(false); // Important to allow image updates
    myVectorGroup = (VectorDrawableCompat.VGroup) vectorDrawable.getTargetByName("my_group");

    myImageView.setImageDrawable(vectorDrawable);

    mViewPager = (ViewPager) findViewById(R.id.pager);
    mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            if(myVectorGroup != null && position < 1) {
                myVectorGroup.setScaleX(1f - positionOffset);
                myVectorGroup.setScaleY(1f - positionOffset);

                myImageView.invalidate();
            }
        }
    });
}

我需要更多测试才能确定兼容性,但是它现在可以正常工作!

UPDATE: Solution found! Scroll down for my accepted answer!

I want to animate multiple elements of one image and link the animation to ViewPagers position (so multiple elements are morphing or flying in/out depending on the current page being dragged).

So, is there a way to precisely control the current frame of the animation? For example let's assume i have this set:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <objectAnimator
        android:interpolator="@android:anim/decelerate_interpolator"
        android:duration="800"
        android:propertyName="scaleY"
        android:valueFrom="0"
        android:valueTo="1" />
    <objectAnimator
        android:interpolator="@android:anim/decelerate_interpolator"
        android:duration="800"
        android:propertyName="scaleX"
        android:valueFrom="0"
        android:valueTo="1" />
    <objectAnimator
        android:interpolator="@android:anim/decelerate_interpolator"
        android:duration="800"
        android:propertyName="rotation"
        android:valueFrom="0"
        android:valueTo="360" />
</set>

Animated vector file:

<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/pre_signup_1" >
    <target
        android:name="plus_button"
        android:animation="@anim/pre_signup_1_plus_container" />
    <target
        android:name="plus"
        android:animation="@anim/pre_signup_1_plus_sign" />
</animated-vector>

Java code to run the animation:

ImageView mImage1 = (ImageView) findViewById(R.id.image_1);
AnimatedVectorDrawableCompat animated = (AnimatedVectorDrawableCompat) mImage1.getDrawable();

animated.start();

Is there a way to control the animation like setCurrentDuration(400) which will presumably set the current state of the animation to it's half? Maybe there is a way to split that vector drawable into layers and animate them programmatically? Thanks in advance!

解决方案

Looks like it is possible to access paths and groups inside VectorDrawableCompat and animate/morph them however you want!

After a some research I ended up duplicating the following classes from the android.support.graphics.drawable package: AndroidResources, PathParser, TypedArrayUtils, VectorDrawableCommon and VectorDrawableCompat.

Next we need to make the following method and classes public inside of the VectorDrawableCompat class: getTargetByName, VGroup and VFullPath.

Next in the VectorDrawableCompat class remove the block that checks for Android version (Build.VERSION.SDK_INT >= 23). Don't know why, but if you don't do it, the animating won't work on android API 23 and up (need more research).

I may have missed a couple of private methods, but it's just a matter of making them public if you run into problems.

So, now we have access to the layers of our VectorDrawable! Here is a small example of scaling a vector group depending on the ViewPager's position:

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="276dp"
    android:height="359dp"
    android:viewportWidth="276"
    android:viewportHeight="359">

    <group
        android:pivotX="205.5"
        android:pivotY="214.5"
        android:name="my_group">
        <path
            android:strokeColor="#4D394B"
            android:strokeWidth="7"
            android:strokeLineJoin="bevel"
            android:fillColor="#1ED761"
            android:pathData="M206.5,180 C186.9,180,171,195.9,171,215.5 S186.9,251,206.5,251
C226.1,251,242,235.1,242,215.5 S226.1,180,206.5,180 Z" />
        <path
            android:fillColor="#4D394B"
            android:pathData="M210,211 L210,190 L202,190 L202,211 L181,211 L181,219 L202,219 L202,241 L210,241
L210,219 L232,219 L232,211 Z" />
    </group>
</vector>

And this is the code used to animate the group:

ImageView myImageView;
VectorDrawableCompat.VGroup myVectorGroup;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_welcome);

    myImageView = (ImageView) findViewById(R.id.image_1);

    VectorDrawableCompat vectorDrawable = VectorDrawableCompat.create(getResources(), R.drawable.my_vector_drawable, null);
    vectorDrawable.setAllowCaching(false); // Important to allow image updates
    myVectorGroup = (VectorDrawableCompat.VGroup) vectorDrawable.getTargetByName("my_group");

    myImageView.setImageDrawable(vectorDrawable);

    mViewPager = (ViewPager) findViewById(R.id.pager);
    mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            if(myVectorGroup != null && position < 1) {
                myVectorGroup.setScaleX(1f - positionOffset);
                myVectorGroup.setScaleY(1f - positionOffset);

                myImageView.invalidate();
            }
        }
    });
}

I need some more testing to determine compatibility, but it works for now!

这篇关于精确控制Android的VectorDrawable动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆