您的位置:首页 > 移动开发 > Android开发

Android动画(一)

2015-12-30 18:24 381 查看
(《群英传》)笔记:

1、视图动画

动画实现原理:每次绘制视图时,View所在的ViewGroup中drawChild函数获取该View的Animation的Transformation值,调用canvans.concat(transformToApply.getMatrix()),通过矩阵运算完成动画帧。如果动画没有完成,就继续调用invalidate()函数,启动下次绘制来驱动动画,从而完成整个动画的绘制。

特点:不能实现交互,元素发生视图动画后,其响应的事件依然在动画前的地方。但效率比较高且使用方便。

四种动画方式:

(1) 透明度动画(Alpha):

AlphaAnimation aa = new AlphaAnimation(0, 1);
aa.setDuration(1000);
view.startAnimation(aa);


(2)旋转动画(Rotate):

// 起始角度、旋转中心坐标
RotateAnimation ra = new RotateAnimation(0, 360, 100, 100);
ra.setDuration(1000);
view.startAnimation(ra);


位移动画(TranslateAnimation):

// (float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)
TranslateAnimation ta = new TranslateAnimation(0, 200, 0, 300);
ta.setDuration(1000);
view .startAnimation(ta);


缩放动画(Scale):

// (float fromX, float toX, float fromY, float toY)
ScaleAnimation sa = new ScaleAnimation(0, 2, 0, 2);
sa.setDuration(1000);
view.startAnimation(sa);


动画集合:

通过AnimationSet,可以将动画以组合形式展现出来:

AnimationSet as = new AnimationSet(true);
as.setDuration(1000);

AlphaAnimation aa = new AlphaAnimation(0, 1);
aa.setDuration(1000);
as.addAnimation(aa);

TranslateAnimation ta = new TranslateAnimation(0, 200, 0, 300);
ta.setDuration(1000);
as.addAnimation(ta);


对应的动画事件监听回调:

// 可以获取到动画的开始、结束合重复事件,并针对相应的事件作出不同的处理。
animation.setAnimationListener(new AnimationListener() {

@Override
public void onAnimationStart(Animation animation) {

}

@Override
public void onAnimationRepeat(Animation animation) {

}

@Override
public void onAnimationEnd(Animation animation) {

}
});


2、 属性动画:

原理:属性动画调用属性的get、set方法来真实地控制了一个View的属性值。通过对AnimatorSet和ObjectAnimator进行精细化控制的配合,只控制一个对象的一个属性值,而使用多个ObjectAnimator组合到AnimatorSet形成一个动画。ObjectAnimator调用setFrameDelay(longframeDelay)设置动画帧之间的间隙时间,调整帧率,减少动画过程中频繁绘制界面,在不影响动画效果的前提下减少CPU的资源消耗。

(1)ObjectAnimator

基本用法:

// 操纵的View;     操纵的属性;  可变数组参数,该属性变化的一个取值过程。
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "translationX", 300);


可以直接使用属性动画的属性值:

translationX和translationY:控制View对象从他的布局容器左上角坐标偏移的位置;

rotation、rotationX和rotationY:控制View对象围绕支点进行2D和3D旋转;

scaleX和scaleY:控制View对象围绕它的支点进行2D缩放;

x和y:描述了View对象在它的容器中的最终位置,它是最初的左上角坐标和translationX和translationY值得累计和;

alpha:它表示View对象的alpha透明度。默认值是1(不透明),0代表完全透明(不可见)。

如果一个属性没有get、set方法。可以通过ValueAnimator来实现。

(2)ValueAnimator

ObjectAnimator是继承自ValueAnimator的。ValueAnimator本身不提供任何动画效果,用来产生具有一定规律的数字,从而让调用者来控制动画的实现效果。

// ValueAnimator的一般使用方法
ValueAnimator animator = ValueAnimator.ofFloat(0, 100);
animator.setTarget(view);
animator.setDuration(1000).start();
animator.addUpdateListener(new AnimatorUpdateListener() {

@Override
public void onAnimationUpdate(ValueAnimator animation) {
Float value = (Float) animation.getAnimatedValue();
// TODO use the value
}
});


