2018-05-04

2018-05-23  本文已影响0人  我有一个梦想_先挣它一个亿

动画

Android 动画分类(针对view控件的动画)

总的来说,Android动画可以分为两类:
        最初的传统动画和Android3.0 之后出现的属性动画
        传统动画又包括 帧动画(Frame Animation)和补间动画(Tweened Animation)

传统动画

帧动画
  帧动画是最容易实现的一种动画,这种动画更多的依赖于完善的UI资源,他的原理就是将一张张单独的图片连贯的进行播放,

从而在视觉上产生一种动画的效果;有点类似于某些软件制作gif动画的方式。

<?xml version="1.0" encoding="utf-8"?>
 <animation-list xmlns:android="http://schemas.android.com/apk/res/android">
      <item android:drawable="@drawable/a_0" android:duration="100" /> 
    <item android:drawable="@drawable/a_1" android:duration="100" /> 
    <item android:drawable="@drawable/a_2" android:duration="100" />
 </animation-list>
protected void onCreate(@Nullable Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
       setContentView(R.layout.activity_frame_animation);
       ImageView animationImg1 = (ImageView) findViewById(R.id.animation1); 
      animationImg1.setImageResource(R.drawable.frame_anim1); 
       AnimationDrawable animationDrawable1 = (AnimationDrawable) animationImg1.getDrawable(); 
      animationDrawable1.start(); 
} 
补间动画

补间动画又可以分为四种形式,分别是 alpha(淡入淡出),translate(位移),scale(缩放大小),rotate(旋转)。

alpha_anim.xml 动画实现

<?xml version="1.0" encoding="utf-8"?>
 <alpha xmlns:android="http://schemas.android.com/apk/res/android" 
        android:duration="1000" 
        android:fromAlpha="1.0"
       android:interpolator="@android:anim/accelerate_decelerate_interpolator" android:toAlpha="0.0" />

scale.xml 动画实现

<?xml version="1.0" encoding="utf-8"?>
 <scale xmlns:android="http://schemas.android.com/apk/res/android" 
        android:duration="1000" 
        android:fromXScale="0.0" 
        android:fromYScale="0.0" 
        android:pivotX="50%" 
        android:pivotY="50%"
       android:toXScale="1.0" 
       android:toYScale="1.0"/>

set 标签将多个动画组合

<?xml version="1.0" encoding="utf-8"?> 
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:interpolator="@[package:]anim/interpolator_resource" 
      android:shareInterpolator=["true" | "false"] >
 <alpha
     android:fromAlpha="float" 
    android:toAlpha="float" /> 
<scale 
    android:fromXScale="float" 
    android:toXScale="float" 
    android:fromYScale="float" 
    android:toYScale="float" 
    android:pivotX="float"
     android:pivotY="float" /> 
<translate
     android:fromXDelta="float" 
     android:toXDelta="float" 
    android:fromYDelta="float"
     android:toYDelta="float" />
 <rotate 
    android:fromDegrees="float" 
    android:toDegrees="float"
     android:pivotX="float" 
    android:pivotY="float" />
  </set>

在Activity中

      Animation animation = AnimationUtils.loadAnimation(mContext, R.anim.alpha_anim);
     img = (ImageView) findViewById(R.id.img);
     img.startAnimation(animation);
属性动画

属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。

属性动画自定义

画最关键的三点就是 运动轨迹、小球半径及颜色的变化;我们就从这三个方面展开(用TypeEvaluator 确定运动轨迹)

public class PointSinEvaluator implements TypeEvaluator { 
@Override public Object evaluate(float fraction, Object startValue, Object endValue) { 
      Point startPoint = (Point) startValue; 
      Point endPoint = (Point) endValue;
       float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX()); 
        float y = (float) (Math.sin(x * Math.PI / 180) * 100) + endPoint.getY() / 2;
         Point point = new Point(x, y);
         return point;
 }
 }

PointSinEvaluator 继承了TypeEvaluator类,并实现了他唯一的方法evaluate;这个方法有三个参数,第一个参数fraction 代表当前动画完成的百分比,这个值是如何变化的后面还会提到;第二个和第三个参数代表动画的初始值和结束值。
逻辑很简单,x的值随着fraction 不断变化,并最终达到结束值;y的值就是当前x值所对应的sin(x) 值,然后用x 和 y 产生一个新的点(Point对象)返回。

使用这个PointSinEvaluator 生成属性动画的实例
Point startP = new Point(RADIUS, RADIUS);
//初始值(起点)
 Point endP = new Point(getWidth() - RADIUS, getHeight() - RADIUS);
//结束值(终点) 
final ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointSinEvaluator(), startP, endP);
     valueAnimator.setRepeatCount(-1);
     valueAnimator.setRepeatMode(ValueAnimator.REVERSE); 
      valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 
      @Override
       public void onAnimationUpdate(ValueAnimator animation) { 
      currentPoint = (Point) animation.getAnimatedValue(); postInvalidate(); 
} 
}); 

