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

Pro Android学习笔记(一一四):2D动画(9):Property Animation(下)

2014-08-18 10:20 316 查看
文章转载只能用于非商业性质,且不能带有虚拟货币、积分、注册等附加条件。转载须注明出处http://blog.csdn.net/flowingflying以及作者@恺风Wei

ViewPropertyAnimator

如果我们动画的对象是view,Android SDK通过ViewProperyAnimator提供一种更为优化的实现方式,同样一次性设置多个值的变化。小例子片段如下:

public void viewPropertiesTest(View v){

//获取当前状态

float h = tv.getHeight();

float w = tv.getWidth();

float x = tv.getX();

float y = tv.getY();



//将view初始值。

tv.setX(w);

tv.setY(h);

tv.setAlpha(0.0f);



//从view中获取ViewPropertyAnimator的对象

ViewPropertyAnimator vpa = tv.animate();

//设置目标值

vpa.setDuration(5000);

vpa.x(x);

vpa.y(y);

vpa.alpha(1.0f);

vpa.setInterpolator(new AccelerateDecelerateInterpolator());

}

注意,和之前的方式不同,不需要通过start()来启动动画。当viewPropertiesTest()函数执行完,返回UI线程时,自动启动动画。

TypeEvaluator

回眸ObjectAnimator最初的小例子,通过onFloat()或者onInt()对某个属性进行设置。如果这个属性不是简单的某个value,而是对象,就需要使用onObject()来进行设置。这个对象属性可以是我们自定义的。我们回头看看当初小例子中的部分代码及解释:

ObjectAnimator fadeout = ObjectAnimator.ofFloat(tv, "alpha", 0.0f);
//将alpha从当前值变为0(看不见),ofFloat()表明这是对tv对象(参数1)的alpha属性(参数2)进行的浮点类型数值的变化,从当前值变化至目标值(参数3)。哪些可以作为属性,需要具备setXXX()方法,则具备XXX属性,本例Textview对象具有public方法 view.setAlpha(float f)方法,故具有属性alpha。初始值从view.getAlpha()中获取。如果带有4个参数,例如 ofFloat(tv,"alpha",1.0f,0.0f),则第三个参数标识from的数值,第4个参数标识to的数值,即从alpha属性从1.0
变为0.0。

fadeout.setDuration(5000);

fadeout.start();
下面,我们将使用PointF(坐标类)来作为属性的值。由于目标的TextView并没有setPoint()和getPoint()的函数,我们需要通过自定义的MyAnimatorView类来实现。我们给出了“point”这个属性的初始值和最终值,但是在动画过程中的中间值如何,需要通过TypeEvaluator的evaluate()来给出,然后通过setPoint()设置给动画对象。

public void typeEvaluatorTest(View v){

//获取当前状态

float h = tv.getHeight();

float w = tv.getWidth();

float x = tv.getX();

float y = tv.getY();

// 获取动画变化属性的初始值和最终值

PointF startPoint = new PointF(w, h);

PointF endPoint = new PointF(x,y);

// 步骤1 :提供自定义属性“point”的动画对象

MyAnimatorView mav = new MyAnimatorView(tv);

// 步骤2 :通过ObjectAnimator的ofObject()来设置动画类型。参数1为动画对象;参数2对属性名称,动画对象应提供setXXX()的方法;参数3为动画过程中的中间值设定;参数4/5是初始值和最终值,如果只有参数4,则参数4位最种植,初始值由动画对象的getXXX()提供。下面分别给出了不带初始值和带有初始值的两种情况。

//ObjectAnimator tea = ObjectAnimator.ofObject(mav, "point", new MyPointEvaluator(), endPoint);

ObjectAnimator tea = ObjectAnimator.ofObject(mav, "point", new MyPointEvaluator(), startPoint,endPoint);

tea.setDuration(5000);

Log.d("WEI","------------------------------");

tea.start();

}

下面是使用TypeEvaluator来提供中间的组合属性,本例为PointF,代码片段如下:

public class MyPointEvaluator implements TypeEvaluator<PointF>{

@Override
// 实现TypeEvaluator接口的evaluate()方式,fraction是动画的进度,从0.0到1.0,根据进度,初始值和最终值,给出动画过程的中间值。

public PointF evaluate(float fraction, PointF startValue, PointF endValue){

Log.d("WEI","MyPointEvaluator : evaluate " + fraction);

return new PointF(startValue.x + fraction * (endValue.x - startValue.x),

startValue.y + fraction * (endValue.y - startValue.y));

}



}

由于TextView不提供setPoint()的方法,不能直接作为动画对象,需要进行封装,代码片段如下:

public class MyAnimatorView{

private View myView = null;



private MyAnimatorView(View v){

myView = v;

}

// 如果没有初始值,同getPoint()获取,本例设置为右下角

public PointF getPoint(){

Log.d("WEI","MyAnimatorView : getPoint()");

return new PointF(myView.getWidth(),myView.getHeight());

}

// 通过setPoint()来设置中间值

public void setPoint(PointF p){

Log.d("WEI","MyAnimatorView : setPoint (" + p.x + "," + p.y + ")");

myView.setX(p.x);

myView.setY(p.y);

}

}
下图是没有设置初始值和设置初始值的debug跟踪情况:



