1. 动画实现例子,理解
补间动画问题:
1. 动画假象,移动到目标位置以后,控件还在原来地方,原来地方可设置点击事件
属性动画是真实改变动画属性
一个最简单的移动图片移动例子:
ImageView shuxingImg;
@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pro_perty);
shuxingImg= (ImageView)findViewById(R.id.shuxingImg);
}
// Button控件 点击效果
public void pingyi(final View view){
// 什么是动画,动画就是在指定时间内不断改变空间位置
// 最简单的移动例子
new Thread(){
@Override
public void run() {
super.run();
for (int i=0;i<100;i++){
SystemClock.sleep(100);
runOnUiThread(new Runnable() {
@Override
public void run() {
int left = shuxingImg.getLeft();
int top = shuxingImg.getTop();
int right= shuxingImg.getRight();
int bottom = shuxingImg.getBottom();
shuxingImg.layout(left+5,top+5,right+5,bottom+5);
}
});
}
}
}.start();
效果图:
2. Android属性动画
*******************************************************
Android为了方便,提供属性动画Api 可以控制属性:
1. translationX
translationY: 控制View控制,坐标原点相对于左上角(0,0)的一个偏移量
shuxingImg.animate().translationXBy(shuxingImg.getWidth())
x、y 描述的左上角坐标的偏移量 原来位置加上+
2. rotation rotationX 和 rotationY, 控制View绕着 (pivoX 和 pivoY) 旋转
3. scaleX和 scaleY 控制View绕着 (pivoX 和 pivoY) 缩放
(pivoX 和 pivoY) 是 View的中心点
4. alpha 不透明度 1 不透明 0透明
API实现:
shuxingImg.animate()
.translationXBy(shuxingImg.getWidth())
.translationYBy(shuxingImg.getHeight())
.alpha(0)
.setDuration(2000)
.setInterpolator(new BounceInterpolator())
.start();
*******************************************************
属性动画写法1 animate():
// 实现 X轴移动图片 宽度、Y轴移动 图片高度,隐藏图片,在2000 毫秒内
ImageView shuxingImg;
@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pro_perty);
shuxingImg= (ImageView)findViewById(R.id.shuxingImg);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@SuppressLint("NewApi")
public void pingyi(final View view){
// //另外一种写法
shuxingImg.animate()
.translationXBy(shuxingImg.getWidth())
.translationYBy(shuxingImg.getHeight())
.alpha(0)
.setDuration(2000)
.setInterpolator(new BounceInterpolator())
.start();
}
总结: ObjectAnimator和 AnimatorSet 使用 同时执行多个动画
或者:addUpdateListener 监听 shuxingImg.setAlpha(1-x0) 设置属性,也可以设置多个动画同时执行
2. ObjectAnimator和 playSequentially 使用 同时依次执行 实现属性动画
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@SuppressLint("NewApi")
public void pingyi(final View view){
// 0 实现 现对于控件 左上 角坐标
// X 轴 移动累加 距离shuxingImg.getWidth()
ObjectAnimator animator3 = ObjectAnimator.ofFloat(shuxingImg,"translationX",0,shuxingImg.getWidth());
animator3.setDuration(2000);
animator3.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// 动画执行过程不断调用该方法
float x0=animation.getAnimatedFraction(); //动画执行百分比 0-1
float x1= (float) animation.getAnimatedValue(); // 动画执行0-shuxingImg.getWidth() 中的某一个值
float t1= animation.getCurrentPlayTime(); //动画已经执行毫秒数据
Log.e("denganzhi1","百分比:"+x0+" 移动距离:"+x1 +" 已经执行时间:"+t1);
// 设置动画透明度
// shuxingImg.setAlpha(1-x0);
}
});
// 动画开始,结束,取消,暂停,重新启动
animator3.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation);
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
@Override
public void onAnimationRepeat(Animator animation) {
super.onAnimationRepeat(animation);
}
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
}
@Override
public void onAnimationPause(Animator animation) {
super.onAnimationPause(animation);
}
@Override
public void onAnimationResume(Animator animation) {
super.onAnimationResume(animation);
}
});
// Y 轴 移动累加 距离shuxingImg.getHeight()
ObjectAnimator animator4 = ObjectAnimator.ofFloat(shuxingImg,"translationY",0,shuxingImg.getHeight());
//实现多个同时执行
// animator3.setStartDelay(3000); // 虽然是同时执行,但是可以设置延时
AnimatorSet set = new AnimatorSet();
// set.playTogether(animator3,animator4);
// set.setDuration(2000);
// set.setInterpolator(new BounceInterpolator()); //设置串改器,抖动效果
// set.start();
// 动画执行顺序控制使用 play 、with
// before after
// ObjectAnimator animator1 = ObjectAnimator.ofFloat(iv, "alpha", 1f,0f,1f);
// ObjectAnimator animator2 = ObjectAnimator.ofFloat(iv, "scaleX", 1f,0.7f,1f);
// ObjectAnimator animator3 = ObjectAnimator.ofFloat(iv, "scaleY", 1f,0.7f,1f);
// AnimatorSet animatorSet = new AnimatorSet();
// animatorSet.setDuration(2000);
// //多个动画同时执行
animatorSet.playTogether(animator1,animator2,animator3);
// //也是多个动画同时执行--with通过with, playTogether底层就是调用with
// animatorSet.play(animator2).with(animator3).with(animator1);
// //A before B:A在B执行之前; A after B:A在B执行之后执行
// animatorSet.play(animator2).with(animator3).before(animator1);
// animatorSet.start();
// 实现多个动画依次执行
set.playSequentially(animator3,animator4);
set.start();
}
多个动画同时执行效果图:
3. ValueAnimator 的使用 实现属性动画
// 使用 ValueAnimator 设置属性动画 水平移动:
// ValueAnimator 就是一个 计算器,在500 ms 内 从 0-100不断计算中间值
// 实现在500 毫秒内, 图片水平移动100 px功能
ImageView shuxingImg;
@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pro_perty);
shuxingImg= (ImageView)findViewById(R.id.shuxingImg);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@SuppressLint("NewApi")
public void pingyi(final View view){
// 使用 ValueAnimator 设置属性动画 水平移动:
// ValueAnimator 就是一个 计算器,在500 ms 内 从 0-100不断计算
ValueAnimator mValueAnim = ValueAnimator.ofFloat(0, 100);
// 动画监听
mValueAnim.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator mAnim) {
float fraction = mAnim.getAnimatedFraction();
// percent 0.0 -> 1.0
//Log.d(TAG, "fraction: " +fraction);
// Integer newHeight = evaluate(fraction, startHeight, endHeight);
Float currentValue = (Float) mAnim.getAnimatedValue();
shuxingImg.setX(shuxingImg.getLeft()+currentValue);
Log.e("denganzhi1", "currentValue:"+currentValue+"");
shuxingImg.requestLayout();
}
});
// mValueAnim.setInterpolator(new OvershootInterpolator()); //这里设置串改器,有抖动效果
mValueAnim.setDuration(500);
mValueAnim.start();
}
4 使用 PropertyValuesHolder 实现属性动画,多个动画同时执行,实现属性动画
ImageView shuxingImg;
@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pro_perty);
shuxingImg= (ImageView)findViewById(R.id.shuxingImg);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@SuppressLint("NewApi")
public void pingyi(final View view){
// 使用PropertyValuesHolder 设置属性动画
// 缩放从原来1.0到0.7 恢复1.0
PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleX", 1f,0.7f,1f);
PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("scaleY", 1f,0.7f,1f);
//在原来基础上 X轴移动 300
PropertyValuesHolder holder4 = PropertyValuesHolder.ofFloat("translationX", 0f,300f);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(shuxingImg, holder2,holder3,holder4);
animator.setDuration(1000);
animator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// TODO Auto-generated method stub
float animatedValue = (Float) animation.getAnimatedValue(); //默认的
float animatedValueTranX=(Float) animation.getAnimatedValue("translationX"); //获取具体的值
float animatedFraction = animation.getAnimatedFraction();
long playTime = animation.getCurrentPlayTime();
Log.e("denganzhi","animatedValue:"+animatedValue+", "
+ "playTime:"+playTime+"animatedValueTranX:"+animatedValueTranX
+"animatedFraction:"+animatedFraction);
// System.out.println("animatedFraction:"+animatedFraction);
}
});
animator.start();
}
3. 属性动画自定义估值器
问题:
ValueAnimator mValueAnim = ValueAnimator.ofFloat(0, 100);
mValueAnim.addUpdateListener(new AnimatorUpdateListener() {
float fraction = mAnim.getAnimatedFraction();
// percent 0.0 -> 1.0
//Log.d(TAG, "fraction: " +fraction);
// Integer newHeight = evaluate(fraction, startHeight, endHeight);
Float currentValue = (Float) mAnim.getAnimatedValue();
shuxingImg.setX(shuxingImg.getLeft()+currentValue);
Log.e("denganzhi1", "currentValue:"+currentValue+"");
}
mValueAnim.setDuration(500);
// 默认计算方式500毫秒内
// 0-100 匀速累加,
// 我现在的需要: 要实现抛物效果
// X 轴 按照 x= vt 来计算
// y 轴 按照 y= 1/2*g*t^2 来计算
// 那么需要自定义 setEvaluator 估值器,按照的方式来计算 变化量实现代码:
// 系统有哪些估值器:
/// TypeEvaluator 设置类型估值器
/// //ArgbEvaluator 颜色估值器
// FloatEvaluator Float估值器
//PointEvaluator Point估值器
public void paowuxiangtest(View view){
/**
* // Android实现 抛物效果
// x= vt
// y= 1/2*g*t^2
*/
ValueAnimator valueAnimator = new ValueAnimator();
valueAnimator.setDuration(4000);
float startX= shuxingImg.getX();
float startY= shuxingImg.getY();
Log.e("denganzhi1", "startX:"+startX+"stratY:"+startY);
// 起始点,指定坐标默认位置
valueAnimator.setObjectValues(new PointF(startX, startY));
// * x:匀速 x=vt
// * y:加速度 y=1/2*g*t*t
// * 使用估值器最好实现。
valueAnimator.setEvaluator(new TypeEvaluator<PointF>() {
@Override
public PointF evaluate(float fraction, PointF startValue,
PointF endValue) {
//startValue==? 不知道
PointF pointF = new PointF();
// 6为 执行时间
pointF.x = endValue.x+100f*(fraction*6);//初始速度*(执行的百分比*4)
// 9.8f效果太差了 换成3.0
pointF.y = endValue.y+0.5f*30.0f*(fraction*6)*(fraction*6);
// pointF.y = 0.5f*150f*(fraction*4)*(fraction*4);
return pointF;
}
});
valueAnimator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//得到此时间点的坐标
PointF pointF = (PointF) animation.getAnimatedValue();
shuxingImg.setX(pointF.x);
shuxingImg.setY(pointF.y);
}
});
valueAnimator.start();
}
动画效果:
// 系统提供插值器使用,这些都是根据设计美学来的
//https://blog.csdn.net/qq_38182125/article/details/89631460 参考 有具体图
// 系统提供插值器使用,这些都是根据设计美学来的
//https://blog.csdn.net/qq_38182125/article/details/89631460 参考 有具体图
public void interpolatorTest(View view){
ObjectAnimator oa = ObjectAnimator.ofFloat(shuxingImg, "translationY", 0f,200f);
oa.setDuration(500);
//设置加速器---
// oa.setInterpolator(new AccelerateInterpolator(5));
// oa.setInterpolator(new AccelerateDecelerateInterpolator());
// oa.setInterpolator(new AnticipateInterpolator(8));
// 有一个回弹效果,例子,卫星菜单
oa.setInterpolator(new OvershootInterpolator());
// oa.setInterpolator(new CycleInterpolator(4));
// oa.setInterpolator(new BounceInterpolator());
oa.start();
}
效果图:setInterpolator 弹出在有点弹出来效果,图片弹回来的有点多,其实很少的
4. Google MaterialDesign新动画效果:
1. 触摸反馈
例子:水波纹效果
2. 揭露效果:
例子:按钮揭露效果
3. 曲线运动:
例子:花椒直播点赞飘出很多心心
Xml布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal"
>
<!--
android 5.0 默认自带
水波纹效果 覆盖父主题效果 直接到 DarkActionBar 中找即可
<item name="colorControlHighlight">#FF0000</item >
-->
<Button
android:layout_width="wrap_content"
android:layout_height="100dp"
android:text="1.Android5.0揭露效果,水波纹" />
<Button
android:id="@+id/bt1"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:text="2. 5.0揭露效果,中心点揭露" />
<Button
android:id="@+id/bt2"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:text="3. 5.0揭露效果,右上角揭露" />
</LinearLayout>
Java 代码实现:
package com.atguigu.l10_animation;
import android.animation.Animator;
import android.annotation.TargetApi;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.animation.AccelerateInterpolator;
import android.widget.Button;
public class AndroidLActivity extends AppCompatActivity {
private Button bt1;
private Button bt2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_android_l);
bt1 = (Button)findViewById(R.id.bt1);
bt2 = (Button)findViewById(R.id.bt2);
bt1.setOnClickListener(new View.OnClickListener() {
@TargetApi(21)
@Override
public void onClick(View v) {
//圆形水波纹揭露效果
// ViewAnimationUtils.createCircularReveal(
// view, //作用在哪个View上面
// centerX, centerY, //扩散的中心点
// startRadius, //开始扩散初始半径
// endRadius)//扩散结束半径
// 揭露中心点、揭露初始半径、揭露最终半径,这个是实心揭露
Animator animator = ViewAnimationUtils.createCircularReveal(bt1, bt1.getWidth()/2, bt1.getHeight()/2, 0, bt1.getHeight());
animator.setDuration(1000);
animator.setInterpolator(new AccelerateInterpolator());
animator.start();
// Math.hypot(x, y)
}
});
bt2.setOnClickListener(new View.OnClickListener() {
@TargetApi(21)
@Override
public void onClick(View v) {
// 勾股定理:hypot, 最终半径用 勾股定理计算
Animator animator = ViewAnimationUtils.createCircularReveal(bt2, 0, 0, 0, (float)Math.hypot(bt2.getWidth(), bt2.getHeight()));
animator.setDuration(1000);
animator.setInterpolator(new AccelerateInterpolator());
animator.start();
}
});
}
}
Google MaterialDesign 提供转场动画在v7包中:
//=====================转场动画========================
// 和PPT播放的时候切换动画差不多
public void startTranlate(View v){
Intent intent = new Intent(this, OtherActivityActivity.class);
startActivity(intent);
//必须在startActivity或者finish之后,立即执行
//类视 IOS右拽关闭Actiivty效果
// overridePendingTransition( android.R.anim.slide_in_left, android.R.anim.slide_out_right);
// 第一个通过透明度隐藏,第二个通过透明度显示
// overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
// 这里v7包下的转换场动画
// 弹出
// overridePendingTransition(R.anim.abc_popup_enter, R.anim.abc_popup_exit);
// overridePendingTransition(R.anim.abc_grow_fade_in_from_bottom, R.anim.abc_shrink_fade_out_from_bottom);
// 从下移动
// overridePendingTransition(R.anim.abc_slide_in_top, R.anim.abc_slide_out_bottom);
// 上移动效果
overridePendingTransition(R.anim.abc_slide_in_bottom, R.anim.abc_slide_out_top);
}
源码地址:https://download.csdn.net/download/dreams_deng/12250489