Android 动画学习">Android 动画学习

android 中动画的介绍

  • 作用

能够让静态的内容变得更加唯美,适当的动画能够给予用户更好的体验。

  • 使用情景

引导页的渐变动画

图片的点击效果,缩放效果

Android 中动画的分类和使用

视图动画

View Animation:视图动画在古老的 Android 版本系统中就已经提供了,只能被用来设置 View 的动画

<alpha>
      android:fromAlpha="float" //动画开始时的透明度(0.0--1.0,0.0是全透明,1.0是不透明)
      android:toAlpha="float" //动画结束时的透明度
  </alpha>
  • alpha 实现淡入的效果
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromAlpha="0.0"
    android:toAlpha="1.0" />
    
将这动画效果添加到View上也只需要一行代码:
view.startAnimation(AnimationUtils.loadAnimation(this, R.anim.fade_in));
  • rotate画面转移旋转动画
<rotate>
      android:fromDegrees="int" //旋转开始角度,正数代表顺时针度数,负数代表逆时针度数
      android:toDegrees="int" //旋转结束角度
      android:pivotX="float" //缩放起点 X 坐标(数值,百分数,百分数p,例如 50表示以当前view左上角加 50px)
      android:pivotY="float" //缩放起点 Y 坐标(50% 表示以当前 View 的左上角加上当前 view 宽高的 50% 作为起始点)
              (50%p 表示以当前 View 的左上角加上父控件宽高的 50% 作为起始点)
  </rotate>
  • rotate :以下示例代码旋转角度从0到360,即旋转了一圈,旋转的中心点都设为了50%,即是View本身中点的位置。
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="2000"
    android:fromDegrees="0"
    android:toDegrees="360"
    android:pivotX="50%"
    android:pivotY="50%" />
    
