Android中的动画可以分为三类:帧动画,补间动画,和属性动画
动画分类 | 说明 |
---|---|
帧动画 | 通过不停的播放图片产生的动画效果 |
补间动画 | 对View的平移,旋转,缩放,透明产生效果 |
属性动画 | 动态的改变属性产生动画效果 |
帧动画是按照一定的顺序播放一系列图片,从而产生动画。和我们看的动漫原理是一样的,本质上是对图片快速的翻页产生动的效果。
示例代码:
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/rocket_thrust1" android:duration="100" />
<item android:drawable="@drawable/rocket_thrust2" android:duration="100" />
<item android:drawable="@drawable/rocket_thrust3" android:duration="100" />
animation-list>
调用
public class MainActivity extends AppCompatActivity {
AnimationDrawable rocketAnimation;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ImageView animationImg = (ImageView) findViewById(R.id.imageView);
animationImg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
animationImg.setImageResource(R.drawable.play);
AnimationDrawable animationDrawable1 = (AnimationDrawable) animationImg.getDrawable();
animationDrawable1.setOneShot(true);
animationDrawable1.start();
}
});
}
}
补间动画的原理是对通过对View的平移,缩放,旋转和透明的操作,从而产生的动画。
注意:补间动画只调整View在Canvas上显示,并没有真实的改变View原来的位置,因此它的点击和触摸事件还保留在没有经过动画前的位置。
动画 | 说明 | 类 |
---|---|---|
平移 | 移动View的位置 | TranslateAnimation |
缩放 | 对View的缩放 | ScaleAnimation |
旋转 | 对View的旋转 | RotateAnimation |
透明 | 改变View的透明度 | AlphaAnimation |
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<alpha
android:duration="3000"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
<scale
android:duration="3000"
android:fromXScale="0.0"
android:fromYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1.0"
android:toYScale="1.0" />
<rotate
android:duration="3000"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="720" />
<translate
android:duration="1000"
android:fromXDelta="0"
android:fromYDelta="0"
android:startOffset="3000"
android:toXDelta="85"
android:toYDelta="0" />
set>
补间动画既可以在xml文件中配置,也可以用Java代码实现:
public class MainActivity extends AppCompatActivity {
private ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = (ImageView) findViewById(R.id.imageView);
TranslateAnimation translateAnim = new TranslateAnimation(0, 200, 0, 200);
translateAnim.setDuration(3000);
translateAnim.setFillAfter(true);
imageView.startAnimation(translateAnim);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//经过平移后的View不相应点击事件,点击事件仍然在没有移动前。
Toast.makeText(MainActivity.this, "123", Toast.LENGTH_SHORT).show();
}
});
}
}
1、调用View的startAnimation()方法出发动画事件。
public void startAnimation(Animation animation) {
animation.setStartTime(Animation.START_ON_FIRST_FRAME);
setAnimation(animation);
invalidateParentCaches();
invalidate(true);
}
在这个方法中,调用invalidate(true),触发调用draw()方法,对view进行重新绘制
2、draw()方法解析
把当前画布中View放置于矩阵中,然后通过矩阵变换对View在画布中影像进行改变。
Transformation 定义的矩阵对象
boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
...
if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) {
parent.getChildTransformation().clear();
parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION;
}
...
//矩阵,把当前的View放置到矩阵中
Transformation transformToApply = null;
//对View进行平移,旋转,缩放,透明等事件处理
if (transformToApply != null
|| alpha < 1
|| !hasIdentityMatrix()
|| (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) {
if (transformToApply != null || !childHasIdentityMatrix) {
int transX = 0;
int transY = 0;
if (offsetForScroll) {
transX = -sx;
transY = -sy;
}
if (transformToApply != null) {
if (concatMatrix) {
if (drawingWithRenderNode) {
renderNode.setAnimationMatrix(transformToApply.getMatrix());
} else {
// Undo the scroll translation, apply the transformation matrix,
// then redo the scroll translate to get the correct result.
canvas.translate(-transX, -transY);
canvas.concat(transformToApply.getMatrix());
canvas.translate(transX, transY);
}
parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
}
float transformAlpha = transformToApply.getAlpha();
if (transformAlpha < 1) {
alpha *= transformAlpha;
parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
}
}
if (!childHasIdentityMatrix && !drawingWithRenderNode) {
canvas.translate(-transX, -transY);
canvas.concat(getMatrix());
canvas.translate(transX, transY);
}
}
// Deal with alpha if it is or used to be <1
if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) {
if (alpha < 1) {
mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA;
} else {
mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA;
}
parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
if (!drawingWithDrawingCache) {
final int multipliedAlpha = (int) (255 * alpha);
if (!onSetAlpha(multipliedAlpha)) {
if (drawingWithRenderNode) {
renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha());
} else if (layerType == LAYER_TYPE_NONE) {
canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(),
multipliedAlpha);
}
} else {
// Alpha is handled by the child directly, clobber the layer's alpha
mPrivateFlags |= PFLAG_ALPHA_SET;
}
}
}
} else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) {
onSetAlpha(255);
mPrivateFlags &= ~PFLAG_ALPHA_SET;
}
if (!drawingWithRenderNode) {
// apply clips directly, since RenderNode won't do it for this draw
if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) {
if (offsetForScroll) {
canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight());
} else {
if (!scalingRequired || cache == null) {
canvas.clipRect(0, 0, getWidth(), getHeight());
} else {
canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight());
}
}
}
if (mClipBounds != null) {
// clip bounds ignore scroll
canvas.clipRect(mClipBounds);
}
}
...
return more;
}
参考:
https://blog.csdn.net/mr_liabill/article/details/49510485