Android动画之属性动画
程序员文章站
2022-05-03 10:36:15
...
总归是逮着机会,稍微慢一点。在过去的很长一段时间内,都是在业务逻辑的复杂变化中挣扎。没有技术上的成长,内心还是蛮恐慌的。一不小心,又带有了些许的情绪在里面。。。。。
一、属性动画单个动画
1,布局文件添加动画作用目标
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.future.animatordemo.MainActivity">
<ImageView
android:id="@+id/content_iv"
android:layout_width="150dp"
android:layout_height="150dp"
android:src="@mipmap/koala" />
</RelativeLayout>
2,获取控件并执行动画
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
/**
* 图片
*/
private ImageView contentIV;
/**
* 自定义控件
*/
private PointView createView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_bak);
initView();
initAnimation();
initListener();
}
/**
* 初始化控件
*/
private void initView() {
contentIV = findViewById(R.id.content_iv);
}
/**
* 初始化动画
*/
private void initAnimation() {
rotateAnimation();
//alpahAnimation();
}
private void initListener() {
contentIV.setOnClickListener(this);
}
/**
* 旋转动画
*/
private void rotateAnimation() {
ObjectAnimator anim = ObjectAnimator.ofFloat(contentIV, "rotation", 0f, 360f);
anim.setDuration(1000);
anim.start();
}
/**
* 透明渐变动画
*/
private void alpahAnimation() {
ObjectAnimator anim = ObjectAnimator.ofFloat(contentIV, "alpha", 1.0f, 0.8f, 0.6f, 0.4f, 0.2f, 0.0f);
anim.setRepeatCount(-1);
anim.setRepeatMode(ObjectAnimator.REVERSE);
anim.setDuration(2000);
anim.start();
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.content_iv:
Toast.makeText(MainActivity.this, "戳中朕心了~_~", Toast.LENGTH_SHORT).show();
break;
}
}
}
执行效果:
旋转动画:
透明渐变动画:
二、属性动画的合集
添加以下方法,并在onCreate()中调用
private void setAnimation() {
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(contentIV, "alpha", 1.0f, 0.5f, 0.8f, 1.0f);
ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(contentIV, "scaleX", 0.0f, 1.0f);
ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(contentIV, "scaleY", 0.0f, 2.0f, 1.0f);
ObjectAnimator rotateAnim = ObjectAnimator.ofFloat(contentIV, "rotation", 0, 360);
ObjectAnimator transXAnim = ObjectAnimator.ofFloat(contentIV, "translationX", 100, 400);
ObjectAnimator transYAnim = ObjectAnimator.ofFloat(contentIV, "translationY", 100, 750, 300, 600);
AnimatorSet set = new AnimatorSet();
set.playTogether(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);//叠加在一起运动
// set.playSequentially(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);
set.setDuration(3000);
set.start();
}
其中playTogether()将所有的动画组合在一起,同时开启动画。playSequentially()将动画顺序执行,当上一个动画没有结束时,下一个动画不会开始执行。
展示效果:
三、属性动画的监听
代码修改,添加动画运行更新监听,并在更新方法中刷新控件状态。使用了Layout()方法。
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
/**
* 图片
*/
private ImageView contentIV;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initListener();
}
/**
* 初始化控件
*/
private void initView() {
contentIV = findViewById(R.id.content_iv);
}
private void initListener() {
contentIV.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.content_iv:
Toast.makeText(MainActivity.this, "戳中朕心了~_~", Toast.LENGTH_SHORT).show();
break;
}
}
public void startAnimatorAnimation(View view) {
ValueAnimator animator = ValueAnimator.ofInt(0, 400);
animator.setDuration(1000);
animator.setInterpolator(new DecelerateInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int curValue = (int) animation.getAnimatedValue();
contentIV.layout(curValue, curValue, curValue + contentIV.getWidth(), curValue + contentIV.getHeight());
}
});
animator.setStartDelay(1000);
animator.start();
}
}
备注:
相比于补间动画,属性动画直接修改了控件属性。直接反馈就是点击事件在补间动画时,只有在控件开始的位置执行才有效,其他地方无效。而属性动画在运行过程中,控件所在位置就是响应事件响应位置。
展示效果:
四、属性动画的应用
依据以上学习内容,制作自定义控件,展示属性动画的应用。
自定义控件实现如下:
public class PointView extends View {
public static final float RADIUS = 20f;
private Point currentPoint;
private Paint mPaint;
private Paint linePaint;
private AnimatorSet animSet;
private TimeInterpolator interpolatorType = new LinearInterpolator();
/**
* 实现关于color 的属性动画
*/
private int color;
private float radius = RADIUS;
public PointView(Context context) {
super(context);
init();
}
public PointView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public PointView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
mPaint.setColor(this.color);
}
public float getRadius() {
return radius;
}
public void setRadius(float radius) {
this.radius = radius;
}
private void init() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.TRANSPARENT);
linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
linePaint.setColor(Color.BLACK);
linePaint.setStrokeWidth(5);
}
@Override
protected void onDraw(Canvas canvas) {
if (currentPoint == null) {
currentPoint = new Point((int) RADIUS, (int) RADIUS);
drawCircle(canvas);
} else {
drawCircle(canvas);
}
drawLine(canvas);
}
private void drawLine(Canvas canvas) {
canvas.drawLine(10, getHeight() / 2, getWidth(), getHeight() / 2, linePaint);
canvas.drawLine(10, getHeight() / 2 - 150, 10, getHeight() / 2 + 150, linePaint);
canvas.drawPoint(currentPoint.x, currentPoint.y, linePaint);
}
public void startAnimation() {
Point startP = new Point((int) RADIUS, (int) RADIUS);
// Point endP = new Point(getWidth() - (int) RADIUS, getHeight() - (int) RADIUS);
Point endP = new Point(MainApplication.getApplication().getWidth() - (int) RADIUS, MainApplication.getApplication().getHeight() - (int) RADIUS);
final ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointSinEvaluator(), startP, endP);
valueAnimator.setRepeatCount(-1);
valueAnimator.setRepeatMode(ValueAnimator.REVERSE);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentPoint = (Point) animation.getAnimatedValue();
postInvalidate();
}
});
//
ObjectAnimator animColor = ObjectAnimator.ofObject(this, "color", new ArgbEvaluator(), Color.GREEN,
Color.YELLOW, Color.BLUE, Color.WHITE, Color.RED);
animColor.setRepeatCount(-1);
animColor.setRepeatMode(ValueAnimator.REVERSE);
ValueAnimator animScale = ValueAnimator.ofFloat(20f, 80f, 60f, 10f, 35f, 55f, 10f);
animScale.setRepeatCount(-1);
animScale.setRepeatMode(ValueAnimator.REVERSE);
animScale.setDuration(5000);
animScale.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
radius = (float) animation.getAnimatedValue();
}
});
animSet = new AnimatorSet();
animSet.play(valueAnimator).with(animColor).with(animScale);
animSet.setDuration(5000);
animSet.setInterpolator(interpolatorType);
animSet.start();
}
private void drawCircle(Canvas canvas) {
float x = currentPoint.x;
float y = currentPoint.y;
canvas.drawCircle(x, y, radius, mPaint);
}
public void setInterpolatorType(int type) {
switch (type) {
case 1:
interpolatorType = new BounceInterpolator();
break;
case 2:
interpolatorType = new AccelerateDecelerateInterpolator();
break;
case 3:
interpolatorType = new DecelerateInterpolator();
break;
case 4:
interpolatorType = new AnticipateInterpolator();
break;
case 5:
interpolatorType = new LinearInterpolator();
break;
case 6:
interpolatorType = new LinearOutSlowInInterpolator();
break;
case 7:
interpolatorType = new OvershootInterpolator();
default:
interpolatorType = new LinearInterpolator();
break;
}
}
@TargetApi(Build.VERSION_CODES.KITKAT)
public void pauseAnimation() {
if (animSet != null) {
animSet.pause();
}
}
public void stopAnimation() {
if (animSet != null) {
animSet.cancel();
this.clearAnimation();
}
}
}
XML文件中使用:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.future.animatordemo.MainActivity">
<ImageView
android:id="@+id/content_iv"
android:layout_width="150dp"
android:layout_height="150dp"
android:src="@mipmap/koala" />
<com.future.animatordemo.view.PointView
android:id="@+id/create_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
初始化控件并使用控件:
public class MainActivityBak extends AppCompatActivity implements View.OnClickListener {
/**
* 图片
*/
private ImageView contentIV;
/**
* 自定义控件
*/
private PointView createView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_bak);
initView();
initAnimation();
initListener();
}
/**
* 初始化控件
*/
private void initView() {
contentIV = findViewById(R.id.content_iv);
createView = findViewById(R.id.create_view);
}
/**
* 初始化动画
*/
private void initAnimation() {
setAnimation();
createView.startAnimation();
}
private void initListener() {
contentIV.setOnClickListener(this);
}
private void setAnimation() {
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(contentIV, "alpha", 1.0f, 0.5f, 0.8f, 1.0f);
ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(contentIV, "scaleX", 0.0f, 1.0f);
ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(contentIV, "scaleY", 0.0f, 2.0f, 1.0f);
ObjectAnimator rotateAnim = ObjectAnimator.ofFloat(contentIV, "rotation", 0, 360);
ObjectAnimator transXAnim = ObjectAnimator.ofFloat(contentIV, "translationX", 100, 400);
ObjectAnimator transYAnim = ObjectAnimator.ofFloat(contentIV, "translationY", 100, 750, 300, 600);
AnimatorSet set = new AnimatorSet();
set.playTogether(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);//叠加在一起运动
// set.playSequentially(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);
set.setDuration(3000);
set.start();
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.content_iv:
Toast.makeText(MainActivity.this, "戳中朕心了~_~", Toast.LENGTH_SHORT).show();
break;
}
}
}
展示效果:
有人请教我哆啦A梦和大雄最后有没有在一起,我便问他,许仙最后有没有和白蛇在一起。生之有涯‘最后'如何,也不过是蜿蜒个几十年的一件小事,而大事是他们,和我们曾经在一起过。
所有被千夫所指的困难,都是为了淘汰掉懦夫!
推荐阅读
-
一看就喜欢的loading动画效果Android分析实现
-
Android实现卡片翻转动画
-
Android属性动画Property Animation系列一之ObjectAnimator_html/css_WEB-ITnose
-
Android开发之使用ExifInterface获取拍照后的图片属性
-
IOS 开发之UIView动画的实例详解
-
Android自定义view绘制圆环占比动画
-
Android编程开发之EditText中inputType属性小结
-
Android逐帧动画实现代码
-
Android动画之渐变动画(Tween Animation)详解 (渐变、缩放、位移、旋转)
-
Android动画之补间动画(Tween Animation)实例详解