美文网首页
2018-05-04

2018-05-04

作者: 我有一个梦想_先挣它一个亿 | 来源:发表于2018-05-23 11:52 被阅读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);
    

    相关文章

      网友评论

          本文标题:2018-05-04

          本文链接:https://www.haomeiwen.com/subject/uqfjrftx.html