XML 属性动画

<set android:ordering="sequentially"> 
    <set> 
      <objectAnimator 
          android:propertyName="x" 
          android:duration="500" 
          android:valueTo="400" 
          android:valueType="intType"/> 
      <objectAnimator 
        android:propertyName="y" 
        android:duration="500" 
         android:valueTo="300"
         android:valueType="intType"/> 
  </set> 
    <objectAnimator
       android:propertyName="alpha" 
      android:duration="500"
       android:valueTo="1f"/> 
</set>

使用方式:

    AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext, R.anim.property_animator);
    set.setTarget(myObject); 
    set.start();

Android过渡动画(针对activity页面的动画)

Scene Transition(场景过渡动画)、Activity过渡动画、Shared Element Transition(共享元素过渡动画)

场景切换的共享元素源码已经上传到github
安卓5.0系统引入了共享元素,能做出非常炫酷的场景切换效果,这让人非常兴奋同时非常蛋疼,因为低版本没法使用啊,所以今天就跟大家分享一下自己写的一个库,其实只有2个文件而已,还是叫它工具比较合适吧......非常轻量级,简直是人畜无害,兼容安卓5.0以下的版本。

image
有ActivityA(简称A)和ActivityB(简称B),在A中启动B,再从B回退到A
·A启动B:
image
·B回退到A:
image
原理:

从A启动B时,首先需要构造一个EasyTransitionOptions对象,直接通过EasyTransitionOptions.makeTransitionOptions方法进行构造,传入的参数为ActivityA以及需要共享的元素View


image

首先调用了options.update方法,接着又获取了options的attrs并放到intent中,看看update方法:

image

跟往常一样,构造一个Intent对象,然后调用EasyTransition.startActivity方法,传入了该Intent以及前面构造好的options,我们看看EasyTransition.startActivity做了什么

options使用传入的View填充了之前看到的那个ViewAttrs集合attrs,attrs存储了View的一些属性,分别为:

image

id用于获取B中的对应的View,startX和startY分别为View在A中的x、y坐标,这里通过View的getLocationOnScreen方法获取View在屏幕中的坐标,可以看到该方法的参数为int[] outLocation,以out开头的参数,意思即为执行方法后将填充该参数。width和height分别为View在A中的宽和高。
通过options获取Activity并调用真正的startActivity方法,然后再调用overridePendingTransition(0, 0)将系统的转场动画覆盖,0表示没有转场动画。
然后进入到B,我们在B的onCreate方法中,只调用了一个方法EasyTransition.enter


image

这个方法有很多个重载,最简单的只需要传入一个Activity参数即可。参数都很简单,分别为ActivityB,动画时间,动画的差值器以及动画监听。

通过Activity获取到Intent并拿到从A传入的ViewAttrs集合,接着执行了runEnterAnimation方法,到这里就要开始执行动画了,看看runEnterAnimation方法:


image

首先遍历attrs,通过id找到B中对应的View;然后在ViewTreeObserver.OnPreDrawListener中设置View的属性,其中scale属性设置为A中View的宽高与B中View的宽高的比,transition属性设置为A中View的坐标相对于B中View的坐标的偏移量,之所以使用屏幕坐标就是为了准确地算出坐标的偏移量,而不受状态栏等其他因素的影响。

从B回退到A,在回退的操作中,调用了EasyTransition.exit方法,


image

跟enter方法差不多,通过Activity获取到Intent,再拿到ViewAttrs集合,接着执行了runExitAnimation方法


image

遍历attrs,找到B中对应id的View,只不过这次动画是从View在B中的初始状态开始,变到View在A中的状态,属性还是那些属性,没有啥其他的。不一样的是,在执行动画后需要关闭B,所以调用了View.postDelayed方法,然后finish掉当前的Activity,依旧是覆盖一下系统的转场动画overridePendingTransition(0, 0)

场景过渡动画中有两个特别关键概念:Scene(场景),Transition(过渡)。
 Scene(场景)
     Scene代表一个场景。Scene保存了一个视图层级结构,包括它所有的views以及views的状态,
     通常由getSceneForLayout (ViewGroup sceneRoot,int layoutId,Context context)获取Scene实例。
 
 Transition(过渡)
     Transition框架可以实现在starting scene和ending scene之间执行动画
      我们不需要创建starting scene,因为starting scene通常由当前UI状态决定,我们只需要创建ending scene。
Android动画可以分为两类,最初的传统动画和Android3.0 之后出现的属性动画;
 1.Touch feedback(触摸反馈) 
 2、Reveal effect(揭露效果) 
 3、Activity transitions(Activity转换效果) 
 4、Curved motion(曲线运动) 
 5、View state changes (视图状态改变) 
 6、Animate Vector Drawables(矢量动画)
