向Android应用添加基于物理的动画

感觉流畅和逼真的动画倾向于使用户界面更具吸引力。 难怪Material Design如此重视它们!

但是,如果您曾经尝试创建此类动画,您就会知道Android SDK提供的简单动画师和插值器通常不够好。 因此,Android支持库的最新修订版附带了一个名为Dynamic Animation的物理模块。

使用动态动画,您可以创建基于物理的动画,这些动画与现实世界中对象的运动极为相似。 您还可以使他们实时响应用户的操作。 在本教程中,我将向您展示如何创建一些此类动画。

先决条件

要继续进行,请确保您具有以下条件:

1.添加依赖项

为了能够在项目中使用动态动画,必须将其作为implementation依赖项添加到app模块的build.gradle文件中:

implementation 'com.android.support:support-dynamic-animation:26.0.0-beta2'

在本教程中,我们将为ImageView小部件设置动画。 当然,它必须显示一些图像,因此打开Vector Assets Studio,并在项目中添加以下“材质”图标:

  • 情绪中立
  • 情绪非常满意

它们是这样的:

两个材料图标

为了获得最佳效果,建议您将图标的大小设置为56 x 56 dp

2.创建文件动画

当您在现实世界中猛扑一个物体时,就会赋予它巨大的动力。 由于动量不过是质量和速度的乘积,因此对象最初将具有较高的速度。 但是,由于摩擦,它逐渐减速直到完全停止移动。 使用Dynamic Animation的FlingAnimation类,可以在应用程序内部模拟此行为。

为了演示起见,让我们现在创建一个包含可拖动ImageView窗口小部件的布局,显示ic_sentiment_neutral_black_56dp图标,然后用户可以按下Button窗口小部件以触发该拖动动画。 如果将它们都放置在RelativeLayout小部件中,则布局XML文件将如下所示:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="16dp">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_sentiment_neutral_black_56dp"
        android:id="@+id/emoji"
        android:layout_centerInParent="true"
        />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Fling"
        android:id="@+id/flinger"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:onClick="flingIt" />
        
</RelativeLayout>

在上面的代码中,您可以看到Button小部件具有onClick属性。 通过单击Android Studio旁边显示的红色灯泡图标,可以在Activity类内生成关联的点击事件处理程序:

public void flingIt(View view) {
    // more code here
}

现在,您可以使用其构造函数创建FlingAnimation类的新实例,该实例需要一个View对象和一个可设置动画的属性的名称。 动态动画支持多种可动画设置的属性,例如缩放,平移,旋转和Alpha。

以下代码显示了如何创建一个FlingAnimation实例,该实例可以使布局的ImageView的X坐标动画化:

// Get a reference to the view
ImageView emoji = (ImageView)findViewById(R.id.emoji);

// Pass it to the constructor
FlingAnimation flingAnimation
        = new FlingAnimation(emoji, DynamicAnimation.X);

默认情况下,将FlingAnimation实例配置为使用0像素/秒作为其初始速度。 这意味着动画一开始就将停止。 为了模拟现实的猛击,您必须始终记住调用setStartVelocity()方法并将较大的值传递给该方法。

此外,您必须了解没有摩擦,动画将不会停止。 因此,您还必须调用setFriction()方法并将少量传递给它。

下面的代码配置FlingAnimation实例,以使ImageView不会超出用户屏幕的范围:

flingAnimation.setStartVelocity(500f);
flingAnimation.setFriction(0.5f);

此时,您可以简单地调用start()方法来启动动画。

flingAnimation.start();

如果您现在运行该应用程序并按按钮,则应该能够看到猛击动画。

值得注意的是,在创建基于物理的动画时,您无需指定持续时间或最终值-当动画意识到其目标对象未在用户屏幕上显示任何可见的运动时,动画将自动停止。

3.模拟弹簧

动态动画使您可以轻松地将弹簧动力学添加到动画中。 换句话说,它可以帮助您创建动画,使小部件以自然的方式弹跳,拉伸和挤压。

为简单起见,让我们现在重新使用布局的ImageView并对其应用基于spring的动画。 但是,要允许用户启动动画,您需要向布局添加另一个Button小部件。

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Bounce"
    android:layout_alignParentTop="true"
    android:layout_alignParentRight="true"
    android:onClick="bounce" />

要创建基于弹簧的动画,必须使用SpringAnimation类。 它的构造函数也希望有一个View对象和一个可设置动画的属性。 以下代码创建一个SpringAnimation实例,该实例配置为使ImageView的x坐标动画化:

// Get a reference to the view
final ImageView emoji = (ImageView)findViewById(R.id.emoji);

// Pass it to the constructor
SpringAnimation springAnimation
        = new SpringAnimation(emoji, DynamicAnimation.X);

要控制基于弹簧的动画的行为,您需要一个弹簧。 您可以使用SpringForce类创建一个,该类允许您指定弹簧的静止位置,其阻尼比和刚度。 您可以将阻尼比视为一个常数,就像摩擦一样,它可以使动画变慢直到停止。 另一方面,刚度指定拉伸弹簧需要多少力。

如果听起来有点太复杂了,那么好消息是SpringForce类提供了几个直观命名的常量,您可以使用它们来快速配置spring。 例如,以下代码创建了一个既有弹性又非常灵活的弹簧:

SpringForce springForce = new SpringForce();
springForce.setFinalPosition(emoji.getX());
springForce.setDampingRatio(SpringForce.DAMPING_RATIO_HIGH_BOUNCY);
springForce.setStiffness(SpringForce.STIFFNESS_LOW);

在上面的代码中,您可以看到我们已经将弹簧的最终静止位置的值设置为ImageView的初始X坐标。 通过这种配置,您可以想象ImageView固定在一条不可见的紧橡皮筋上,该橡皮筋在每次移动时都会将ImageView快速拉回到其原始位置。

现在,您可以使用setSpring()方法将spring与SpringAnimation实例相关联。

springAnimation.setSpring(springForce);

最后,在开始动画之前,必须确保使用setStartVelocity()方法为其赋予较大的初始速度。

springAnimation.setStartVelocity(2000f);
springAnimation.start();

如果您现在运行该应用程序,应该会看到类似以下内容:

4.听动画事件

使用动态动画库创建的动画必须始终从UI线程启动。 您还可以确保一旦调用start()方法,它将立即start() 。 但是,它异步运行。 因此,如果希望在结束时收到通知,则必须使用addEndListener()方法将OnAnimationEndListener对象附加到该对象。

要查看侦听器的运行情况,让我们更改在上一步中基于弹簧的动画每次开始和结束时ImageView显示的“材质”图标。 我建议您在动画开始时使用ic_sentiment_very_satisfied_black_56dp图标,在动画结束时使用ic_sentiment_neutral_black_56dp图标。 以下代码向您展示了如何:

// Change icon before animation starts
emoji.setImageResource(
        R.drawable.ic_sentiment_very_satisfied_black_56dp);

// Start animation
springAnimation.start();

springAnimation.addEndListener(
    new DynamicAnimation.OnAnimationEndListener() {
        @Override
        public void onAnimationEnd(DynamicAnimation animation, 
                                boolean canceled,
                                float value, float velocity) {
            // Change icon after animation ends
            emoji.setImageResource(
                    R.drawable.ic_sentiment_neutral_black_56dp);
        }
});

使用上面的代码,动画将如下所示:

5.动画多个属性

FlingAnimationSpringAnimation类的构造函数只能接受一个可设置动画的属性。 如果要同时为多个属性设置动画,则可以创建可能繁琐的类的多个实例,也可以创建一个新的自定义属性来封装所有所需的属性。

要创建自定义的动画属性,必须创建FloatPropertyCompat类的子类,该类具有两个抽象方法: setValue()getValue() 。 您可能已经猜到了,您可以在setValue()方法中更新所有所需的可设置动画的属性的值。 但是,在getValue()方法内部,必须仅返回任何一个属性的当前值。 由于此限制,通常必须确保封装属性的值彼此之间不是完全独立的。

例如,下面的代码向您展示如何创建一个名为scale的自定义属性,该属性可以统一为小部件的SCALE_XSCALE_Y属性设置动画:

FloatPropertyCompat<View> scale = 
    	new FloatPropertyCompat<View>("scale") {
			@Override
			public float getValue(View view) {
				// return the value of any one property
				return view.getScaleX();
			}

			@Override
			public void setValue(View view, float value) {
				// Apply the same value to two properties
				view.setScaleX(value);
				view.setScaleY(value);
			}
		};

现在,自定义属性已准备就绪,您可以像使用任何其他可设置动画的属性一样使用它。 以下代码显示了如何使用它创建SpringAnimation对象:

SpringAnimation stretchAnimation =
            new SpringAnimation(emoji, scale);

创建使用自定义属性的动画时,最好还调用setMinimumVisibleChange()方法并向其传递有意义的值,以确保动画不会消耗太多CPU周期。 对于缩放小部件的动画,可以使用以下代码:

stretchAnimation.setMinimumVisibleChange(
                DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE);

自定义属性动画如下所示:

结论

您现在知道了使用动态动画的基础知识。 使用您在本教程中学到的技术,即使您对牛顿物理学的知识很少,也可以在几分钟内创建令人信服的基于物理学的动画。

翻译自: https://code.tutsplus.com/tutorials/adding-physics-based-animations-to-android-apps--cms-29053

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值