如何以类似流体的方式为VectorDrawable设置动画? [英] How to animate a VectorDrawable in a fluid-like manner?

查看:97
本文介绍了如何以类似流体的方式为VectorDrawable设置动画?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景



假设我有一个VectorDrawable,看起来像上下箭头:



< a href = https://i.stack.imgur.com/nFXwF.png rel = nofollow noreferrer>

 < vector xmlns:android = http://schemas.android .com / apk / res / android 
android:width = 24dp
android:height = 24dp
android:viewportWidth = 24.0
android:viewportHeight = 24.0>
< path
android:pathData = M20,12l-1.41,-1.41L13,16.17V4h-2v12.17l-5.58,-5.59L4,12l8,8 8,-8z
android:fillColor =#010101 />
< / vector>

我想展示它的动画,看起来像是倒出的液体,所以首先没有如图所示,然后是顶部区域,然后是中间区域,然后是底部。全部显示之后,它开始隐藏,以便顶部被隐藏,然后是中间,然后是底部。



这里是我的意思的草图:





问题



有一些有关VectorDrawable动画的教程,似乎它们需要大量矢量理解,而没有一种简便的方法来做这种事情。



我发现的东西



我已经找到了用于此目的的工具,但我不知道如何使用它,示例链接为当前已损坏:





但是我找不到方法。



问题



如何在VectorDrawable上应用这样的动画?



使用支持库,它也可以在旧版Android上使用吗?






编辑:
我已经成功制作了箭头动画,但是它有2个问题:


  1. 由于它是一条路径,所以看起来不太好。它需要知道如何将其分为3条路径,以便每条路径都具有良好的动画效果。


  2. 似乎我在代码中使用的都是来自API 21和以上。我通过查看我之前(在此处)编写的链接来做到这一点,并且需要知道如何支持较旧的版本。


这是代码:



res / drawable / vector_animation.xml

 <动画矢量
xmlns:aapt = http://schemas.android.com/aapt
xmlns:android = http:// schemas。 android.com/apk/res/android
android:drawable = @ drawable / ic_darkblue_arrow>

<目标android:name = a_stroke>
< aapt:attr name = android:animation>
< objectAnimator
android:duration = 5000
android:interpolator = @ android:interpolator / fast_out_slow_in
android:propertyName = trimPathEnd
android :startOffset = 1300
android:valueFrom = 0
android:valueTo = 1 />
< / aapt:attr>
< / target>


< / animated-vector>

res / drawable / vector.xml

 < vector xmlns:android = http://schemas.android.com/apk/res/android 
android:width = 24dp
android:height = 24dp
android:viewportHeight = 24.0
android:viewportWidth = 24.0>
< path
android:name = a_stroke
android:fillColor =#010101
android:pathData = M20,12l-1.41,-1.41L13,16.17 V4h-2v12.17l-5.58,-5.59L4,12l8,8 8,-8z /
< / vector>

res / layout / activity_main.xml

 <?xml version = 1.0 encoding = utf-8?> 
< FrameLayout
xmlns:android = http://schemas.android.com/apk/res/android
xmlns:app = http://schemas.android.com / apk / res-auto
xmlns:tools = http://schemas.android.com/tools
android:layout_width = match_parent
android:layout_height = match_parent >

< ImageView
android:id = @ + id / imageView
android:layout_width = 200dp
android:layout_height = 200dp
android:contentDescription = @ null
android:src = @ drawable / vector_animation />

< / FrameLayout>

MainActivity.java

 公共类MainActivity扩展了AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState );
setContentView(R.layout.activity_main);
最终的Animatable cursiveAvd =(((Animatable)((ImageView)findViewById(R.id.imageView))。getDrawable());
cursiveAvd.stop();
cursiveAvd.start();
}
}






编辑:
我制作了一个简单的3路径箭头VectorDrawable,并成功对其进行了动画处理。



这是我创建的VectorDrawable:



ic_drawing.xml

 < vector xmlns:android = http ://schemas.android.com/apk/res/android 
android:width = 210dp
android:height = 297dp
android:viewportHeight = 1052.3622
android:viewportWidth = 744.0945>
< path
android:name = main_line
android:fillColor =#00000000
android:pathData = M742.6,9.7C313,-8.4 316.2, 860.8 316.2,860.8
android:strokeAlpha = 1
android:strokeColor =#000000
android:strokeLineCap = butt
android:strokeLineJoin = miter
android:strokeWidth = 5.32507801 />
< path
android:name = left_line
android:fillColor =#00000000
android:pathData = m314.3,846.6c-211.4,-254.3 -160 ,-294.3 -160,-294.3
android:strokeAlpha = 1
android:strokeColor =#000000
android:strokeLineCap = butt
android:strokeLineJoin = miter
android:strokeWidth = 5 />
< path
android:name = right_line
android:fillColor =#00000000
android:pathData = M320,843.8C364.2,751.2 437.4,670.7 471.4, 566.6
android:strokeAlpha = 1
android:strokeColor =#000000
android:strokeLineCap = butt
android:strokeLineJoin = miter
android:strokeWidth = 5 />
< / vector>