(3)PropertyValuesHolder:

组合动画。比如一个动画在平移过程中,同时改变X、Y轴的缩放。

PropertyValuesHolder pHolder1 = PropertyValuesHolder.ofFloat("translationX", 300f);
PropertyValuesHolder pHolder2 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
PropertyValuesHolder pHolder3 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
ObjectAnimator.ofPropertyValuesHolder(view, pHolder1, pHolder2, pHolder3).setDuration(1000);


动画事件的监听

ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", 0.5f);
anim.addListener(new AnimatorListener() {

@Override
public void onAnimationStart(Animator animation) {

}

@Override
public void onAnimationRepeat(Animator animation) {

}

// 大部分时候只关心onAnimationEnd动画
@Override
public void onAnimationEnd(Animator animation) {

}

@Override
public void onAnimationCancel(Animator animation) {

}
});
anima.start();

Android提供了AnimatorListenerAdapter来让我们选择必要的事件进行监听。
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
});


(5)AnimatorSet

不仅能实现PropertyValuesHolder的效果,也能实现更为精确的顺序控制。

ObjectAnimator anim1 = ObjectAnimator.ofFloat(view, "translationX", 300f);
ObjectAnimator anim2 = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0f, 1f);
ObjectAnimator anim3 = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0f, 1f);
AnimatorSet set = new AnimatorSet();
set.setDuration(1000);
// 通过playTogether()、playSequentially()、animSet.play().with()、before()、after()
// 这些方法来控制多个动画的协同工作方式。
set.playTogether(anim1, anim2, anim3);
set.start();


(6)在XML中使用动画:

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:propertyName="scaleX"
android:valueFrom="1.0"
android:valueTo="2.0"
android:valueType="floatType" >

</objectAnimator>


在程序中使用XML定义的属性动画:

Animator animator = AnimatorInflater.loadAnimator(this, R.animator.property);
animator.setTarget(view);
animator.start();


(7)View的animate方法:

直接驱动属性动画。是属性动画的一种简写方式。

view.animate().alpha(0).y(300).setDuration(1000)
.withStartAction(new Runnable() {

@Override
public void run() {

}
}).withEndAction(new Runnable() {

@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {

}
});
}
});


3、布局动画

作用在ViewGroup上,给ViewGroup增加View时添加一个动画过渡效果。

(1)最简单的布局动画:

Android:animateLayoutChanges="true"


(2)使用LayoutAnimationController 类来自定义一个子View的过渡效果。

示例:子View出现的时候,有一个缩放的动画效果。

LinearLayout ll = findViewById(R.id.ll);
//设置过渡动画
ScaleAnimation sa = new ScaleAnimation(0, 1 ,0, 1);
sa.setDuration(1000);
// 设置布局动画的显示属性
LayoutAnimationController lac = new LayoutAnimationController(sa, 0.5F);
lac.setOrder(LayoutAnimationController.ORDER_NORMAL);
// 为ViewGroup设置布局动画
ll.setLayoutAnimation(lac);


ORDER_NORMAL:顺序

ORDER_RANDOM:随机

ORDER_REVERSE:反序

4、 Interpolators(插值器)

可以定义动画变换速率,类似加速度,作用是控制目标变量的变化值进行对应的变化。

5、自定义动画

只需要实现它的applyTransformation的逻辑就可以了。

public class CustomAnim extends Animation {

private int mCenterWidth;
private int mCenterHeight;
// Camera 封装了openGL的3D动画
private Camera mCamera = new Camera();
private float mRotateY = 0.0f;

@Override
public void initialize(int width,
int height,
int parentWidth,
int parentHeight) {

super.initialize(width, height, parentWidth, parentHeight);
// 设置默认时长
setDuration(2000);
// 动画结束后保留状态
setFillAfter(false);
// 设置默认插值器
setInterpolator(new BounceInterpolator());
mCenterWidth = width / 2;
mCenterHeight = height / 2;
}

// 暴露接口-设置旋转角度
public void setRotateY(float rotateY) {
mRotateY = rotateY;
}

// 自定义动画的核心-----如何定义动画的进行过程
//第一个参数:插值器的时间因子0~1.0, 第二个参数:矩阵的封装类。
@Override
protected void applyTransformation(
float interpolatedTime,
Transformation t) {
final Matrix matrix = t.getMatrix();
mCamera.save();
// 使用Camera设置旋转的角度
mCamera.rotateY(mRotateY * interpolatedTime);
// 将旋转变换作用到matrix上
mCamera.getMatrix(matrix);
mCamera.restore();
// 通过matrix的各种操作来实现动画
// 通过pre方法设置矩阵作用前的偏移量来改变旋转中心
matrix.preTranslate(mCenterWidth, mCenterHeight);
matrix.postTranslate(-mCenterWidth, -mCenterHeight);
}
}


