如果你经常听歌,你会发现歌曲 app 的背景会随着音乐移动的,从左到右或者从上到下,这种动画虽然简单,但是这里有一个技巧。如果你还不明白这种动效看看下面的 demo.
移动背景效果
使用 setImageMatrix 播放图片动画
下面是官方文档给出的解释:
你可以看到这里的解释很简单,就是代替 ImageView 的图像矩阵,然后 configureBounds 和 invalidate 被调用。 在 java 代码中我们可以设置 Matrix 的 scaleType.
1
| mImageView.setScaleType(ScaleType.MATRIX)
|
或者在xml文件中设置:
1
| android:scaleType="matrix"
|
下面是ImageView的初始矩阵(matrix)
在x和y方向上放大2倍:
1
2
3
| final Matrix matrix = new Matrix();
matrix.postScale(2, 2);
imageView.setImageMatrix(matrix);
|
1
2
3
4
| final Matrix matrix = new Matrix();
matrix.postScale(2, 2);
matrix.postRotate(15);
imageView.setImageMatrix(matrix);
|
使你的图片移动
首先我们需要计算 ImageView 当前方向(水平,纵向)和图片当前方向的比例,就比如水平方向吧,我们就要让图片和 view 的高度相同,横向放大或者缩小。
1
2
| float scaleFactor = (float)imageView.getHeight() / (float) drawable.getIntrinsicHeight();
mMatrix.postScale(scaleFactor, scaleFactor);
|
这样我们就能保证图片的高和 ImageView 相同,并且填充满 ImageView. 接下来我们就让 ImageView 的图片移动,我们要用到一个强大的 Android 动画框架:ValueAnimator,其原理就是利用 ImageView 的图像矩阵在 x 轴方向变换移动。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| mAnimator = ValueAnimator.ofFloat(0, 100);
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (Float) animation.getAnimatedValue();
matrix.reset();
matrix.postScale(scaleFactor, scaleFactor);
matrix.postTranslate(-value, 0);
imageView.setImageMatrix(matrix);
}
});
mAnimator.setDuration(5000);
mAnimator.start();
|
整个代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
| package com.testimageview;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.os.Bundle;
import android.widget.ImageView;
public class MainActivity extends Activity{
private static final int RightToLeft = 1;
private static final int LeftToRight = 2;
private static final int DURATION = 5000;
private ValueAnimator mCurrentAnimator;
private final Matrix mMatrix = new Matrix();
private ImageView mImageView;
private float mScaleFactor;
private int mDirection = RightToLeft;
private RectF mDisplayRect = new RectF();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.imageView);
mImageView.post(new Runnable() {
@Override
public void run() {
mScaleFactor = (float) mImageView.getHeight()
/ (float) mImageView.getDrawable().getIntrinsicHeight();
mMatrix.postScale(mScaleFactor, mScaleFactor);
mImageView.setImageMatrix(mMatrix);
animate();
}
});
}
private void animate() {
updateDisplayRect();
if(mDirection == RightToLeft) {
animate(mDisplayRect.left, mDisplayRect.left
- (mDisplayRect.right - mImageView.getWidth()));
} else {
animate(mDisplayRect.left, 0.0f);
}
}
private void animate(float from, float to) {
mCurrentAnimator = ValueAnimator.ofFloat(from, to);
mCurrentAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (Float) animation.getAnimatedValue();
mMatrix.reset();
mMatrix.postScale(mScaleFactor, mScaleFactor);
mMatrix.postTranslate(value, 0);
mImageView.setImageMatrix(mMatrix);
}
});
mCurrentAnimator.setDuration(DURATION);
mCurrentAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if(mDirection == RightToLeft)
mDirection = LeftToRight;
else
mDirection = RightToLeft;
animate();
}
});
mCurrentAnimator.start();
}
private void updateDisplayRect() {
mDisplayRect.set(0, 0, mImageView.getDrawable().getIntrinsicWidth(),
mImageView.getDrawable().getIntrinsicHeight());
mMatrix.mapRect(mDisplayRect);
}
}
|