如何以类似流体的方式为VectorDrawable设置动画? [英] How to animate a VectorDrawable in a fluid-like manner?
问题描述
背景
假设我有一个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个问题:
-
由于它是一条路径,所以看起来不太好。它需要知道如何将其分为3条路径,以便每条路径都具有良好的动画效果。
-
似乎我在代码中使用的都是来自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:
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.
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屋!