在小例子中,属性的组合使用了PointF的坐标类型,我们也可以加入其它的属性,自定义属性的组合。

Keyframe

通过Keyframe,我们可以设定某个时刻,某属性的值是多少。下面的小例子,通过对alpha的设定,实现变淡在变浓的效果。

public void keyFrameTest(View v){

//获取当前状态

float w = tv.getWidth();

float x = tv.getX();



// 为某个属性(本例子为alpha)设定特定时间的值。参数1为fraction,表示进度;参数2为具体数值,下面表示在进度20%时,该值为0.8,在50%时为0.2,在80%是为0.8,在100%(即最后)为1.0。

Keyframe kf0 = Keyframe.ofFloat(0.2f, 0.8f);

Keyframe kf1 = Keyframe.ofFloat(0.5f, 0.2f);

Keyframe kf2 = Keyframe.ofFloat(0.8f, 0.8f);

Keyframe kf3 = Keyframe.ofFloat(1.0f, 1.0f);

//通过PropertyValuesHolder来关联keyframe和属性。此外,我们还设置一个从x轴从右到左的移动

PropertyValuesHolder pvAlpha = PropertyValuesHolder.ofKeyframe("alpha", kf0,kf1,kf2,kf3);

PropertyValuesHolder pvX = PropertyValuesHolder.ofFloat("x", w, x);



ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(tv, pvAlpha,pvX);

anim.setDuration(5000);

anim.start();

}

LayoutTransition

通过LayoutTransition可以对view group中的各个view进行动画处理,这些动画处理包括四种情况:
1、增加一个View(view出现,LayoutTransition.APPEARING)
2、因增加view,而改变现实的其他view(LayoutTransition.CHANGE_APPEARING)
3、删除一个View(LayoutTransition.DISAPPEARING)
4、因删除某个View,而改变现实的其他view(LayoutTransition.CHANGE_DISAPPEARING)
小例子以第一种情况,即在Layout中增加一个view,view出现时具备某种动画效果。首选,需要对Layout中通过LayoutTransition对上述view变化进行设定,可以放在activity初始化阶段:

protected void onCreate(Bundle savedInstanceState) {

… …

myLayout = (LinearLayout)findViewById(R.id.my_layout);

//【步骤1】:将LayoutTransittion关联与某个view group中,本例为LinearLayout

LayoutTransition lt = new LayoutTransition();

myLayout.setLayoutTransition(lt);

//【步骤2】:针对4种情况情况进行动画设置,本例子讲针对添加view的情况,即LayoutTransition.APPREAING


//(2.1)设置动画ObjectAnimator,其中对象目标为何不重要,因为会通过LayoutTransition对象关联到layout,可设置为null。LayoutTransition的动画是有缺省值的,通过LogCat显示为300ms,如果我们设定的动画时间超过该值,是不其作用的,这种情况,可以通过设置LayoutTransition的动画时间来解决,例如本例可设置lt.setDuration(5000),提供一个慢速的动画效果。

ObjectAnimator animIn = ObjectAnimator.ofFloat(null, "rotationY", 90f,0f);

animIn.setDuration(lt.getDuration(LayoutTransition.APPEARING));


Log.d("WEI","" + lt.getDuration(LayoutTransition.APPEARING));

//(2.2)将动画加在LayoutTransition上,并指出属于那种情况下的动画

lt.setAnimator(LayoutTransition.APPEARING, animIn);

//(2.3)可以监听动画的执行情况

animIn.addListener(new AnimatorListener() {

@Override

public void onAnimationStart(Animator animation) {

// TODO Auto-generated method stub

}

@Override

public void onAnimationRepeat(Animator animation) {

// TODO Auto-generated method stub

}

@Override //获取进行动画的view的例子

public void onAnimationEnd(Animator animation) {

View view = (View) ((ObjectAnimator) animation).getTarget();

Log.d("WEI",view.toString());

}

@Override

public void onAnimationCancel(Animator animation) {

// TODO Auto-generated method stub

}

});

}

我们也可以设置其他的情况的动画,例如删除

Keyframe kf0 = Keyframe.ofFloat(0.2f, 0.8f);

Keyframe kf1 = Keyframe.ofFloat(0.5f, 0.5f);

Keyframe kf2 = Keyframe.ofFloat(1.0f, 0.0f);

PropertyValuesHolder pvh = PropertyValuesHolder.ofKeyframe( "alpha", kf0, kf1, kf2);

ObjectAnimator animOut = ObjectAnimator.ofPropertyValuesHolder(myLayout, pvh);

animOut.setDuration(lt.getDuration(LayoutTransition.DISAPPEARING));

lt.setAnimator(LayoutTransition.DISAPPEARING, animOut);
如果我们要记住某个时刻动画设置,以便后来恢复,可以使用:

Animator defaultAppearAnimator = lt.getAnimator(APPEARING);
在设置了LayoutTransition后,我们进行添加view的测试,如下:

TextView testView1 = new TextView(this);

testView1.setText("测试Layout Transition。Hello, World! ");

myLayout.addView(testView1);

通过LayoutTranistion将动画加诸在每个view中,animator会复制给每个view。如果这些view有onClick的处理,在进行动画的过程中,如果进行点击,其结果不可预测,因此一般动画设定时间不要过长。
小例子代码在:Pro Android学习:2D动画小例子

相关链接:我的Android开发相关文章
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