学习资料
- Android动画
- Android的几种动画定义与使用
- 百度翻译
- Android中getX(),getY(),getTop,getRawY()等的区别
简介
- Android基础之动画(上)中学习了补间动画和帧动画。
- 这篇就讲属性动画和过渡动画
属性动画(PropertyAnimation)
- 作用对象:任意 Java 对象,不再局限于 视图View对象;实现的动画效果:可自定义各种动画效果,不再局限于4种基本变换:平移、旋转、缩放 & 透明度
- 主要特点是,属性动画是改变了动画对象的属性来实现动画的,比如平移是真的改变了对象的坐标信息的。
- 和其他动画一样,也可以代码实现和xml文件实现。
使用
xml文件实现动画
- 使用xml方式实现属性动画的时,需要先在res目录下创建animator文件夹。
- 然后新建xml文件,写好你的动画文件
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together">
<objectAnimator
android:duration="4000"
android:propertyName="alpha"
android:valueFrom="1"
android:valueTo="0.5"
android:valueType="floatType"/>
<objectAnimator
android:duration="4000"
android:propertyName="width"
android:valueFrom="240"
android:valueTo="480"
android:valueType="intType"
/>
<objectAnimator
android:propertyName="rotation"
android:duration="4000"
android:valueFrom="90"
android:valueTo="145"
android:valueType="floatType"/>
</set>
- 然后就在代码中使用啦,和普通动画差不多滴。
private ImageView img_beauty;
private Animator animator;
private void initAnimatorXML(){
animator = AnimatorInflater.loadAnimator(this,R.animator.beauty_animtor);
animator.setTarget(new WrapView(img_beauty));
animator.start();
}
最关键的一步来了,如果使用ObjectAnimator的话,必须要为你操作的对象实现相应的getXX()和setXX()的方法,这个XX就是你需要改变的属性.- 我重新试了试,发现不用包装也可以运行,所以不用实现下面这些方法。直接用
private void initAnimatorXML() {
animatorXML = AnimatorInflater.loadAnimator(this, R.animator.beauty_animtor);
animatorXML.setTarget(img_beauty);
}
代码实现动画
- 直接使用ObjectAnimator类。其实也可以用ValueAnimator,但是ObjectAnimator就是继承自ValueAnimator,所以肯定是ObjectAnimator是有优化,会用一个就OK了,这里我直接用的ObjectAnimator;不用去管ValueAnimator;
- 首先是透明度动画
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(img_beauty,"alpha",1.0f,0.5f);
objectAnimator.setDuration(4000);
- 这里贴出我写的动画,不一个个写了
ObjectAnimator objectAnimator;
animator = null;
//透明度
objectAnimator = ObjectAnimator.ofFloat(img_beauty, "alpha", 1.0f, 0.5f);
//角度rotation
objectAnimator = ObjectAnimator.ofFloat(img_beauty, "rotation", 90, 45);
//缩放 这里传入的值是倍数,即原本图片的宽度的倍数
objectAnimator = ObjectAnimator.ofFloat(img_beauty, "scaleX", 0, 1);
objectAnimator = ObjectAnimator.ofFloat(img_beauty, "scaleY", 1, 0);
//平移 这里想从原位置开始平移,那么第一个位置参数设置为0就行了
//这里的getX()返回的就是0。但是这个值应该是触摸点距离控件的左边距的距离。不是很懂。
float x = img_beauty.getX();
objectAnimator = ObjectAnimator.ofFloat(img_beauty, "translationX", x, x + 50);
//背景颜色
//API23才能使用这个方法
//这个还蛮好玩的,可以多种颜色,而且是线性变化,慢慢变化的。
objectAnimator = ObjectAnimator.ofArgb(findViewById(R.id.btn_start_anim_java),"backgroundColor",
getColor(R.color.purple_200), getColor(R.color.teal_200),getColor(R.color.black));
//控件宽度
int width = img_beauty.getLayoutParams().width;
objectAnimator = ObjectAnimator.ofInt(new WrapView(img_beauty),"width",width,width/2);
animator = objectAnimator;
animator.setDuration(4000);
- 哦,上面话横线的也不算说错,比如上面最后一个动画,宽度改变的动画,因为我的ImageView没有setWidth的方法,就会报错,告诉我需要一个相关的方法,这样就必须有一个包装类,来包装我的ImageView,然后使用。、
class WrapView {
private View view;
private int width;
private float alpha;
private float rotation;
public WrapView(View view) {
this.view = view;
}
public int getWidth() {
if (view == null) return 0;
return view.getLayoutParams().width;
}
public void setWidth(int w) {
this.width = w;
view.getLayoutParams().width = w;
view.requestLayout();//刷新布局
}
public float getAlpha() {
if (view == null) return 0;
return view.getAlpha();
}
public void setAlpha(float alpha) {
this.alpha = alpha;
view.setAlpha(alpha);
view.requestLayout();
}
public float getRotation() {
if (view == null) return 0;
return view.getRotation();
}
public void setRotation(float rotation) {
this.rotation = rotation;
view.setRotation(rotation);
view.requestLayout();
}
}
动画合集AnimatorSet
- 没什么好说的,动画肯定不能一个一个执行,肯定有需求要求一起是吧。
- 大同小异,就是设置好动画以后,放入AnimatorSet中,按照自己想要的顺序灵活运用play,with,after,before等方法添加动画。
private void initAnimatorSet() {
AnimatorSet animatorSet = new AnimatorSet();
//透明度
Animator alpha = ObjectAnimator.ofFloat(img_beauty, "alpha", 1.0f, 0.5f);
//角度rotation
Animator rotation = ObjectAnimator.ofFloat(img_beauty, "rotation", 90, 45);
//缩放 这里传入的值是倍数,即原本图片的宽度的倍数
Animator scaleX = ObjectAnimator.ofFloat(img_beauty, "scaleX", 1, 2);
Animator scaleY = ObjectAnimator.ofFloat(img_beauty, "scaleY", 2, 1);
//平移 这里想从原位置开始平移,那么第一个位置参数设置为0就行了
//这里的getX()返回的就是0。但是这个值应该是触摸点距离控件的左边距的距离。不是很懂。
float x = img_beauty.getX();
Animator translationX = ObjectAnimator.ofFloat(img_beauty, "translationX", x, x + 50);
//背景颜色
//API23才能使用这个方法
//这个还蛮好玩的,可以多种颜色,而且是线性变化,慢慢变化的。
Animator backgroundColor = ObjectAnimator.ofArgb(findViewById(R.id.btn_start_anim_java),"backgroundColor",
getColor(R.color.purple_200), getColor(R.color.teal_200),getColor(R.color.black));
//控件宽度
int width = img_beauty.getLayoutParams().width;
Animator w = ObjectAnimator.ofInt(new WrapView(img_beauty),"width",width,width/2);
animatorSet.play(alpha)
.with(rotation)//需要同时执行的动画用with
.with(w)
.with(translationX)
.after(scaleX)//需要执行play之后执行的动画
.before(scaleY);//需要执行play之前执行的动画
animator = animatorSet;
animator.setDuration(6000);
}
- 完整代码
package com.southwind.androidfoundation.animation;
import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Color;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.RadioGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.dynamicanimation.animation.FloatValueHolder;
import com.southwind.androidfoundation.R;
import com.southwind.androidfoundation.fourassembly.base.BaseActivity;
/**
* 属性动画
*/
public class PropertyAnimationActivity extends BaseActivity {
private ImageView img_beauty;
private Animator animator;
private Animator animatorXML;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
setContentView(R.layout.activity_property_animation);
super.onCreate(savedInstanceState);
initData();
}
private void initData() {
// initValueAnimator();
initObjectAnimator();
initAnimatorXML();
initAnimatorSet();
}
@Override
public void initView() {
super.initView();
img_beauty = findViewById(R.id.img_beauty);
}
private void initObjectAnimator() {
ObjectAnimator objectAnimator;
animator = null;
//透明度
objectAnimator = ObjectAnimator.ofFloat(img_beauty, "alpha", 1.0f, 0.5f);
//角度rotation
objectAnimator = ObjectAnimator.ofFloat(img_beauty, "rotation", 90, 45);
//缩放 这里传入的值是倍数,即原本图片的宽度的倍数
objectAnimator = ObjectAnimator.ofFloat(img_beauty, "scaleX", 0, 1);
objectAnimator = ObjectAnimator.ofFloat(img_beauty, "scaleY", 1, 0);
//平移 这里想从原位置开始平移,那么第一个位置参数设置为0就行了
//这里的getX()返回的就是0。但是这个值应该是触摸点距离控件的左边距的距离。不是很懂。
float x = img_beauty.getX();
objectAnimator = ObjectAnimator.ofFloat(img_beauty, "translationX", x, x + 50);
//背景颜色
//API23才能使用这个方法
//这个还蛮好玩的,可以多种颜色,而且是线性变化,慢慢变化的。
objectAnimator = ObjectAnimator.ofArgb(findViewById(R.id.btn_start_anim_java),"backgroundColor",
getColor(R.color.purple_200), getColor(R.color.teal_200),getColor(R.color.black));
//控件宽度
int width = img_beauty.getLayoutParams().width;
objectAnimator = ObjectAnimator.ofInt(new WrapView(img_beauty),"width",width,width/2);
animator = objectAnimator;
animator.setDuration(4000);
}
private void initValueAnimator() {
animator = null;
ValueAnimator valueAnimator = ValueAnimator.ofFloat(1.0f, 0.5f);
valueAnimator.setTarget(img_beauty);
animator = valueAnimator;
animator.setDuration(4000);
}
private void initAnimatorSet() {
AnimatorSet animatorSet = new AnimatorSet();
//透明度
Animator alpha = ObjectAnimator.ofFloat(img_beauty, "alpha", 1.0f, 0.5f);
//角度rotation
Animator rotation = ObjectAnimator.ofFloat(img_beauty, "rotation", 90, 45);
//缩放 这里传入的值是倍数,即原本图片的宽度的倍数
Animator scaleX = ObjectAnimator.ofFloat(img_beauty, "scaleX", 1, 2);
Animator scaleY = ObjectAnimator.ofFloat(img_beauty, "scaleY", 2, 1);
//平移 这里想从原位置开始平移,那么第一个位置参数设置为0就行了
//这里的getX()返回的就是0。但是这个值应该是触摸点距离控件的左边距的距离。不是很懂。
float x = img_beauty.getX();
Animator translationX = ObjectAnimator.ofFloat(img_beauty, "translationX", x, x + 50);
//背景颜色
//API23才能使用这个方法
//这个还蛮好玩的,可以多种颜色,而且是线性变化,慢慢变化的。
Animator backgroundColor = ObjectAnimator.ofArgb(findViewById(R.id.btn_start_anim_java),"backgroundColor",
getColor(R.color.purple_200), getColor(R.color.teal_200),getColor(R.color.black));
//控件宽度
int width = img_beauty.getLayoutParams().width;
Animator w = ObjectAnimator.ofInt(new WrapView(img_beauty),"width",width,width/2);
animatorSet.play(alpha)
.with(rotation)//需要同时执行的动画用with
.with(w)
.with(translationX)
.after(scaleX)//需要执行play之后执行的动画
.before(scaleY);//需要执行play之前执行的动画
animator = animatorSet;
animator.setDuration(6000);
}
private void initAnimatorXML() {
animatorXML = AnimatorInflater.loadAnimator(this, R.animator.beauty_animtor);
animatorXML.setTarget(img_beauty);
}
@Override
public void initButton() {
super.initButton();
//开始动画
initButton(R.id.btn_start_anim_java, new View.OnClickListener() {
@Override
public void onClick(View v) {
if (animator != null)
animator.start();
}
});
//结束动画
initButton(R.id.btn_start_anim_xml, new View.OnClickListener() {
@Override
public void onClick(View v) {
if (animatorXML != null)
animatorXML.start();
}
});
}
class WrapView {
private View view;
private int width;
private float alpha;
private float rotation;
public WrapView(View view) {
this.view = view;
}
public int getWidth() {
if (view == null) return 0;
return view.getLayoutParams().width;
}
public void setWidth(int w) {
this.width = w;
view.getLayoutParams().width = w;
view.requestLayout();//刷新布局
}
public float getAlpha() {
if (view == null) return 0;
return view.getAlpha();
}
public void setAlpha(float alpha) {
this.alpha = alpha;
view.setAlpha(alpha);
view.requestLayout();
}
public float getRotation() {
if (view == null) return 0;
return view.getRotation();
}
public void setRotation(float rotation) {
this.rotation = rotation;
view.setRotation(rotation);
view.requestLayout();
}
}
}
- 属性动画还可以传入回调,用来监听动画的执行到那一步了。我就不写了,感觉用处不大。谁管你啊,动画跑完就完事儿了。
过渡动画
- 使用简单哈,首先这个分为5.0版本之前和5.0版本之后,这个是不是真分,我不确定,我看资料这么说,我就这么信了。我使用的时候其实两种用法都不影响哈。
使用
- 首先呢老规矩定义动画的xml,这次还是在anim文件夹下定义
- close_exit.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000">
<translate
android:fromXDelta="0%p"
android:toXDelta="100%p"/>
</set>
- open_enter.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000">
<translate
android:fromXDelta="100%p"
android:toXDelta="0%p"/>
</set>
- 然后可以在代码中直接使用,一般是使用在跳转代码之后
- 这里5.0之前,都是使用overridePendingTransition方法,传入动画,跳转的时候就可以看到相应的动画了。
private void jumpWithPendingAnimation(){
//Android5.0版本以上
//5.0以上自带3中专场动画
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP){
makeSceneTransitionAnimation();//第一种 看起来是淡入淡出
// makeTaskLaunchBehind();//alpha的变化,但是感觉用法有问题,乖乖的。
// custom();//自定义的用法,和5.0以下使用overridePendingTransition方式一样,传入自己的动画。
}else {
jump2NextActivity(PendingAnimationActivity.class);
overridePendingTransition(R.anim.open_enter,R.anim.close_exit);
}
}
- 5.0之后呢,可以使用的方法就灵活多变了。前两种是Android内置的,后一种和老版本一样传入自己定义的动画xml文件。
private void makeSceneTransitionAnimation(){
Intent intent = new Intent(this,PendingAnimationActivity.class);
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
}
private void makeTaskLaunchBehind(){
Intent intent = new Intent(this,PendingAnimationActivity.class);
startActivity(intent,ActivityOptions.makeTaskLaunchBehind().toBundle());
}
private void custom(){
Intent intent = new Intent(this,PendingAnimationActivity.class);
startActivity(intent,ActivityOptions.makeCustomAnimation(this,R.anim.open_enter,R.anim.close_exit).toBundle());
}
-
当然,你嫌不够,这里方法有很多,我没有一个一个去看到底是啥,反正很多就完事儿了。
效果,我这里故意将动画时间设置为3000也就是3秒,能清除看到动画的流程哈。
效果动图
-
这里动图给我转成了jpg,我直接开了个gitee仓库放我的动图行了吧。