这是我参与「第四届青训营 」笔记创作活动的第6天
动画
帧动画
帧动画示例:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@drawable/ic_wifi_0" android:duration="100"/>
<item android:drawable="@drawable/ic_wifi_1" android:duration="100"/>
<item android:drawable="@drawable/ic_wifi_2" android:duration="100"/>
<item android:drawable="@drawable/ic_wifi_3" android:duration="100"/>
<item android:drawable="@drawable/ic_wifi_4" android:duration="100"/>
<item android:drawable="@drawable/ic_wifi_5" android:duration="100"/>
</animation-list>
private void playAnimation() {
mImageView.setImageResource(R.drawable.frame_anim);
AnimationDrawable animationDrawable = (AnimationDrawable) mImageView.getDrawable();
animationDrawable.start();
...
animationDrawable.stop();
}
补间动画
示例 :
public void tweenedAnimation(View view) {
// 创建一个透明度动画,透明度从1渐变至0
AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);
alphaAnimation.setDuration(3000);
// 创建一个旋转动画,从0度旋转至360度
RotateAnimation rotateAnimation = new RotateAnimation(0, 360,
Animation.RELATIVE_TO_SELF, 0.5f,Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(3000);
ScaleAnimation scaleAnimation = new ScaleAnimation(1, 0.5f, 1, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(3000);
TranslateAnimation translateAnimation = new TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 1,
Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 1);
translateAnimation.setDuration(3000);
// 组合上述4种动画
AnimationSet animationSet = new AnimationSet(true);
animationSet.addAnimation(alphaAnimation);
animationSet.addAnimation(rotateAnimation);
animationSet.addAnimation(scaleAnimation);
animationSet.addAnimation(translateAnimation);
view.startAnimation(animationSet);
}
差值器示例:
属性动画
属性动画示例:
private void startObjectAnimatorSet() {
// 创建一个ObjectAnimator,将mImageView的scaleX属性值从1变化到0.5
Animator scaleXAnimator = ObjectAnimator.ofFloat(mImageView, "scaleX", 1, 0.5f);
scaleXAnimator.setDuration(2000);
// 创建一个ObjectAnimator,将mImageView的scaleY属性值从1变化到0.5
Animator scaleYAnimator = ObjectAnimator.ofFloat(mImageView, "scaleY", 1, 0.5f);
scaleYAnimator.setDuration(2000);
// 创建一个ObjectAnimator,将mImageView的rotationX属性值从0变化到360
Animator rotationXAnimator = ObjectAnimator.ofFloat(mImageView, "rotationX", 0, 360);
rotationXAnimator.setDuration(2000);
// 创建一个ObjectAnimator,将mImageView的rotationY属性值从0变化到360
Animator rotationYAnimator = ObjectAnimator.ofFloat(mImageView, "rotationY", 0, 360);
rotationYAnimator.setDuration(2000);
// 组合上述4种动画
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(scaleXAnimator).with(scaleYAnimator)
.before(rotationXAnimator).after(rotationYAnimator);
animatorSet.start();
}
动画总结
两类动画的根本区别在于:是否改变动画本身的属性
- 视图动画:不改变动画的属性,在动画过程中仅对图像进行变换来达到动画效果。无论动画结果在哪,该View的位置和响应区域都是在原地,不会根据结果而移动;
- 属性动画:改变了动画属性 因属性动画在动画过程中对动态改变了对象属性,从而达到了动画效果
自定义View
自定义 View示例
创建View
public class SwitchButton extends View implements Checkable {
public SwitchButton(Context context) {
super(context);
init(context, null);
}
public SwitchButton(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public SwitchButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public SwitchButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
处理View布局
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if(widthMode == MeasureSpec.UNSPECIFIED || widthMode == MeasureSpec.AT_MOST){
widthMeasureSpec = MeasureSpec.makeMeasureSpec(DEFAULT_WIDTH, MeasureSpec.EXACTLY);
}
if(heightMode == MeasureSpec.UNSPECIFIED || heightMode == MeasureSpec.AT_MOST){
heightMeasureSpec = MeasureSpec.makeMeasureSpec(DEFAULT_HEIGHT, MeasureSpec.EXACTLY);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
float viewPadding = Math.max(shadowRadius + shadowOffset, borderWidth);
height = h - viewPadding - viewPadding;
width = w - viewPadding - viewPadding;
...
}
绘制View
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制白色背景的圆角矩形
paint.setStrokeWidth(borderWidth);
paint.setStyle(Paint.Style.FILL);
paint.setColor(background);
drawRoundRect(canvas, left, top, right, bottom, viewRadius, paint);
//绘制关闭状态的边框
paint.setStyle(Paint.Style.STROKE);
paint.setColor(uncheckColor);
drawRoundRect(canvas,left, top, right, bottom, viewRadius, paint);
...
//绘制按钮左边绿色长条遮挡
paint.setStyle(Paint.Style.FILL);
paint.setStrokeWidth(1);
drawArc(canvas, left, top, left + 2 * viewRadius, top + 2 * viewRadius,90, 180, paint);
canvas.drawRect( left + viewRadius, top,viewState.buttonX,
top + 2 * viewRadius,paint);
...
//绘制按钮
drawButton(canvas, viewState.buttonX, centerY);
}
处理用户交互
@Override
public boolean onTouchEvent(MotionEvent event) {
if(!isEnabled()) { return false; }
switch (actionMasked){
case MotionEvent.ACTION_DOWN:
...
break;
case MotionEvent.ACTION_MOVE:
if(isPendingDragState()){ //在准备进入拖动状态过程中,可以拖动按钮位置
...
}else if(isDragState()){ //拖动按钮位置,同时改变对应的背景颜色
...
}
break;
case MotionEvent.ACTION_UP:
if(System.currentTimeMillis() - touchDownTime <= 300){ //点击时间小于300ms,认为是点击操作
toggle();
}else if(isDragState()){ //在拖动状态,计算按钮位置,设置是否切换状态
...
}
break;
case MotionEvent.ACTION_CANCEL:
removeCallbacks(postPendingDrag);
break;
}
return true;
}
处理动画
// 初始化View时设置动画
valueAnimator = ValueAnimator.ofFloat(0f, 1f);
valueAnimator.setDuration(effectDuration);
valueAnimator.setRepeatCount(0);
valueAnimator.addUpdateListener(animatorUpdateListener);
// 点击开关后启动动画
valueAnimator.start();
// 简单动画更新回调,触发View绘制
private ValueAnimator.AnimatorUpdateListener animatorUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (Float) animation.getAnimatedValue();
switch (animateState) {
...
case ANIMATE_STATE_SWITCH:
viewState.buttonX = beforeState.buttonX + (afterState.buttonX - beforeState.buttonX) * value;
float fraction = (viewState.buttonX - buttonMinX) / (buttonMaxX - buttonMinX);
viewState.checkStateColor = (int) argbEvaluator.evaluate( fraction,uncheckColor,checkedColor);
viewState.radius = fraction * viewRadius;
viewState.checkedLineColor = (int) argbEvaluator.evaluate(fraction,Color.TRANSPARENT, checkLineColor);
break;
}
postInvalidate();
}
};
自定义View小结
课程总结
\