vector_animation2.xml

 <动画矢量
xmlns:aapt = http://schemas.android.com/aapt
xmlns:android = http: //schemas.android.com/apk/res/android
android:drawable = @ drawable / ic_drawing>

<目标android:name = main_line>
< aapt:attr name = android:animation>
< objectAnimator
android:duration = 5000
android:interpolator = @ android:interpolator / fast_out_slow_in
android:propertyName = trimPathEnd
android :startOffset = 1300
android:valueFrom = 0
android:valueTo = 1 />
< / aapt:attr>
< / target>
< target android:name = left_line>
< aapt:attr name = android:animation>
< objectAnimator
android:startDelay = 5000
android:duration = 5000
android:interpolator = @ android:interpolator / fast_out_slow_in
android :propertyName = trimPathEnd
android:startOffset = 1300
android:valueFrom = 0
android:valueTo = 1 />
< / aapt:attr>
< / target>
< target android:name = right_line>
< aapt:attr name = android:animation>
< objectAnimator
android:startDelay = 5000
android:duration = 5000
android:interpolator = @ android:interpolator / fast_out_slow_in
android :propertyName = trimPathEnd
android:startOffset = 1300
android:valueFrom = 0
android:valueTo = 1 />
< / aapt:attr>
< / target>

< / animated-vector>

因此,它的效果很好,但仅适用于较新的Android版本,我仍然希望知道如何很好地拆分现有的VectorDrawable,而不是创建一个新的VectorDrawable。

解决方案

有几种方法可以得到相似的外观,但并非所有支持库都可以向后兼容。因此,我建议使用 trimPathStart trimPathEnd



我将描述我将采用的方法,而不是最终的解决方案(可能会很费时!)。



入门的第一个问题是您的原来的VectorDrawable不太适合这种动画!



问题中的drawable描述了形状的轮廓(即勾勒出箭头的9条线),并且显示填充。对于我们而言,更好的方法是使可绘制对象由三行组成,其中没有 fillColor ,而是使用<$ c $设置这些行的显示方式c> strokeColor 和 strokeWidth



这应该是带有三个< path> 元素:一个用于垂直线,每个用于箭头的侧面。



一旦有了这个,您就可以考虑想要动画的外观了。 trimPathStart trimPathEnd 的值应介于0和1之间,其中0是路径的开始,而1是结束。考虑从上到下绘制的垂直线:



trimPathStart = 0 trimPathEnd = 0 -我们看不到行



->动画为



trimPathStart = 0 trimPathEnd = 1 -我们从顶部开始到底部



->动画



trimPathStart = 1 trimPathEnd = 1 -通过将起点从上移到下,使该行再次消失



您会在箭头的每一侧做类似的事情,并适当地订购东西以获得期望的效果。


Background

Suppose I have a VectorDrawable that look like a top->down arrow:

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0">
    <path
        android:pathData="M20,12l-1.41,-1.41L13,16.17V4h-2v12.17l-5.58,-5.59L4,12l8,8 8,-8z"
        android:fillColor="#010101"/>
</vector>

I want to show an animation of it that looks like a fluid that it poured, so that first nothing is shown, then the top area, then also the mid area, and then the bottom. After all is shown, it begins to hide, so that the top gets hidden, and then the mid, and then the bottom.

Here's a sketch of what I mean:

The problem

There are some tutorials about VectorDrawable animations, and it seems they require a lot of vector understanding, without an easy way to do such a thing.

What I've found

I've found a tool to use for this, but I don't understand how to use it, and the examples link is currently broken :

https://romannurik.github.io/AndroidIconAnimator/

I've also found some tutorials about VectorDrawable animations in general, but I can't find this specific animation explanation:

http://www.androiddesignpatterns.com/2016/11/introduction-to-icon-animation-techniques.html

This link in particular has a clue about what I should use. I think I should use "trimPathStart", "trimPathEnd", "trimPathOffset", or maybe "clip-path" .

The example animation they have there shows that it might be it:

But I can't find how to do it.

The question

How can I apply such an animation on the VectorDrawable?

Will it work on old Android versions too, using the support library?


EDIT: I've succeeded animating the arrow, but it has 2 issues:

  1. Because it's a single path, it doesn't look well. It need to know how to split it into 3 paths, so that each will animate nicely.

  2. It seems all I use in the code is from API 21 and above. I did it by looking at the link I wrote before (here), and need to know how to support older versions.

Here's the code:

res/drawable/vector_animation.xml

<animated-vector
    xmlns:aapt="http://schemas.android.com/aapt"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_darkblue_arrow">

    <target android:name="a_stroke">
        <aapt:attr name="android:animation">
            <objectAnimator
                android:duration="5000"
                android:interpolator="@android:interpolator/fast_out_slow_in"
                android:propertyName="trimPathEnd"
                android:startOffset="1300"
                android:valueFrom="0"
                android:valueTo="1"/>
        </aapt:attr>
    </target>