LayoutAnimation、gridLayoutAnimation-给容器中的控件应用统一动画(针对viewGroup 容器的动画)
LayoutAnimation :普通viewGroup 添加统一的进入动画
gridLayoutAnimation: 针对 gridView 添加进入动画

LayoutAnimation 和 gridLayoutAnimation 在 API 1 中就有的函数,因为是在 API 1 中就引入了,
所以也只能使用 animtion 来做动画,而不能使用 animator。

一、LayoutAnimation

1. xml实现

第一步:在res/anim下新建单个item的slide_in_left.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
       android:duration="1000" >
 <translate
     android:fromXDelta="-30%" 
      android:toXDelta="0" /> 
<alpha 
      android:fromAlpha="0.0"
       android:toAlpha="1.0" />
 </set>

第二步:定义viewGroup的layout_animation

<?xml version="1.0" encoding="utf-8"?>
 <layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android" 
      android:animation="@anim/slide_in_left" 
      android:animationOrder="normal" 
      android:delay="1" />

LayoutAnimation详解:

delay:指每个 Item 的动画开始延时,取值是 android:animation 所指定动画时长的倍数,取值类型可以是 float 类型,也可以是百分数,默认是 0.5;
在 slide_in_left.xml 中android:duration="1000",即单次动画的时长是 1000 毫秒,而我们在这里的指定 android:delay=”1”,即一个 Item 的动画会在上一个 item 动画完成后延时单次动画时长的一倍时间开始,即延时 1000 毫秒后开始

animationOrder:指 viewGroup 中的控件动画开始顺序,取值有 normal(正序)、reverse(倒序)、random(随机)
animation:指定每个 item 入场所要应用的动画。仅能指定 res/aim 文件夹下的 animation 定义的动画,不可使用 animator 动画。

第三步:布局文件中的viewgroup引用

<ListView
    android:id="@+id/listview"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
  android:layoutAnimation="@anim/layout_animation"
/>

第四步:java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ListView listView = (ListView) findViewById(R.id.listview);
    arrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_expandable_list_item_1, getData());
    listView.setAdapter(arrayAdapter);
}
public List<String> getData() {
    ArrayList<String> strings = new ArrayList<>();
    for (int i = 0; i < 20; i++) {
        strings.add("测试"+i);
    }
    return strings;
}


发现:
1.第二屏以及之后的数据并不会有动画
2.listview 中各个 item 从左至右滑入位置
3.动画仅在第一次创建时有用,后期加入的数据,将不会再有动画

android:layoutAnimation 只在 viewGroup 创建的时候,才会对其中的 item 添加动画。在创建成功以后,再向其中添加 item 将不会再有动画。

2. LayoutAnimation 的代码实现—LayoutAnimationController
Animation loadAnimation = AnimationUtils.loadAnimation(this, R.anim.slide_in_left);
LayoutAnimationController layoutAnimationController=new LayoutAnimationController(loadAnimation);
layoutAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL);
layoutAnimationController.setDelay(1);
listView.setLayoutAnimation(layoutAnimationController);
listView.startLayoutAnimation();

二、GridLayoutAnimation

1. xml实现

建立item的动画,和LayoutAnimation一样的slide_in_left.xml
建立gridlayout_animation.xml

<?xml version="1.0" encoding="utf-8"?>
<gridLayoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
                     android:rowDelay="75%"
                     android:columnDelay="60%"
                     android:directionPriority="row"
                     android:direction="top_to_bottom|right_to_left"
                     android:animation="@android:anim/slide_in_left"
/>

rowDelay:每一行动画开始的延迟。与 LayoutAnimation 一样
columnDelay:每一列动画开始的延迟。取值类型及意义与 rowDelay 相同。
directionPriority:方向优先级。取值为 row,collumn,none,意义分别为:行优先,列优先,和无优先级(同时进行)
direction:gridview 动画方向。
left_to_right:列,从左向右开始动画
right_to_left :列,从右向左开始动画
top_to_bottom:行,从上向下开始动画

bottom_to_top:行,从下向上开始动画
这四个值之间可以通过“|”连接,从而可以取多个值。很显然 left_to_right 和 right_to_left 是互斥的,top_to_bottom 和 bottom_to_top 是互斥的。如果不指定 direction 字段,默认值为 left_to_right | top_to_bottom;即从上往下,从左往右。
animation: gridview 内部元素所使用的动画。

xml中引用
<GridView
    android:id="@+id/grid"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:columnWidth="90dp"
    android:gravity="center"
    android:horizontalSpacing="10dp"
    android:layoutAnimation="@anim/gridlayout_animation"
    android:numColumns="auto_fit"
    android:stretchMode="columnWidth"
    android:verticalSpacing="10dp"
/>

最后一步

arrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_expandable_list_item_1, getData());
gridView.setAdapter(arrayAdapter);
上一篇 下一篇

猜你喜欢

热点阅读