在 Java 代码中使用
RotateAnimation rotateAnimation = (RotateAnimation) AnimationUtils.loadAnimation(this, R.anim.rotate_one);
view.startAnimation(rotateAnimation);
  • scale`: 渐变尺寸伸缩动画
<scale>
     android:fromXScale="float" //初始 X 轴缩放比例,1.0表示无变化
     android:toXScale="float" //结束 X 轴缩放比例
     android:fromYScale="float" //初始 Y 轴缩放比例
     android:toYScale="float" //结束 Y 轴缩放比例
     android:pivotX="float" //缩放起点 X 轴坐标(参数含义同 rotate )
     android:pivotY="float" //缩放结束 Y 轴坐标
</scale>

PS: 以上四个属性,0.0表示缩放到没有,1.0表示正常无缩放,小于1.0表示收缩,大于1.0表示放大

  • android:pivotX 缩放时的固定不变的X坐标,一般用百分比表示,0%表示左边缘,100%表示右边缘
  • android:pivotY 缩放时的固定不变的Y坐标,一般用百分比表示,0%表示顶部边缘,100%表示底部边缘
  • scale 实现时长为一秒钟的 view 从原有样子放大到 1.5 倍的效果
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromXScale="1.0"
    android:fromYScale="1.0"
    android:pivotX="0%"
    android:pivotY="100%"
    android:toXScale="1.5"
    android:toYScale="1.5" />
    
在 Java 代码中使用
ScaleAnimation zoomOutAnimation = (ScaleAnimation) AnimationUtils.loadAnimation(this, R.anim.zoom_out);
view.startAnimation(zoomOutAnimation);
  • translate画面转移位置移动动画效果
<translate>
     android:fromXDelta="float" //起始点 X 轴坐标(参数含义同 rotate )
     android:fromYDelta="float" //起始点 Y 轴坐标
     android:toXDelta="float" //结束点 X 轴坐标
     android:toYDelta="float" //结束点 Y 轴坐标
</translate>
  • translate 使用例子,以下代码实现的是从左到右的移动效果,起始位置为相对于控件本身-100%的位置,即在控件左边,与控件本身宽度一致的位置;结束位置为相对于父控件100%的位置,即会移出父控件右边缘的位置。
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="2000"
    android:fromXDelta="-100%"
    android:fromYDelta="0"
    android:toXDelta="100%p"
    android:toYDelta="0" />
    
在 Java 代码中使用
TranslateAnimation moveAnimation = (TranslateAnimation) AnimationUtils.loadAnimation(this, R.anim.move_left_to_right);
view.startAnimation(moveAnimation);

帧动画

Drawable Animation:这种动画(也叫 Frame 动画、帧动画)其实可以划分到视图动画的类别,专门用来一个一个的显示 Drawableresources ,就像放幻灯片一样。存放在 res/drawable 目录下

<animation-list
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshor="true"  : true 表示只执行一次,false 表示循环执行
    >
    <item>
      每一帧的动画资源
      android:drawable="drawable name " : 资源文件
      android:duration="1000"           : 一帧显示多长时间
    </item>
  </animation-list>
  • 使用方式
ImageView img = (ImageView)findViewById(R.id.img) ;
img.setBackgroundResource(R.drawable.***) ;

Animation imgAnimation = (AnimationDrawable)img.getBackground() ;
imgAnimation.start() ;
  • 使用注意

    AnimationDrawablestart() 方法不能在 activityonCreat() 中调用, 因为 AnimationDrawable 还未完全附着到 window 上, 所以最好的调用时机时在 onWindowFocusChange() 方法中。 onWindowFocusChange() 方法在 Activity 生命周期中表示 view 的可视, onStart, onResume, onCreate 都不是真正 view visible 的时间点,真正的 view visible 时间点是 onWindowFocusChanged() 函数被执行时。通过下面的执行流程可以清楚了解到 AnimationDrawable 的使用时机。

    1. entry: onStart---->onResume---->onAttachedToWindow----------->onWindowVisibilityChanged--visibility=0---------->onWindowFocusChanged(true)------->
    
    2. exit:  onPause---->onStop---->onWindowFocusChanged(false)  -----------(lockscreen)
    
    3. exit : onPause----->onWindowFocusChanged(false)------>onWindowVisibilityChanged----visibility=8------------>onStop(to another activity)
    

属性动画

Property Animation:属性动画只对 Android 3.0(API 11) 以上版本的 Android 系统才有效,对于低版本的可以使用开源动画库 nineoldandroids 去实现兼容,它在低版本的实现也是通过 View 动画实现,只是使用方式像属性动画。属性动画可以设置给任何 Object ,包括那些还没有渲染到屏幕上的对象。并且属性动画是可扩展的,可以让你自定义任何类型和属性的动画。

  • 属性动画提供的属性有:
Duration : 动画的持续时间
TimeInterpolation: 定义动画变化速率的接口,所有插值器都必须实现此接口,如线性、非线性插值器
TypeEvaluator: 用于定义属性值计算方式的接口,有int,float,color 类型
Animation sets: 动画集合,即可以对一个对象应用多个动画
Frame refresh delay: 多少时间刷新一次,默认为10ms,最终的刷新时间还受系统进程调度和硬件影响
Repeat Country and behavior: 重复次数与方式
  • 属性动画的可以使用在xml中和Java代码中,下面是属性动画在xml中的使用姿势
<set
    android:ordering="together|sequentially"  // 控制动画的启动方式,together(默认)表示同时执行,sequentially表示按照顺序先后执行
    >
    ...
      <objectAnimator>
          android:propertyName="string"       // 必须要设置的节点属性,代表执行动画的属性(通过改名字去引用)
          android:duration="int"              // 动画时常,默认是300 ms
          android:valueFrom="folat|int|color" // 动画的起始点
          android:valueTo="folat|int|color"   // 必须要设置的节点属性,表明动画结束的点
          android:startOffset="int"           // 动画延迟的时间,毫秒为单位
          android:repeatCount="int"           // 动画的重复次数,0表示不重复(默认),-1表示无线重复,1表示执行完动画后再重复一次,也就是动画执行两次
          android:repeatMode="repeat|reverse" //重复的模式
          android:valueType="intType|floatType" //关键参数,如果该value是一个颜色,那么不需要指定该值。
      </objectAnimator>

      <animation>
          android:duration="int"
          android:valueFrom="folat|int|color"
          android:valueTo="folat|int|color"
          android:startOffset="int"
          android:repeatCount="int"
          android:repeatMode="repeat|reverse"
          android:valueType="intType|floatType"
      </animation>
      ...
  </set>

在 Java 代码中调用的方式:
AnimatorSet set = AnimatorInflater.loadAnimation(context,R.animator,****);  // 获取动画资源
set.setTarget(object) ; // 给目标对象设置动画
set.start() ;       // 启动动画
  • 属性代码在Java中的使用姿势,习惯上使用Java代码去实现,容易理解一些。
大多数的情况使用ObjectAnimator就足够了,因为它是的目标对象动画值的处理过程变得足够简单,不用像ValueAnimator那样自己写动画更新的逻辑

但是使用ObjectAnimator 也有一些限制,比如它需要目标对象的属性提供指定的处理方法(譬如:getXXX,setXXX方法)

注意: ObjectAnimator 的动画原理是不停的调用setXXX方法更新属性值,所有使用 ObjectAnimator更新属性时的前提时Object必须声明有getXXX方法

3D 旋转动画实例:
ObjectAnimator.ofFloat(view,"rotationY",0.0f,360.0f).setDuration(1000).start() ;
  • AnimatorSet

AnimatorSet 顾名思义就是动画集合,例如下面的代码实现了 view 对象从不透明到透明的动画后,接着在Y轴上移动了 viewWidth 的宽度

ObjectAnimator a1 = ObjectAnimator.ofFloat(view,"alpha",1.0f,0f) ;  // 从不透明到透明
ObjectAnimator a2 = ObjectAnimator.ofFloat(view,"translationY",0.0f,viewWidth) ;  // 从 0 到view的宽度移动
...
AnimatorSet set = new AnimatorSet() ;
set.setDuration(2000) ;
set.setInterpolator(new LinearInterpolater()) ; // 设置线性匀速插值器
set.play(a1).after(a2) ;
...   // 其他组合方式
set.start() ;

引导页动画例子

  • 实现的效果如下, 代码来自这位仁兄 iwgang

三张图片,每张图片顶部有标题的描述。图片的边角是会露出。当用户左划或者右滑到一定的距离,之前或者之后的图片需要缩小和放大、文字需要淡入或者淡出。例如:第一次启动App显示第一张图篇和文字,当用户左划到第二章图片全部显示的这个过程,这个过程的动画是第一张图片往左缩小、文字往左淡出,第二张的图片逐渐放大、文字淡入直至全部显示。最后的那个立即体验按钮是通过判断是否是最后一张图片而去动态显示的。

这里源码作者的实现是采用 VIewPager 去实现翻页效果。

第一个问题:图片的边角露出如何实现?

利用ViewPager的一个方法去实现,源码中是这么用的: mViewPager.setPageMargin(-dip2px(135)); dip2px是作者封装的屏幕分辨率工具。

第二个问题:滑动视差效果如何实现?

也是利用ViewPager的一个方法是实现, mViewPager.setPageTransformer(false, new ViewPager.PageTransformer() {} 这个方法是ViewPager提供的页面切换时的动画效果。

在重写的 transformPage(View view, float position) 中去实现滑动的视差动画。通过判断当前的position,如果是第一页则图片不缩放,文字标题和描述不缩放、透明度为不透明;如果是第二页则图片XY方向缩放为原来图片的0.85f倍,文字变为透明。以此类推。

 if (position < -1) {	// 错误的情况
     mTitle.setAlpha(0);
     mDesc.setAlpha(0);
} else if (position <= 1) {	// 正常的情况
     float scaleFactor = Math.max(0.85f, 1 - Math.abs(position));
     float scaleTxtFactor = Math.max(0.0f, 1 - Math.abs(position));

    mGuideImage.setScaleX(scaleFactor);
    mGuideImage.setScaleY(scaleFactor);

    mTitle.setScaleX(scaleTxtFactor);
    mTitle.setScaleY(scaleTxtFactor);
    mTitle.setAlpha(0.0f + (scaleTxtFactor - 0.0f) / (1 - 0.0f) * (1 - 0.0f));

    mDesc.setAlpha(mTitle.getAlpha());
    mDesc.setScaleX(scaleTxtFactor);
    mDesc.setScaleY(scaleTxtFactor);
} else {		// 错误的情况
    mTitle.setAlpha(0);
    mDesc.setAlpha(0);
}
  • 源码实现 视差引导页
赞 (0) 评论 分享 ()