</animated-vector>

res/drawable/vector.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:viewportHeight="24.0"
        android:viewportWidth="24.0">
    <path
        android:name="a_stroke"
        android:fillColor="#010101"
        android:pathData="M20,12l-1.41,-1.41L13,16.17V4h-2v12.17l-5.58,-5.59L4,12l8,8 8,-8z"/>
</vector>

res/layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:contentDescription="@null"
        android:src="@drawable/vector_animation"/>

</FrameLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final Animatable cursiveAvd = ((Animatable) ((ImageView) findViewById(R.id.imageView)).getDrawable());
        cursiveAvd.stop();
        cursiveAvd.start();
    }
}


EDIT: I made a simple 3-paths arrow VectorDrawable, and succeeded animating it.

Here's the VectorDrawable I created:

ic_drawing.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="210dp"
        android:height="297dp"
        android:viewportHeight="1052.3622"
        android:viewportWidth="744.0945">
    <path
        android:name="main_line"
        android:fillColor="#00000000"
        android:pathData="M742.6,9.7C313,-8.4 316.2,860.8 316.2,860.8"
        android:strokeAlpha="1"
        android:strokeColor="#000000"
        android:strokeLineCap="butt"
        android:strokeLineJoin="miter"
        android:strokeWidth="5.32507801"/>
    <path
        android:name="left_line"
        android:fillColor="#00000000"
        android:pathData="m314.3,846.6c-211.4,-254.3 -160,-294.3 -160,-294.3"
        android:strokeAlpha="1"
        android:strokeColor="#000000"
        android:strokeLineCap="butt"
        android:strokeLineJoin="miter"
        android:strokeWidth="5"/>
    <path
        android:name="right_line"
        android:fillColor="#00000000"
        android:pathData="M320,843.8C364.2,751.2 437.4,670.7 471.4,566.6"
        android:strokeAlpha="1"
        android:strokeColor="#000000"
        android:strokeLineCap="butt"
        android:strokeLineJoin="miter"
        android:strokeWidth="5"/>
</vector>

vector_animation2.xml

<animated-vector
    xmlns:aapt="http://schemas.android.com/aapt"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_drawing">

    <target android:name="main_line">
        <aapt:attr name="android:animation">
            <objectAnimator
                android:duration="5000"
                android:interpolator="@android:interpolator/fast_out_slow_in"
                android:propertyName="trimPathEnd"
                android:startOffset="1300"
                android:valueFrom="0"
                android:valueTo="1"/>
        </aapt:attr>
    </target>
    <target android:name="left_line">
        <aapt:attr name="android:animation">
            <objectAnimator
                android:startDelay="5000"
                android:duration="5000"
                android:interpolator="@android:interpolator/fast_out_slow_in"
                android:propertyName="trimPathEnd"
                android:startOffset="1300"
                android:valueFrom="0"
                android:valueTo="1"/>
        </aapt:attr>
    </target>
    <target android:name="right_line">
        <aapt:attr name="android:animation">
            <objectAnimator
                android:startDelay="5000"
                android:duration="5000"
                android:interpolator="@android:interpolator/fast_out_slow_in"
                android:propertyName="trimPathEnd"
                android:startOffset="1300"
                android:valueFrom="0"
                android:valueTo="1"/>
        </aapt:attr>
    </target>

</animated-vector>

So, it works nicely, but works only on newer versions of Android, and I still would like to know how to split existing VectorDrawable nicely, instead of creating a new one.

解决方案

There are a few ways to get a similar look, however not all are going to be backwards compatible using the support library. For that reason I'd recommend using trimPathStart and trimPathEnd.

I'll describe the approach I would take, rather than the final solution(can be time consuming!).

The first problem in getting started is that your original VectorDrawable isn't really suitable for this type of animation!

The drawable in the question describes the outline of the shape(ie. the nine lines outlining the arrow) and displays the fill. What would be better for our purposes would be to have a drawable made up of three lines where there is no fillColor and instead we set how the lines should display using strokeColor and strokeWidth.

This should be a simple VectorDrawable with three <path> elements: one for the vertical line, and one each for the sides of the arrow head.

Once you have this you can think about how you want your animation to look. trimPathStart and trimPathEnd should be values between 0 and 1 where 0 is the start of the path and 1 is the end. Consider the vertical line drawn from top to bottom:

trimPathStart="0" trimPathEnd="0" --we can't see the line

-> animate to

trimPathStart="0" trimPathEnd="1" --we've drawn the line from top to bottom

-> animate to

trimPathStart="1" trimPathEnd="1" --we've made the line disappear again by moving the starting point from top to bottom

You would do a similar thing with each side of the arrow and order things as appropriate to get your desired effect.

这篇关于如何以类似流体的方式为VectorDrawable设置动画?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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