分类:C#、Android、VS2015;
创建日期:2016-03-21
Android 提供了以下三种创建动画的方式:
注意:虽然这三种动画都可用,但只要有可能,都应该优先考虑用属性动画来实现。另外,动画虽然能吸引人,但不要滥用,否则只会适得其反。
1、画板动画(Drawable Animations)
Drawable Animations提供了按帧播放的简单动画API,在其他实现技术中一般将其称为帧动画(Frame Animations)。这种动画的播放效果非常类似电影或卡通(cartoon)漫画。
帧动画是通过顺序播放图片来产生动画效果的,下图通过顺序播放6张图片实现一个人跳起来的动画效果:
控制动画序列的画板资源(XML文件)通常保存在应用程序的/Resource/drawable文件夹中,文件中用<animation-list>元素作为根元素,用<item>元素定义每一帧。
例如,在/Resource/drawable/ch2103DrawableAnimDemo.xml文件中定义动画序列:
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/a01" android:duration="100" />
<item android:drawable="@drawable/a02" android:duration="100" />
<item android:drawable="@drawable/a03" android:duration="100" />
<item android:drawable="@drawable/a04" android:duration="100" />
<item android:drawable="@drawable/a05" android:duration="100" />
<item android:drawable="@drawable/a06" android:duration="100" />
</animation-list>
此动画包含六个帧。其中,a01~a06是图片文件,android:duration属性声明每个帧显示的时间。定义动画序列以后,只需要在布局文件中指定该文件,Android就会自动按顺序加载和显示动画。
2、视图动画(View Animations)
在Android系统中,视图动画(或者叫补间动画)有4种表现方式:渐变、缩放、平移、旋转。利用View动画能完成一系列诸如位置、大小、不透明度、旋转等简单的变化。例如对程序中的某个ImageView实现动画处理等。
View动画位于Android.View.Animation命名空间中,在代码中可通过下面的方法对View对象进行动画处理:
AlphaAnimation:控制不透明度变化的动画类
Rotate Animation:控制旋转的动画类
ScaleAnimation:控制缩放变化的动画类
TranslateAnimation:控制平移变化的动画类
AnimationSet:控制动画属性的集合类
动画变换文件一般保存在/Resources/anim文件夹中。另外,虽然此API是早期版本提供的,但是由于它的简单性,因此仍然有用。
注意:保存在/Resources/anim文件夹中的XML文件是声明View动画的首选办法,因为这种方式更易于阅读和维护。该XML文件必须用以下元素之一作为根元素:
默认情况下,Android会同时应用该XML文件中的所有动画。要使动画按指定的顺序变化,将android:startOffset属性设置在上面定义的元素之一即可。
也可以内插器改变动画速率,如加速、重复、减速等动画效果:
具体用法见本节示例中的“视图动画示例”。在这个例子中,动画效果是先将图像沿水平和垂直方向缩放,然后将图像逆时针旋转45度同时缩小图像的大小。
3、属性动画(Property Animations)
这种动画可对任何对象的属性进行处理(包括View),是首选的执行动画的方式,即使动画对象不可见也一样能对其进行处理。
属性动画API的灵活性在于还能将动画封装在不同的类中,使代码共享更加方便。
所有属性动画都是通过Animator子类的实例来创建:
使用动画是,可能还需要下面的特殊类:
如果正在进行动画处理的属性不是float、int或Color,可通过实现ITypeEvaluator接口创建他们自己的计算类型。
(1)ValueAnimator
通过调用下面的方法之一,可获取得ValueAnimator的实例:
下面的代码演示如何将值从 0 到 100进行动画处理,动画持续时间为1000毫秒。
ValueAnimator animator = ValueAnimator.OfInt(0, 100);
animator.SetDuration(1000);
animator.Start();
但是,仅有这些代码还不够,这是因为虽然执行了动画但是并没有将目标更新为新的值,因此还需要引入相关的事件:
MyCustomObject myObj = new MyCustomObject();
myObj.SomeIntegerValue = -1;
animator.Update += (object sender, ValueAnimator.AnimatorUpdateEventArgs e) =>
{
int newValue = (int) e.Animation.AnimatedValue;
// Apply this new value to the object being animated.
myObj.SomeIntegerValue = newValue;
};
(2)ObjectAnimator
ObjectAnimator是ViewAnimator的子类,它将计时引擎和ValueAnimator结合在一起实现动画。例如:
MyCustomObject myObj = new MyCustomObject();
myObj.SomeIntegerValue = -1;
ObjectAnimator animator = ObjectAnimator.OfFloat(myObj, "SomeIntegerValue”, 0, 100);
animator.SetDuration(1000);
animator.Start();
与前面的代码相比,这样做可减少代码量。
1、运行截图
2、设计步骤
(1)添加图片
在Drawable文件夹下添加6个图片(ch2103asteroid01.png~ch2103asteroid06.png),这些图片用于演示帧动画的用法。
然后再添加一个ch2103ship.png图片,该图片用于演示视图动画的用法。
(2)添加ch2103DrawableAnimDemo.xml
在Resources/Drawable文件夹下添加该文件。
<?xml version="1.0" encoding="UTF-8" ?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" > <item android:drawable="@drawable/ch2103asteroid01" android:duration="100" /> <item android:drawable="@drawable/ch2103asteroid02" android:duration="100" /> <item android:drawable="@drawable/ch2103asteroid03" android:duration="100" /> <item android:drawable="@drawable/ch2103asteroid04" android:duration="100" /> <item android:drawable="@drawable/ch2103asteroid05" android:duration="100" /> <item android:drawable="@drawable/ch2103asteroid06" android:duration="100" /> </animation-list>
(3)添加ch2103ViewAnimDemo.xml
在Resources/anim文件夹下添加该文件。
<?xml version="1.0" encoding="utf-8" ?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false"> <scale android:interpolator="@android:anim/accelerate_decelerate_interpolator" android:fromXScale="1.0" android:toXScale="1.4" android:fromYScale="1.0" android:toYScale="0.6" android:pivotX="50%" android:pivotY="50%" android:fillEnabled="true" android:fillAfter="false" android:duration="700" /> <set android:interpolator="@android:anim/accelerate_interpolator"> <scale android:fromXScale="1.4" android:toXScale="0.0" android:fromYScale="0.6" android:toYScale="0.0" android:pivotX="50%" android:pivotY="50%" android:fillEnabled="true" android:fillBefore="false" android:fillAfter="true" android:startOffset="700" android:duration="400" /> <rotate android:fromDegrees="0" android:toDegrees="-45" android:toYScale="0.0" android:pivotX="50%" android:pivotY="50%" android:fillEnabled="true" android:fillBefore="false" android:fillAfter="true" android:startOffset="700" android:duration="400" /> </set> </set>
(4)添加ch2103Main.axml
在Resources/layout文件夹下添加该文件。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:minWidth="25px" android:minHeight="25px"> <TextView android:text="画板动画示例" android:textAppearance="?android:attr/textAppearanceSmall" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center" android:background="@color/myGray" android:layout_marginTop="5dp" /> <ImageView android:src="@android:drawable/ic_menu_gallery" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/ch2103_imageView_DrawableDemo" android:layout_marginTop="5dp" /> <TextView android:text="视图动画示例" android:textAppearance="?android:attr/textAppearanceSmall" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center" android:background="@color/myGray" android:layout_marginTop="5dp" /> <ImageView android:src="@android:drawable/ic_menu_gallery" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/ch2103_imageView_ViewDemo" android:layout_marginLeft="20dp" android:layout_marginTop="5dp" /> <Button android:text="开始" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/ch2103_btnViewDemoStart" android:layout_gravity="center" /> <TextView android:text="属性动画示例(拖放滑动条观察进度条动画)" android:textAppearance="?android:attr/textAppearanceSmall" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center" android:background="@color/myGray" android:layout_marginTop="5dp" /> <FrameLayout android:minWidth="25px" android:minHeight="35px" android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/frameLayout1" android:layout_marginTop="15dp" android:layout_marginBottom="5dp"> <MyDemos.SrcDemos.ch2103MyView android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:id="@+id/ch2103myview1" /> </FrameLayout> <SeekBar android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/ch2103seekBar1" android:max="100" android:progress="50" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginTop="10dp" /> </LinearLayout>
(5)添加ch2103MyView.cs
using System; using Android.Content; using Android.Views; using Android.Graphics; using Android.Util; using Android.Animation; namespace MyDemos.SrcDemos { /// <summary> /// 演示进度条动画控制的基本用法 /// </summary> public class ch2103MyView : View { private const int DefaultHeight = 20; private const int DefaultWidth = 120; private Paint mNegativePaint; private double mPosition = 0.5; private Paint mPositivePaint; public ch2103MyView(Context context, IAttributeSet attrs) : this(context, attrs, 0) { Initialize(); } public ch2103MyView(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle) { Initialize(); } public double CurrentValue { get { return mPosition; } set { mPosition = Math.Max(0f, Math.Min(value, 1f)); Invalidate(); } } public void SetCurentValue(double value, bool animate) { if (!animate) { CurrentValue = value; return; } ValueAnimator animator = ValueAnimator.OfFloat((float)mPosition, (float)Math.Max(0f, Math.Min(value, 1f))); animator.SetDuration(500); animator.Update += (sender, e) => CurrentValue = (double)e.Animation.AnimatedValue; animator.Start(); } protected override void OnDraw(Canvas canvas) { base.OnDraw(canvas); float middle = canvas.Width * (float)mPosition; canvas.DrawPaint(mNegativePaint); canvas.DrawRect(0, 0, middle, canvas.Height, mPositivePaint); } protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.GetSize(widthMeasureSpec); SetMeasuredDimension(width < DefaultWidth ? DefaultWidth : width, DefaultHeight); } private void Initialize() { mPositivePaint = new Paint { AntiAlias = true, Color = Color.Rgb(0x99, 0xcc, 0), }; mPositivePaint.SetStyle(Paint.Style.FillAndStroke); mNegativePaint = new Paint { AntiAlias = true, Color = Color.Rgb(0xff, 0x44, 0x44) }; mNegativePaint.SetStyle(Paint.Style.FillAndStroke); } } }
(6)添加ch2103MainActivity.cs
using Android.App; using Android.OS; using Android.Widget; using Android.Views.Animations; namespace MyDemos.SrcDemos { [Activity(Label = "【例21-3】动画基本用法")] public class ch2103MainActivity : Activity { protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.ch2103Main); //画板动画Demo var img1 = FindViewById<ImageView>(Resource.Id.ch2103_imageView_DrawableDemo); img1.SetImageResource(Resource.Drawable.ch2103DrawableAnimDemo); //视图动画Demo var btn1 = FindViewById<Button>(Resource.Id.ch2103_btnViewDemoStart); btn1.Click += (sender, args) => { Animation animation = AnimationUtils.LoadAnimation(this, Resource.Animation.ch2103ViewAnimDemo); var img2 = FindViewById<ImageView>(Resource.Id.ch2103_imageView_ViewDemo); img2.SetImageResource(Resource.Drawable.ch2103ship); img2.StartAnimation(animation); }; //属性动画Demo var myView = FindViewById<ch2103MyView>(Resource.Id.ch2103myview1); var seekBar = FindViewById<SeekBar>(Resource.Id.ch2103seekBar1); seekBar.StopTrackingTouch += (sender, args) => { double currentValue = ((double)seekBar.Progress) / seekBar.Max; myView.SetCurentValue(currentValue, true); }; } } }