模拟电视机关闭的效果:让一个图片纵向比例不断缩小。

Final Matrix matrix = t.getMartrix();
matrix.preScale(1,
1 - interpolatedTime,
// 缩放的中心点
mCenterWidth,
mCenterHeight);


7、Android动画特效

示例1:灵动菜单

思路:使用属性动画,每个不同的按钮设置不同的动画,并设置相应的插值器实现展开、合拢效果。

/**
* 点击主菜单向四周展出子菜单的动画
* @author Administrator
*
*/
public class PropertyTest extends Activity implements View.OnClickListener {

private int[] mRes = {R.id.imageView_a, R.id.imageView_b, R.id.imageView_c,
R.id.imageView_d, R.id.imageView_e};
private List<ImageView> mImageViews = new ArrayList<ImageView>();
private boolean mFlag = true;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.property);
for (int i = 0; i < mRes.length; i++) {
ImageView imageView = (ImageView) findViewById(mRes[i]);
imageView.setOnClickListener(this);
mImageViews.add(imageView);
}
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.imageView_a:
if (mFlag) {
startAnim();
} else {
closeAnim();
}
break;
default:
Toast.makeText(PropertyTest.this, "哈哈" + v.getId(),
Toast.LENGTH_SHORT).show();
break;
}
}

private void closeAnim() {
ObjectAnimator animator0 = ObjectAnimator.ofFloat(mImageViews.get(0),
"alpha", 0.5F, 1F);
ObjectAnimator animator1 = ObjectAnimator.ofFloat(mImageViews.get(1),
"translationY", 200F, 0);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(mImageViews.get(2),
"translationX", 200F, 0);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(mImageViews.get(3),
"translationY", -200F, 0);
ObjectAnimator animator4 = ObjectAnimator.ofFloat(mImageViews.get(4),
"translationX", -200F, 0);
AnimatorSet set = new AnimatorSet();
set.setDuration(500);
set.setInterpolator(new BounceInterpolator());
set.playTogether(animator0, animator1, animator2, animator3, animator4);
set.start();
mFlag = true;

}

private void startAnim() {
ObjectAnimator animator0 = ObjectAnimator.ofFloat(
mImageViews.get(0),
"alpha",
1F,
0.5F);
ObjectAnimator animator1 = ObjectAnimator.ofFloat(
mImageViews.get(1),
"translationY",
200F);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(
mImageViews.get(2),
"translationX",
200F);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(
mImageViews.get(3),
"translationY",
-200F);
ObjectAnimator animator4 = ObjectAnimator.ofFloat(
mImageViews.get(4),
"translationX",
-200F);
AnimatorSet set = new AnimatorSet();
set.setDuration(500);
set.setInterpolator(new BounceInterpolator());
set.playTogether(
animator0,
animator1,
animator2,
animator3,
animator4);
set.start();
mFlag = false;
}
}


示例2:计时器(使用ValueAnimator)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:onClick="onClick"
android:text="点我!!"
android:textSize="60sp" />

</RelativeLayout>
/**
* 计时器
* @author Administrator
*
*/
public class TimerTest extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.timer);
}

public void onClick(final View view) {
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 100);
valueAnimator.addUpdateListener(
new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// 借助ValueAnimator来实现数字的不断增加,并将值设置给TextView
((TextView) view).setText("$ " +
(Integer) animation.getAnimatedValue());
}
});
valueAnimator.setDuration(3000);
valueAnimator.start();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: