博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android Spring动画–基于物理的动画
阅读量:2532 次
发布时间:2019-05-11

本文共 18071 字,大约阅读时间需要 60 分钟。

In this tutorial, we’ll implement Spring based animations that are a part of the support library in our android application. Spring Animation is part of Android Physics Based animation API.

在本教程中,我们将实现基于Spring的动画,这些动画是我们android应用程序中支持库的一部分。 Spring Animation是Android Physics Based动画API的一部分。

Android Spring动画 (Android Spring Animation)

Android Spring Animation animates views based on spring properties: dampness, stiffness, bouncy.

Android Spring Animation会根据弹簧特性(潮湿度,刚度,弹性)为视图设置动画。

Spring Animation can be implemented in your project once you add the following dependency in your dependencies section in the build.gradle:

只要在build.gradle的“ dependencies”部分中添加以下依赖项,即可在项目中实现Spring Animation:

dependencies {      implementation 'com.android.support:support-dynamic-animation:27.1.1'  }

To create a Spring Animation, we need to create a SpringAnimation class and pass along the animation type – translation/rotation/scaling along with the final position of the view and velocity of the animation.

要创建Spring动画,我们需要创建一个SpringAnimation类并传递动画类型- 平移/旋转/缩放以及动画的最终位置和动画速度。

We can also set additional properties i.e. Stiffness and Damping.

我们还可以设置其他属性,例如StiffnessDamping

A spring in real life bounces when it returns to its final position.

现实生活中的弹簧回到其最终位置时会反弹。

The Higher the Damping and lower the stiffness the more it would oscillate/bounce.

阻尼越高,刚度越低,则其振荡/反弹越多。

To animate a view the final position of the View must always be assigned before.

要为视图设置动画,必须始终在之前分配视图的最终位置。

To start the animation we invoke either start() or animateToFinalPosition(Float finalPosition). The latter updates the final position and calls start() internally.

要启动动画,我们调用start()animateToFinalPosition(Float finalPosition) 。 后者更新最终位置并在内部调用start()。

Besides, updateListener and removeListener are the respective listeners for listening to updates and removing the listener when it’s no longer needed.

此外,updateListener和removeListener分别是侦听器,用于侦听更新并在不再需要时删除侦听器。

简单的春天动画 (Simple Spring Animation)

In java, to set spring animation on any view we do:

在Java中,要在任何视图上设置Spring动画,我们可以:

SpringAnimation springAnim = new SpringAnimation(fab, SpringAnimation.TRANSLATION_Y);SpringForce springForce = new SpringForce();springForce.setFinalPosition(-200f);springForce.setStiffness(SpringForce.STIFFNESS_LOW);springForce.setDampingRatio(SpringForce.DAMPING_RATIO_HIGH_BOUNCY);springAnim.setSpring(springForce);springAnim.start();

The position must be a floating value. A negative in the Y direction is upwards. A negative in the X direction is leftwards. fab is the view instance over which the animation happens.

该头寸必须为浮动值。 Y方向的负数是向上的。 X方向的负数向左。 fab是动画发生的视图实例。

像运动一样拖动视图弹簧 (Dragging View Spring Like Movement)

We can also drag a certain view and see it bounce like a spring. For this, we need to set the touch listener on the view.

我们还可以拖动某个视图,然后看到它像春天一样反弹。 为此,我们需要在视图上设置触摸监听器。

private SpringAnimation xAnimation;private SpringAnimation yAnimation;ImageView imageView;private void imageViewDragSpringAnimation() {        imageView.getViewTreeObserver().addOnGlobalLayoutListener(globalLayoutListener);        imageView.setOnTouchListener(touchListener);    }    private ViewTreeObserver.OnGlobalLayoutListener globalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {        @Override        public void onGlobalLayout() {            xAnimation = createSpringAnimation(imageView, SpringAnimation.X, imageView.getX(),                    SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_HIGH_BOUNCY);            yAnimation = createSpringAnimation(imageView, SpringAnimation.Y, imageView.getY(),                    SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_HIGH_BOUNCY);        }    };    private View.OnTouchListener touchListener = new View.OnTouchListener() {        @Override        public boolean onTouch(View v, MotionEvent event) {            switch (event.getActionMasked()) {                case MotionEvent.ACTION_DOWN:                    dX = v.getX() - event.getRawX();                    dY = v.getY() - event.getRawY();                    // cancel animations                    xAnimation.cancel();                    yAnimation.cancel();                    break;                case MotionEvent.ACTION_MOVE:                    imageView.animate()                            .x(event.getRawX() + dX)                            .y(event.getRawY() + dY)                            .setDuration(0)                            .start();                    break;                case MotionEvent.ACTION_UP:                    xAnimation.start();                    yAnimation.start();                    break;            }            return true;        }    };    public SpringAnimation createSpringAnimation(View view,                                                 DynamicAnimation.ViewProperty property,                                                 float finalPosition,                                                 float stiffness,                                                 float dampingRatio) {        SpringAnimation animation = new SpringAnimation(view, property);        SpringForce springForce = new SpringForce(finalPosition);        springForce.setStiffness(stiffness);        springForce.setDampingRatio(dampingRatio);        animation.setSpring(springForce);        return animation;    }

The GlobalLayoutListener is triggered when the ImageView is displayed on the screen with its width and height finalized.

当ImageView显示在屏幕上并确定其宽度和高度时,将触发GlobalLayoutListener

Once that is done, we set the final position of the SpringAnimation to the current X and Y coordinates of the ImageView at rest.

完成此操作后,我们将SpringAnimation的最终位置设置为静止时ImageView的当前X和Y坐标。

onTouchListener is used to drag the view on the screen.

onTouchListener用于在屏幕上拖动视图。

When the drag starts we capture the difference between view’s top left corner and touch point and on moving the view, the difference is added to the current position.

当拖动开始时,我们捕获了视图左上角和触摸点之间的差异,并且在移动视图时,差异被添加到了当前位置。

When the drag stops the SpringAnimation is canceled and the view returns to its original position.

当拖动停止时,SpringAnimation被取消,视图返回其原始位置。

连锁春天动画 (Chained Spring Animation)

In this type of animation, we group together views to make them animate together.

在这种动画中,我们将视图组合在一起以使它们动画在一起。

Each would animate differently depending on its Spring Properties.

每个动画的动画取决于其弹簧属性。

In the following section, we’ll implement each of the above types of Spring Animations in our Android Studio Project.

在下一节中,我们将在Android Studio项目中实现上述每种类型的Spring动画。

项目结构 (Project Structure)

Android Spring动画代码 (Android Spring Animation Code)

The code for the activity_main.xml layout is given below:

下面给出了activity_main.xml布局的代码:

The code for the content_main.xml layout is given below:

下面给出了content_main.xml布局的代码:

We’ve created six . Three for simple Spring Animation and three for the chained spring animations.

我们已经创建了六个 。 三个用于简单的Spring动画,三个用于链接的Spring动画。

The sole ImageView would be used to show how dragging the view causes the Spring Animation.

唯一的ImageView将用于显示拖动视图如何导致Spring Animation。

The code for the MainActivity.java is as follows:

MainActivity.java的代码如下:

package com.journaldev.androidspringanimations;import android.os.Bundle;import android.support.animation.DynamicAnimation;import android.support.animation.SpringAnimation;import android.support.animation.SpringForce;import android.support.design.widget.FloatingActionButton;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.Toolbar;import android.view.MotionEvent;import android.view.View;import android.view.Menu;import android.view.MenuItem;import android.view.ViewGroup;import android.view.ViewTreeObserver;import android.widget.ImageView;public class MainActivity extends AppCompatActivity {    private SpringAnimation xAnimation;    private SpringAnimation yAnimation;    ImageView imageView;    private float dX;    private float dY;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Toolbar toolbar = findViewById(R.id.toolbar);        setSupportActionBar(toolbar);        imageViewDragSpringAnimation();        chainedSpringAnimation();        final FloatingActionButton fab = findViewById(R.id.fab);        final FloatingActionButton fab2 = findViewById(R.id.fab2);        final FloatingActionButton fab3 = findViewById(R.id.fab3);        fab.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                SpringAnimation springAnim = new SpringAnimation(fab, SpringAnimation.TRANSLATION_Y);                SpringForce springForce = new SpringForce();                springForce.setFinalPosition(-200f);                springForce.setStiffness(SpringForce.STIFFNESS_LOW);                springForce.setDampingRatio(SpringForce.DAMPING_RATIO_HIGH_BOUNCY);                springAnim.setSpring(springForce);                springAnim.start();            }        });        fab2.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                final SpringAnimation springAnim = new SpringAnimation(fab2, SpringAnimation.TRANSLATION_Y);                SpringForce springForce = new SpringForce();                springForce.setFinalPosition(-200f);                springForce.setStiffness(SpringForce.STIFFNESS_HIGH);                springForce.setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY);                springAnim.setSpring(springForce);                springAnim.start();            }        });        fab3.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                final SpringAnimation springAnim = new SpringAnimation(fab3, SpringAnimation.TRANSLATION_X);                SpringForce springForce = new SpringForce();                springForce.setFinalPosition(-200f);                springForce.setStiffness(SpringForce.STIFFNESS_MEDIUM);                springForce.setDampingRatio(SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY);                springAnim.setSpring(springForce);                springAnim.start();            }        });    }    @Override    public boolean onCreateOptionsMenu(Menu menu) {        // Inflate the menu; this adds items to the action bar if it is present.        getMenuInflater().inflate(R.menu.menu_main, menu);        return true;    }    @Override    public boolean onOptionsItemSelected(MenuItem item) {        // Handle action bar item clicks here. The action bar will        // automatically handle clicks on the Home/Up button, so long        // as you specify a parent activity in AndroidManifest.xml.        int id = item.getItemId();        //noinspection SimplifiableIfStatement        if (id == R.id.action_settings) {            return true;        }        return super.onOptionsItemSelected(item);    }    private void imageViewDragSpringAnimation() {        imageView = findViewById(R.id.imageView);        imageView.getViewTreeObserver().addOnGlobalLayoutListener(globalLayoutListener);        imageView.setOnTouchListener(touchListener);    }    private ViewTreeObserver.OnGlobalLayoutListener globalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {        @Override        public void onGlobalLayout() {            xAnimation = createSpringAnimation(imageView, SpringAnimation.X, imageView.getX(),                    SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_HIGH_BOUNCY);            yAnimation = createSpringAnimation(imageView, SpringAnimation.Y, imageView.getY(),                    SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_HIGH_BOUNCY);        }    };    private View.OnTouchListener touchListener = new View.OnTouchListener() {        @Override        public boolean onTouch(View v, MotionEvent event) {            switch (event.getActionMasked()) {                case MotionEvent.ACTION_DOWN:                    // capture the difference between view's top left corner and touch point                    dX = v.getX() - event.getRawX();                    dY = v.getY() - event.getRawY();                    // cancel animations                    xAnimation.cancel();                    yAnimation.cancel();                    break;                case MotionEvent.ACTION_MOVE:                    //  a different approach would be to change the view's LayoutParams.                    imageView.animate()                            .x(event.getRawX() + dX)                            .y(event.getRawY() + dY)                            .setDuration(0)                            .start();                    break;                case MotionEvent.ACTION_UP:                    xAnimation.start();                    yAnimation.start();                    break;            }            return true;        }    };    public SpringAnimation createSpringAnimation(View view,                                                 DynamicAnimation.ViewProperty property,                                                 float finalPosition,                                                 float stiffness,                                                 float dampingRatio) {        SpringAnimation animation = new SpringAnimation(view, property);        SpringForce springForce = new SpringForce(finalPosition);        springForce.setStiffness(stiffness);        springForce.setDampingRatio(dampingRatio);        animation.setSpring(springForce);        return animation;    }    public SpringAnimation createSpringAnimation(View view,                                                 DynamicAnimation.ViewProperty property,                                                 float stiffness,                                                 float dampingRatio) {        SpringAnimation animation = new SpringAnimation(view, property);        SpringForce springForce = new SpringForce();        springForce.setStiffness(stiffness);        springForce.setDampingRatio(dampingRatio);        animation.setSpring(springForce);        return animation;    }    private void chainedSpringAnimation() {        final FloatingActionButton fab4 = findViewById(R.id.fab4);        final FloatingActionButton fab5 = findViewById(R.id.fab5);        final FloatingActionButton fab6 = findViewById(R.id.fab6);        final SpringAnimation firstXAnim = createSpringAnimation(fab5, DynamicAnimation.X, SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_HIGH_BOUNCY);        final SpringAnimation firstYAnim = createSpringAnimation(fab5, DynamicAnimation.Y, SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_HIGH_BOUNCY);        final SpringAnimation secondXAnim = createSpringAnimation(fab6, DynamicAnimation.X, SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_HIGH_BOUNCY);        final SpringAnimation secondYAnim = createSpringAnimation(fab6, DynamicAnimation.Y, SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_HIGH_BOUNCY);        final ViewGroup.MarginLayoutParams fab5Params = (ViewGroup.MarginLayoutParams) fab5.getLayoutParams();        final ViewGroup.MarginLayoutParams fab6Params = (ViewGroup.MarginLayoutParams) fab6.getLayoutParams();        firstXAnim.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {            @Override            public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float v, float v1) {                secondXAnim.animateToFinalPosition(v + ((fab5.getWidth() -                        fab6.getWidth()) / 2));            }        });        firstYAnim.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {            @Override            public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float v, float v1) {                secondYAnim.animateToFinalPosition(v + fab5.getHeight() +                        fab6Params.topMargin);            }        });        fab4.setOnTouchListener(new View.OnTouchListener() {            @Override            public boolean onTouch(View view, MotionEvent motionEvent) {                switch (motionEvent.getActionMasked()) {                    case MotionEvent.ACTION_DOWN:                        dX = view.getX() - motionEvent.getRawX();                        dY = view.getY() - motionEvent.getRawY();                        break;                    case MotionEvent.ACTION_MOVE:                        float newX = motionEvent.getRawX() + dX;                        float newY = motionEvent.getRawY() + dY;                        view.animate().x(newX).y(newY).setDuration(0).start();                        firstXAnim.animateToFinalPosition(newX + ((fab4.getWidth() -                                fab5.getWidth()) / 2));                        firstYAnim.animateToFinalPosition(newY + fab4.getHeight() +                                fab5Params.topMargin);                        break;                }                return true;            }        });    }}

The first type of Simple Spring Animation is performed on fab, fab2, and fab3. One of them would translate horizontally.

第一类简单弹簧动画是在fab,fab2和fab3上执行的。 其中之一可以水平平移。

imageViewDragSpringAnimation() triggers the second type of animation as we had discussed before.

imageViewDragSpringAnimation()会触发第二种动画类型。

chainedSpringAnimation() method triggers the third type.

chainedSpringAnimation()方法触发第三种类型。

In the chainedSpringAnimation we drag the first fab i.e. fab4 which would trigger animation update listeners of the X and Y Spring Animation. In each of these listeners, we trigger the Spring Animations for the other two Floating Action Button thus chaining them.

chainedSpringAnimation我们拖动第一个fab,即fab4 ,它将触发X和Y Spring Animation的动画更新侦听器。 在每个这些侦听器中,我们触发其他两个Floating Action Button的Spring动画,从而将它们链接起来。

The output of the above application in action is given below:

上面应用程序的输出如下:

This brings an end to this tutorial. You can download the project from the link below:

本教程到此结束。 您可以从下面的链接下载项目:

Reference:

参考:

翻译自:

转载地址:http://wyqzd.baihongyu.com/

你可能感兴趣的文章
java基础之集合:List Set Map的概述以及使用场景
查看>>
Python 线程 进程 协程
查看>>
iOS语言中的KVO机制
查看>>
excel第一次打开报错 向程序发送命令时出错 多种解决办法含终极解决方法
查看>>
响应式web设计之CSS3 Media Queries
查看>>
实验三
查看>>
机器码和字节码
查看>>
环形菜单的实现
查看>>
【解决Chrome浏览器和IE浏览器上传附件兼容的问题 -- Chrome关闭flash后,uploadify插件不可用的解决办法】...
查看>>
34 帧动画
查看>>
二次剩余及欧拉准则
查看>>
Centos 7 Mysql 最大连接数超了问题解决
查看>>
thymeleaf 自定义标签
查看>>
关于WordCount的作业
查看>>
C6748和音频ADC连接时候的TDM以及I2S格式问题
查看>>
UIView的layoutSubviews,initWithFrame,initWithCoder方法
查看>>
STM32+IAP方案 实现网络升级应用固件
查看>>
用74HC165读8个按键状态
查看>>
jpg转bmp(使用libjpeg)
查看>>
linear-gradient常用实现效果
查看>>