[Android][Animation]
1.View Animation(Tweened Animation)补间动画
View Animation主要是针对View的,而且它只是让View展示指定动画,但是并不会改变View的属性。也就是说使用tweened动画来实现移动,缩放,旋转,透明度,最后都是没有改变view的位置,大小,角度,透明度,我们看到的只是一个动画效果。
1).创建动画对象
(1)直接new
Android提供了四个类TranslateAnimation,ScaleAnimation,RotateAnimation和AlphaAnimation。我们可以通过这四个类实现移动,缩放,旋转和透明度设置。如果一个View要同时执行多个动画可以使用AnimationSet。
例子一:TranslateAnimation
/**
* 确实如果使用TranslateAnimation实现位移动画,如果没有setX,setY,那么view是不会移动到指定位置的,
* 而且通过setX,setY移动view到知道位置的时候,view是会闪一下,如果使用tweened动画来实现缩放,旋转,透明度,最后都是没有改变view的,我们看到的只是一个动画效果
*/
private void transition() {
UiUtil.initialize(this);
animation = new TranslateAnimation(0, UiUtil.getScreenWidth() / 2, 0,
UiUtil.getScreenHeight() / 2);
animation.setDuration(2000);
animation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
Log.i("lgy",
"start----x:" + button.getX() + " y:" + button.getY());
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation animation) {
button.setX(UiUtil.getScreenWidth() / 2);
button.setY(UiUtil.getScreenHeight() / 2);
Log.i("lgy",
"end----x:" + button.getX() + " y:" + button.getY());
}
});
button.startAnimation(animation);
}
例子二:ScaleAnimation
/**
* float fromX 动画起始时 X坐标上的伸缩尺寸
* float toX 动画结束时 X坐标上的伸缩尺寸
* float fromY 动画起始时Y坐标上的伸缩尺寸
* float toY 动画结束时Y坐标上的伸缩尺寸
* int pivotXType 动画在X轴相对于控件位置类型
* float pivotXValue 动画相对于控件的X坐标的开始位置
* int pivotYType 动画在Y轴相对于控件位置类型
* float pivotYValue 动画相对于控件的Y坐标的开始位置
* 1.四个参数的ScaleAnimation默认是动画是从左上角开始,
* 所以new ScaleAnimation(0.0f, 1.4f, 0.0f, 1.4f),
* 你会看到的效果是动画会以view的左上角为定点,开始向x轴和y轴慢慢伸长到1.4倍,
* 动画结束后,由于tweened动画不改变view的属性,view就会恢复为正常状态
* 2.八个参数的ScaleAnimation可以定义相对于控件位置类型
* (1)RELATIVE_TO_SELF 相对于自己
* (2)RELATIVE_TO_PARENT 相对于父控件
* (3)ABSOLUTE 绝对位置 ,例如Animation.ABSOLUTE, new ScaleAnimation(0.0f, 1.4f, 0.0f, 1.4f,
Animation.ABSOLUTE, 200f, Animation.ABSOLUTE, 100f)意思是相对于当前位置
x轴增量为200的坐标点,y轴增量为100的坐标点
如果使用的是RELATIVE_TO_SELF,RELATIVE_TO_PARENT类型,那么他的参数表示的的是倍数
如果使用的是ABSOLUTE,那么他表示的就是具体的增量
*
*/
private void scale() {
UiUtil.initialize(this);
// scaleAnimation = new ScaleAnimation(0.0f, 1.4f, 0.0f, 1.4f);
// scaleAnimation = new ScaleAnimation(0.0f, 1.4f, 0.0f, 1.4f,
// Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation = new ScaleAnimation(0.0f, 1.4f, 0.0f, 1.4f,
Animation.RELATIVE_TO_SELF, 1f, Animation.RELATIVE_TO_SELF, 1f);
scaleAnimation.setDuration(2000);
scaleAnimation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation animation) {
}
});
button.startAnimation(scaleAnimation);
}
例子三:RotateAnimation
/**
* float fromDegrees:旋转的开始角度。
* float toDegrees:旋转的结束角度。
* int pivotXType:X轴上旋转点模式,可以取值为ABSOLUTE、RELATIVE_TO_SELF、RELATIVE_TO_PARENT。
* float pivotXValue:X轴上旋转点的值。
* int pivotYType:Y轴上旋转点模式,可以取值为ABSOLUTE、RELATIVE_TO_SELF、RELATIVE_TO_PARENT。
* float pivotYValue:Y轴上旋转点的值。
*/
private void rotate() {
UiUtil.initialize(this);
rotateAnimation = new RotateAnimation(0f,360f,Animation.RELATIVE_TO_SELF,
0.5f,Animation.RELATIVE_TO_SELF,0.5f);
rotateAnimation.setDuration(2000);
rotateAnimation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation animation) {
}
});
button.startAnimation(rotateAnimation);
}
例子四:AlphaAnimation
/**
* float fromAlpha:开始时候的透明度。
* float toAlpha:结束时候的透明度。
* 这里都是用倍数表示
*/
private void alpha() {
UiUtil.initialize(this);
alphaAnimation = new AlphaAnimation(0f, 1f);
alphaAnimation.setDuration(2000);
alphaAnimation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation animation) {
}
});
button.startAnimation(alphaAnimation);
}
例子五:AnimationSet
/**
* 同时执行多个动画
*/
private void animSet() {
UiUtil.initialize(this);
animationSet = new AnimationSet(true);
alphaAnimation = new AlphaAnimation(0f, 1f);
animationSet.addAnimation(alphaAnimation);
rotateAnimation = new RotateAnimation(0f,360f,Animation.RELATIVE_TO_SELF,
0.5f,Animation.RELATIVE_TO_SELF,0.5f);
animationSet.addAnimation(rotateAnimation);
scaleAnimation = new ScaleAnimation(0.0f, 1.4f, 0.0f, 1.4f,
Animation.RELATIVE_TO_SELF, 1f, Animation.RELATIVE_TO_SELF, 1f);
animationSet.addAnimation(scaleAnimation);
animation = new TranslateAnimation(0, UiUtil.getScreenWidth() / 2, 0,
UiUtil.getScreenHeight() / 2);
animationSet.addAnimation(animation);
animationSet.setDuration(2000);
button.startAnimation(animationSet);
}
(2)AnimationUtils.loadAnimation
也就是通过加载定义好的xml文件来实例化动画对象。
步骤一:在res文件夹下新建一个anim文件夹(anim文件夹下放的是Tweened动画,如果想放Property动画,必须要在res下新建一个animator,把Property动画的文件放里边,在Android Studio里是需要这样区分的,Eclipse没有验证,就不清楚了)
步骤二:在anim里可以定义自己Tweened动画xml文件,他们一般是以set为根标签。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<translate
android:fromXDelta="-100%"
android:toXDelta="0%"
android:duration="1000" />
</set>
步骤三:加载xml,实例化动画对象
/**
* 这里是实现将mContentView从左边移动出现,而mLoadingView向左移动消失的效果
*/
private void xmlAnim() {
contentViewAnim = AnimationUtils.loadAnimation(this, R.anim.tweened_anim_translation);
contentViewAnim.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation animation) {
mContentView.setVisibility(View.VISIBLE);
}
});
mContentView.startAnimation(contentViewAnim);
loadingViewAnim = AnimationUtils.loadAnimation(this, R.anim.tweened_anim_translation2);
loadingViewAnim.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation animation) {
mLoadingView.setVisibility(View.GONE);
}
});
mLoadingView.startAnimation(loadingViewAnim);
}
2).动画监听setAnimationListener
我们可以对动画的行为进行监听,根据需要执行我们的操作,AnimationListener这个接口可以监听到动画开始,重复,动画结束的动作。
loadingViewAnim.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation animation) {
mLoadingView.setVisibility(View.GONE);
}
});
3).插值器Imterpolator
其实插值器就是设置动画改变的速率。
* 1:AccelerateDecelerateInterpolator 加速减速插补器(先慢后快再慢)
* 2:AccelerateInterpolator 加速插补器(先慢后快)
* 3:AnticipateInterpolator 向前插补器(先往回跑一点,再加速向前跑)
* 4:AnticipateOvershootInterpolator 向前向后插补器(先往回跑一点,再向后跑一点,再回到终点)
* 5:BounceInterpolator 反弹插补器(在动画结束的时候回弹几下,如果是竖直向下运动的话,就是玻璃球下掉弹几下的效果)
* 6:CycleInterpolator 循环插补器(按指定的路径以指定时间(或者是偏移量)的1/4、变速地执行一遍,再按指定的轨迹的相反反向走1/2的时间,再按指定的路径方向走完剩余的1/4的时间,最后回到原点。假如:默认是让a从原点往东跑100米。它会先往东跑100米,然后往西跑200米,再往东跑100米回到原点。可在代码中指定循环的次数)
* 7:DecelerateInterpolator 减速插补器(先快后慢)
* 8:LinearInterpolator 直线插补器(匀速)
* 9:OvershootInterpolator 超出插补器(向前跑直到越界一点后,再往回跑)
* 10:FastOutLinearInInterpolator MaterialDesign基于贝塞尔曲线的插补器 效果:依次 慢慢快
* 11:FastOutSlowInInterpolator MaterialDesign基于贝塞尔曲线的插补器 效果:依次 慢快慢
* 12:LinearOutSlowInInterpolator MaterialDesign基于贝塞尔曲线的插补器 效果:依次 快慢慢
setInterpolator(new LinearOutSlowInInterpolator())
4).改变属性
我们知道Tweened动画只是让View展示指定动画,但是并不会改变View的属性。那么如果我们要改变它的属性可以通过View的set方法
/**
* 确实如果使用TranslateAnimation实现位移动画,如果没有setX,setY,那么view是不会移动到指定位置的,
* 而且通过setX,setY移动view到知道位置的时候,view是会闪一下,如果使用tweened动画来实现缩放,旋转,透明度,最后都是没有改变view的,我们看到的只是一个动画效果
*/
private void transition() {
UiUtil.initialize(this);
animation = new TranslateAnimation(0, UiUtil.getScreenWidth() / 2, 0,
UiUtil.getScreenHeight() / 2);
animation.setDuration(2000);
animation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
Log.i("lgy",
"start----x:" + button.getX() + " y:" + button.getY());
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation animation) {
button.setX(UiUtil.getScreenWidth() / 2);
button.setY(UiUtil.getScreenHeight() / 2);
// button.setAlpha(1f);
// button.setScaleX(1.4f);
// button.setScaleY(1.4f);
// button.setRotationX(0);
// button.setRotationY(100);
Log.i("lgy",
"end----x:" + button.getX() + " y:" + button.getY());
}
});
button.startAnimation(animation);
}
2.Drawable Animation(帧动画)
这个其实就是按顺序一帧一帧的播放图片。
1)使用xml加载
步骤一:在res下的anim文件夹下创建帧动画xml文件,这个文件的根标签是animation-list。
<?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/little_gray_01" android:duration="300" />
<item android:drawable="@drawable/little_gray_03" android:duration="300" />
<item android:drawable="@drawable/little_gray_04" android:duration="300" />
<item android:drawable="@drawable/little_gray_05" android:duration="300" />
</animation-list>
步骤二:加载xml,创建对象
/**
* ProgressBar可以用下面这个设置
* bar.setIndeterminate(true);
bar.setIndeterminateDrawable(getResources().getDrawable(R.anim.frame_anim_list));
*/
private void xmlAnimation()
{
imageView.setBackgroundResource(R.anim.frame_anim_list);
AnimationDrawable animation = (AnimationDrawable) imageView.getBackground();
animation.start();
}
2)不使用xml
private void noXmlAnimation()
{
AnimationDrawable anim = new AnimationDrawable();
Drawable drawable1 = getResources().getDrawable(R.drawable.little_gray_01);
Drawable drawable3 = getResources().getDrawable(R.drawable.little_gray_03);
Drawable drawable4 = getResources().getDrawable(R.drawable.little_gray_04);
Drawable drawable5 = getResources().getDrawable(R.drawable.little_gray_05);
anim.addFrame(drawable1, 300);
anim.addFrame(drawable3, 300);
anim.addFrame(drawable4, 300);
anim.addFrame(drawable5, 300);
anim.setOneShot(false);
imageView.setBackground(anim);
anim.start();
}
3.Property Animation
是在Android 3.0中才引进的,它更改的是对象的实际属性,在View Animation(Tween Animation)中,其改变的是View的绘制效果,真正的View的属性保持不变。而且Property Animation不止可以应用于View,还可以应用于任何对象。Property Animation只是表示一个值在一段时间内的改变,当值改变时要做什么事情完全是你自己决定的。
1)ValueAnimator
ValueAnimator包含Property Animation动画的所有核心功能,它是PropertyAnimation动画的基础,ObjectAnimator也是继承了ValueAnimation。
(1)基础用法
这个例子只修改了view的一个属性:x的坐标
/**
* 只修改button的x轴动画
*/
private void valueAnim()
{
UiUtil.initialize(this);
ValueAnimator animator = ValueAnimator.ofFloat(0f,UiUtil.getScreenWidth()/2);
animator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
button.setTranslationX((Float)animation.getAnimatedValue());
}
});
animator.setDuration(2000);
animator.start();
}
(2)修改多个属性
下面展示的是同时修改x坐标和y坐标的值,这里用到了PropertyValuesHolder ,可以使用它来同时执行多个动画。
/**
* 修改button的x轴和Y轴动画,通过下面的方法可以传多个动画
*/
private void valueAnim2()
{
UiUtil.initialize(this);
PropertyValuesHolder xvalue = PropertyValuesHolder.ofFloat("x", 0f,UiUtil.getScreenWidth()/2);
PropertyValuesHolder yvalue = PropertyValuesHolder.ofFloat("y", 0f,UiUtil.getScreenHeight()/2);
ValueAnimator animator = ValueAnimator.ofPropertyValuesHolder(xvalue,yvalue);
animator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
button.setTranslationX((Float)animation.getAnimatedValue("x"));
button.setTranslationY((Float)animation.getAnimatedValue("y"));
}
});
animator.setDuration(2000);
animator.start();
}
(3)监听属性的渐变值
可以通过addUpdateListener监听到属性的渐变值,可以看到下面的代码,
我们可以通过PropertyValuesHolder 的ofFloat给某个属性定义一个propertyName,然后在addUpdateListener里的回调方法onAnimationUpdate,可以通过animation.getAnimatedValue(propertyName)获取对于该属性名的渐变值。
private void valueAnim2()
{
UiUtil.initialize(this);
PropertyValuesHolder xvalue = PropertyValuesHolder.ofFloat("x", 0f,UiUtil.getScreenWidth()/2);
PropertyValuesHolder yvalue = PropertyValuesHolder.ofFloat("y", 0f,UiUtil.getScreenHeight()/2);
ValueAnimator animator = ValueAnimator.ofPropertyValuesHolder(xvalue,yvalue);
animator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
button.setTranslationX((Float)animation.getAnimatedValue("x"));
button.setTranslationY((Float)animation.getAnimatedValue("y"));
}
});
animator.setDuration(2000);
animator.start();
}
2)ObjectAnimator
(1)ObjectAnimator的基本用法
也是修改一个属性值。
/**
* 修改button的x轴动画
*/
private void objectAnim()
{
UiUtil.initialize(this);
ObjectAnimator animator = ObjectAnimator
.ofFloat(button, "translationX", 0f,UiUtil.getScreenWidth()/2);
animator.setDuration(2000);
animator.start();
}
(2)修改多个属性值
/**
* 修改button的x轴和Y轴动画,通过下面的方法可以传多个动画
*/
private void objectAnim2()
{
UiUtil.initialize(this);
PropertyValuesHolder xvalue = PropertyValuesHolder.ofFloat("x", 0f,UiUtil.getScreenWidth()/2);
PropertyValuesHolder yvalue = PropertyValuesHolder.ofFloat("y", 0f,UiUtil.getScreenHeight()/2);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(button, xvalue,yvalue);
animator.setDuration(2000);
animator.start();
}
(3)加载xml方式执行动画
步骤一:在res的animator目录下创建动画xml文件,这动画很明显,是同时执行将view的x坐标和y坐标都移动到400处。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:ordering="together" >
<!-- 动画执行顺序 sequentially:顺序执行;together:同时执行。 -->
<objectAnimator
android:propertyName="translationX"
android:duration="2000"
android:valueFrom="0"
android:valueTo="400"
android:valueType="floatType" />
<objectAnimator
android:propertyName="translationY"
android:valueFrom="0"
android:duration="2000"
android:valueTo="400"
android:valueType="floatType" />
<!-- 动画值的类型 -->
</set>
步骤二:加载xml文件,执行动画
通过AnimatorInflater.loadAnimator方法可以获得一个Animator 对象。
/**
* 修改button的x轴和Y轴动画,通过下面的方法可以传多个动画
*/
private void objectAnimByXml()
{
Animator animator = AnimatorInflater.loadAnimator(this, R.animator.property_tran_x);
animator.setTarget(button);
animator.start();
}
3)AnimatorSet 和 PropertyValuesHolder
AnimatorSet 和PropertyValuesHolder都是可以执行多个动画的,PropertyValuesHolder的动画是必须全部同时执行的,而AnimatorSet 可以控制动画是同时执行还是先后执行。
/**
* AnimatorSet
* play和with可以同时播放多个动画
* play,after,before可以设置动画的先后顺序
* 而PropertyValuesHolder是无法设置动画的先后播放顺序,只能同时执行多个动画
*/
private void objectAnimSet()
{
UiUtil.initialize(this);
ObjectAnimator animatorx = ObjectAnimator
.ofFloat(button, "translationX", 0f,UiUtil.getScreenWidth()/2);
ObjectAnimator animatory = ObjectAnimator
.ofFloat(button, "translationY", 0f,UiUtil.getScreenHeight()/2);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(animatorx).with(animatory);
animatorSet.setDuration(2000);
animatorSet.start();
}
4)ViewPropertyAnimator
ViewPropertyAnimator也是用于同时执行多个动画的,但是它可以直接从view的animate()方法里获得,如果是对view要执行多个动画的情况下,使用它是十分简便的。
/**
* ViewPropertyAnimator
* 如果View只用到一两个动画,那么用ObjectAnimatior就好了,
* 但是如果一个View同时要执行多个动画ViewPropertyAnimator的方法会更佳
*/
private void ViewPropertyAnim()
{
UiUtil.initialize(this);
button.animate()
.translationX(UiUtil.getScreenWidth()/2)
.translationY(UiUtil.getScreenHeight()/2)
.setDuration(2000)
.start();
}
5)布局改变的动画(Viewgroup)
API 11后,在ViewGroup中添加或删除view会触发系统提供的布局动画。
(1)在xml代码中的ViewGroup中添加android:animateLayoutChanges=”true”既可触发系统内置的增加删除item view的动画效果。LinearLayout是继承ViewGroup的这个大家都知道的哦。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/body"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:layout_weight="1"
android:showDividers="middle"
android:orientation="vertical" >
</LinearLayout>
<Button
android:id="@+id/add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="ADD" />
</LinearLayout>
2)代码中的ViewGroup直接设置setLayoutTransition(new LayoutTransition());即可调用系统提供的默认动画。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_linearlaout_anim);
bodyLayout = (LinearLayout) findViewById(R.id.body);
bodyLayout.setLayoutTransition(new LayoutTransition());
add = (Button) findViewById(R.id.add);
add.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
addItem();
}
});
}
(3)自定义ViewGroup增加和删除item的动画
可以通过自己定义LayoutTransition,然后通过setLayoutTransition来设置自己定义的动画。
/**
* 自定义的LayoutTransaction是在API11出现的
* ObjectAnimator outAnimator = new ObjectAnimator().ofFloat(null, "translationX", 0f,UiUtil.getScreenWidth()).setDuration(4000);
* 上面这样在结尾设置setDuration(4000)动画时间是没有效果的
* 需要在layoutTransition对象直接设置动画时间才有效果layoutTransition.setDuration(4000)
*/
private LayoutTransition initCustomLayoutTransition()
{
UiUtil.initialize(this);
LayoutTransition layoutTransition = new LayoutTransition();
ObjectAnimator outAnimator = ObjectAnimator.ofFloat(null, "translationX", 0f,UiUtil.getScreenWidth()).setDuration(3000);
layoutTransition.setAnimator(LayoutTransition.DISAPPEARING, outAnimator);
// layoutTransition.setDuration(4000);
ObjectAnimator intAnimator = ObjectAnimator.ofFloat(null, "translationX", UiUtil.getScreenWidth(),0f);
layoutTransition.setAnimator(LayoutTransition.APPEARING, intAnimator);
//加了下面两个效果感觉不是很好,而且效果也没出来
// ObjectAnimator intOtherAnimator = ObjectAnimator.ofFloat(null, "rotationY", 0,90,0);
// layoutTransition.setAnimator(LayoutTransition.CHANGE_APPEARING, intOtherAnimator);
//
// ObjectAnimator outOtherAnimator = ObjectAnimator.ofFloat(null, "rotationX", 0,-90,0);
// layoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, outOtherAnimator);
return layoutTransition;
}
<1>可以定制dViewGroup的几个动画效果
我们可以定义的动画有一下几种:
*1.LayoutTransition.APPEARING 子View添加到容器中时的过渡动画效果。
*2.LayoutTransition.DISAPPEARING 子View从容器中移除时的过渡动画效果。
*3.LayoutTransition.CHANGE_DISAPPEARING 子View从容器中移除时,其它子view位置改变的过渡动画。
*4.LayoutTransition.CHANGE_APPEARING 子View添加到容器中时,其他子View位置改变的过渡动画。
*5.LayoutTransition.CHANGING 4.1 JellyBean上还有一个增强的功能,可以在容器内的子view的layout发生变化时也播放动画。
下面这段代码就是设置子View从容器中移除时,其它子view位置改变的过渡动画:
layoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, outOtherAnimator);
<2>LayoutTransition需要注意的问题
1.LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING必须要使用PropertyValuesHolder构造的动画才有效
2.在构造PropertyValuesHolder动画时,”left”,”top”,”right”和”bottom”属性至少要写两个,而且如果是两个的时候,必须是左上,左下,右上,右下的模式,不能出现左右,上下的模式
3.对于LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING,在构造PropertyValuesHolder时,所使用的ofInt,ofFloat中的参数值,第一个值和最后一个值必须相同,不然此属性所对应的的动画将被放弃,在此属性值上将不会有效果
/**
* http://blog.csdn.net/harvic880925/article/details/50985596
* PropertyValuesHolder是用于同时执行多个动画,没必要像下面这样,只有一个动画就不必使用PropertyValuesHolder
* 但是LayoutTransition有几个需要注意的问题:
* 1.LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING必须要使用PropertyValuesHolder构造的动画才有效
* 2.在构造PropertyValuesHolder动画时,"left","top","right"和"bottom"属性至少要写两个,而且如果是两个的时候,必须是左上,左下,右上,右下的模式,不能出现左右,上下的模式
* 3.对于LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING,在构造PropertyValuesHolder时,所使用的ofInt,ofFloat中的参数值,第一个值和最后一个值必须相同,不然此属性所对应的的动画将被放弃,在此属性值上将不会有效果
* @return
*/
private LayoutTransition initCustomLayoutTransition2()
{
UiUtil.initialize(this);
LayoutTransition layoutTransition = new LayoutTransition();
PropertyValuesHolder outValuesHolder = PropertyValuesHolder.ofFloat("translationX", 0f,UiUtil.getScreenWidth());
PropertyValuesHolder inValuesHolder = PropertyValuesHolder.ofFloat("translationX", UiUtil.getScreenWidth(),0f);
ObjectAnimator outAnimator = ObjectAnimator.ofPropertyValuesHolder(bodyLayout,outValuesHolder);
layoutTransition.setAnimator(LayoutTransition.DISAPPEARING, outAnimator);
ObjectAnimator intAnimator = ObjectAnimator.ofPropertyValuesHolder(bodyLayout,inValuesHolder);
layoutTransition.setAnimator(LayoutTransition.APPEARING, intAnimator);
PropertyValuesHolder pvhLeft =
PropertyValuesHolder.ofInt("left", 0, 0);
PropertyValuesHolder pvhTop =
PropertyValuesHolder.ofInt("top", 0, 0);
PropertyValuesHolder pvhRight =
PropertyValuesHolder.ofInt("right", 0, 0);
PropertyValuesHolder pvhBottom =
PropertyValuesHolder.ofInt("bottom", 0, 0);
PropertyValuesHolder outOtherValuesHolder = PropertyValuesHolder.ofFloat("rotationY", 0,180,0);
PropertyValuesHolder inOtherValuesHolder = PropertyValuesHolder.ofFloat("rotationX", 0,-180,0);
ObjectAnimator intOtherAnimator = ObjectAnimator.ofPropertyValuesHolder(bodyLayout, pvhRight, pvhTop,outOtherValuesHolder);
layoutTransition.setAnimator(LayoutTransition.CHANGE_APPEARING, intOtherAnimator);
layoutTransition.setDuration(3000);
ObjectAnimator outOtherAnimator = ObjectAnimator.ofPropertyValuesHolder(bodyLayout, pvhRight, pvhTop,inOtherValuesHolder);
layoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, outOtherAnimator);
return layoutTransition;
}
4.Viewpager转场动画
Viewpager本来就有转场动画,但是我们还可以通过PageTransformer设置他的转场动画效果。官网的Using ViewPager for Screen Slides也有介绍。
其实我们要做的很简单,只需要自定义一个PageTransformer,然后在通过Viewpager的setPageTransformer方法设置即可。
当我们实现PageTransformer接口的时候,我们需要实现transformPage方法。里面的两个参数很关键:
View view 这个view即我们能看到的界面;
float position 这个是一个动态属性,是用来控制动画的重要参数;
下面我们通过例子来说明这两个参数。
首先,我给Viewpager的几个界面都设置一个id,pager1=111,pager2=222,pager3=333,这样我们就可以知道在切换界面的时候position 参数改变对应的是哪个view。
public class TestViewPagerActivity extends Activity{
private ViewPager viewPager = null;
private List<LinearLayout> pagers = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_viewpager);
viewPager = (ViewPager) findViewById(R.id.view_pager);
viewPager.setPageTransformer(true, new DepthPageTransformer());
pagers = new ArrayList<LinearLayout>();
Pager pager1 = new Pager(this);
pager1.setId(111);
pager1.setText("界面一");
pager1.setBackgroundColor(Color.RED);
Pager pager2 = new Pager(this);
pager2.setId(222);
pager2.setText("界面二");
pager2.setBackgroundColor(Color.YELLOW);
Pager pager3 = new Pager(this);
pager3.setId(333);
pager3.setText("界面三");
pager3.setBackgroundColor(Color.BLUE);
pagers.add(pager1);
pagers.add(pager2);
pagers.add(pager3);
MyAdapter adapter = new MyAdapter();
adapter.setList(pagers);
viewPager.setAdapter(adapter);
}
private class MyAdapter extends PagerAdapter
{
private List<LinearLayout> list = null;
public List<LinearLayout> getList() {
return list;
}
public void setList(List<LinearLayout> list) {
this.list = list;
}
@Override
public int getCount() {
return list!=null?list.size():0;
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0==arg1;
}
@Override
public void destroyItem(ViewGroup container, int position,
Object object) {
container.removeView(list.get(position));
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
container.addView(list.get(position));
return list.get(position);
}
}
}
然后实现我们自己的PageTransformer,在里面打个日志
Log.i(“lgy”, “position:”+position+” view:”+view.getId());
/**
* @author LGY
*View page :这个当然就是我们在ViewPager中滑动的界面。
*float position :这个参数是动态改变的,是一个float类型,而不是平常我们所理解的int位置,只有很好的理解这个参数我们才能设计出我们想要的效果。
*当position=-1时,表示当前页的前一页,此时该页面是看不见的
*当position= 0时,表示当前页,当前显示页
*当position=-1时,表示当前页的下一页
*position取值为 [-Infinity,-1) -> 页面不可见
*position取值为(1,+Infinity] -> 页面不可见
*position取值为[-1,1] -> 于可见状态区间
如果前一页和下一页基本各在屏幕占一半时,前一页的position是-0.5,后一页的posiotn是0.5,所以根据position的值我们就可以自行设置需要的alpha,x/y信息
*/
public class DepthPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.75f;
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
Log.i("lgy", "position:"+position+" view:"+view.getId());
if (position < -1) { // [-Infinity,-1)[负无穷大,-1)
// This page is way off-screen to the left.这一页是屏幕左边
view.setAlpha(0);
} else if (position <= 0) { // [-1,0]
// Use the default slide transition when moving to the left page
//当向左移动页面的时候,使用默认的幻灯片过渡
view.setAlpha(1);
view.setTranslationX(0);
view.setScaleX(1);
view.setScaleY(1);
} else if (position <= 1) { // (0,1]
// Fade the page out.页面消失了
view.setAlpha(1 - position);
// Counteract the default slide transition
view.setTranslationX(pageWidth * -position);
// Scale the page down (between MIN_SCALE and 1)
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
结果:当我向左滑动,界面一切换到显示界面二的时候的日志如下:
从结果我们可以看出,在切换过程中界面一和界面二我们都可以看到,所以从日志里我们可以看到界面一和界面二的position参数。我们可以再看下面这个图理解
这个图展示的是当界面一滑动到界面的一半的时候,界面一的拿到的position是-0.5,而界面而的position是0.5。
所以根据这个position参数就可以设置界面二的出现动画,如下的代码,我们知道界面二出现的过程中,position是从1到0这样变化的,所以view.setAlpha(1 - position);透明度是从0-1变化。
else if (position <= 1) { // (0,1]
// Fade the page out.页面消失了
view.setAlpha(1 - position);
// Counteract the default slide transition
view.setTranslationX(pageWidth * -position);
// Scale the page down (between MIN_SCALE and 1)
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
}
5.总结
其实还有好多细节没有点 出来,由于没有用到,说要就不探究那么仔细了。
6.参考文章
官方介绍动画的使用
Viewpager动画,这篇文章挺好的
http://blog.csdn.net/yegongheng/article/details/38435553
http://blog.csdn.net/javazejian/article/details/52571779
https://developer.android.com/guide/topics/graphics/view-animation.html
https://developer.android.com/guide/topics/graphics/prop-animation.html
https://developer.android.com/guide/topics/graphics/drawable-animation.html