android动画分析

  • 一、view动画(视图动画)

    主要方法介绍:
      //设置插值器:(后面会有插值器的介绍)
       setInterpolator(Context context, int resID)
       setInterpolator(Interpolator i)
      //设置动画执行的时间:
       setDuration(long durationMillis) 
      //设置动画重复次数 
      //注意:这里设置的是重复次数,即动画总的执行次数是1+repeatCount
      setRepeatCount(int repeatCount)
      //设置动画重复方式(参数有两个值:Animation.RESTART:重新开始  Animation.REVERSE:第二遍动画倒序执行),这个只有在动画执行次数大于1次是生效
      setRepeatMode(int repeatMode)
      //设置动画延迟时间
      setStartTime(long startTimeMillis)
      //设置动画停止时是否还显示控件  默认是false
      setFillEnabled(boolean fillEnabled)
      //设置动画停止时是否显示第一帧动画(即停止时是否在原始位置显示) 默认是true
      setFillBefore(boolean fillBefore)
      //设置动画停止时是否显示最后一帧动画(即停止时是否在终点位置显示) 默认是false
      setFillAfter(boolean fillAfter)
      //fillEnabled、fillBefore、fillAfter理解:
      //   - 1.fillEnabled=false时,fillBefore、fillAfter的设置无效
      //    当三者都设置true时,等价于fillEnalbed=false
      //   - 2.fillEnabled=true&&fillBefore=true&&fillAfter=false 是系统默认的设置,即动画停止时会在原始位置显示控件
      //   - 3.fillEndabled=true&&fillBefore=false&&fillAfter=true 动画停止时会在终点显示控件
      
      //设置动画的监听事件
      setAnimationListener(Animation.AnimationListener listener)
      
       public interface AnimationListener {
        //动画开始
        void onAnimationStart(Animation var1);
        //动画结束
        void onAnimationEnd(Animation var1);
        //动画重复
        void onAnimationRepeat(Animation var1);
        }
    
上述方法都有对应的get方法
  • 1.平移

    将控件从指定的坐标(x1,y1)平滑的移动目的坐标处(x2,y2),使用方式有两种,一种是通过代码设置(推荐的方式),一种是通过xml文件设置(下文会有介绍)。

    构造函数:

    //参数:上下文对象,资源文件配置
    public TranslateAnimation(Context context, AttributeSet attrs) {
        
    }

    //参数:起始点x坐标,起始点y坐标,终点x坐标,终点y坐标
    public TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta) {
       
    }
    //参数:参数很多,但是很好理解,总体来说就两种类型type和value,
    //type是后面value的类型,有两个值:Animation.RELATIVE_TO_SELF:value的值是相对于控件自身来测量的值,Animation.RELATIVE_TO_PARENT:value的值是相对于父布局来测量的。
    //value是定义的具体的数值,fromXValue/fromYValue  是起始点坐标的x和y值,toXType/toYValue 是终点坐标的x和y值
    public TranslateAnimation(int fromXType, float fromXValue, int toXType, float toXValue, int fromYType, float fromYValue, int toYType, float toYValue) {
      
    }

使用:

        //使用的是4个参数的构造函数,指定了起点和终点的坐标
        //获取屏幕的宽和高
        WindowManager windowManager = getWindowManager();
        Display display = windowManager.getDefaultDisplay();
        Point point = new Point();
        display.getSize(point);
        int screenWidth = point.x;//屏幕宽
        int screenHeight = point.y;//屏幕高
        TranslateAnimation translateAnimation = new TranslateAnimation(0,
                screenWidth  - imageView.getWidth(),
                0,
                screenHeight  - imageView.getHeight());
        //动画停止时在终点显示控件
        translateAnimation.setFillEnabled(true);
        translateAnimation.setFillBefore(false);
        translateAnimation.setFillAfter(true);
        //重复次数,此时动画一共会执行3次
        translateAnimation.setRepeatCount(2);
        //重复的模式
        // Animation.RESTART:重新开始  Animation.REVERSE:第二遍动画倒序执行
        translateAnimation.setRepeatMode(Animation.REVERSE);
        translateAnimation.setDuration(2000);
        imageView.startAnimation(translateAnimation);
  • 2.旋转

    将控件绕某一点进行旋转
    构造函数:
    //参数:上下文对象,资源文件配置
    public RotateAnimation(Context context, AttributeSet attrs) {
        
    }
    //参数:开始的角度,最终的角度(即:从fromDegrees旋转到toDegrees,比如从45度旋转到90度),没有指定轴点坐标,默认会以控件的左上角的点为轴点旋转
    public RotateAnimation(float fromDegrees, float toDegrees) {
       
    }
    //参数:开始的角度,最终的角度,旋转轴点x坐标和y坐标
    public RotateAnimation(float fromDegrees, float toDegrees, float pivotX, float pivotY) {
        
    }
     //参数:开始的角度,最终的角度,后面四个参数定义的是旋转轴点坐标,type和value参考上面平移的解释
    public RotateAnimation(float fromDegrees, float toDegrees, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue) {
       
    }

使用:

    //这里使用的是按照控件的中心点旋转,如果使用两个参数的构造器,则按照控件的左上角的点旋转
    RotateAnimation rotateAnimation = new RotateAnimation(0, 90,
                imageView.getWidth() / 2, imageView.getHeight() / 2);
    rotateAnimation.setDuration(2000);
    rotateAnimation.setFillEnable(true);
    rotateAnimation.setFillBefore(false);
    rotateAnimation.setFillAfter(true);
    //可以设置其他属性
    imageView.startAnimation(rotateAnimation);
  • 3.缩放

将控件按照一定的比例进行放大或缩小。
构造函数:

    //参数:上下文对象,资源配置
    public ScaleAnimation(Context context, AttributeSet attrs) {
        
    }
    //参数:将x轴从fromX缩放到toX,将y轴从fromY缩放到toY,默认是以控件的左上角的角点作为缩放的基点
    //理解:将x的宽度从(fromX*控件的宽度)缩放到(toX*控件的宽度),将控件的高度从(fromY*控件的高度)缩放到(toY*控件的高度),缩放是以控件的宽高为基数进行操作的,比如(1f,0.5f,1f,0.5f)是将控件的宽高缩小一倍
    public ScaleAnimation(float fromX, float toX, float fromY, float toY) {
        
    }
    //参数:将x轴从fromX缩放到toX,将y轴从fromY缩放到toY,pivotX和pivotY是放大缩小的轴点坐标
    public ScaleAnimation(float fromX, float toX, float fromY, float toY, float pivotX, float pivotY) {
        
    }
    //参数比上面的构造器多了type值,type和value的含义同上面动画的一样
    public ScaleAnimation(float fromX, float toX, float fromY, float toY, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue) {
       
    }

使用:

      //将控件整体缩放一倍,以左上角的点
     ScaleAnimation scaleAnimation = new ScaleAnimation(1f, 0.5f,
                1f, 0.5f);
     scaleAnimation.setDuration(2000);
     scaleAnimation.setFillEnabled(true);
     scaleAnimation.setFillBefore(false);
     scaleAnimation.setFillAfter(true);
     imageView.startAnimation(scaleAnimation);
  • 4.渐变(改变透明度)

构造器:

  //参数:上下文对象,配置的参数
   public AlphaAnimation(Context context, AttributeSet attrs) {
        super(context, attrs);
 
    }
    
   //参数:起始透明度,最终透明度
    public AlphaAnimation(float fromAlpha, float toAlpha) {
      
    }

使用:

    AlphaAnimation alphaAnimation = new AlphaAnimation(1f, 0.2f);
    alphaAnimation.setDuration(2000);
    alphaAnimation.setFillAfter(true);
    imageView.startAnimation(alphaAnimation);

上面写的都是基本的用法,一般来说动画都没有单一的,都是组合动画,组合动画的使用主要用到一个类:AnimationSet,通过它将单一的动画组合起来。
AnimationSet的构造器:

    //参数:上下文对象,配置的参数
     public AnimationSet(Context context, AttributeSet attrs) {
        super(context, attrs);
     }
    // 参数:是否使用用一个插值器,如果复杂动画的每一种动画都有自己的插值器则设置为false,true表示多种动画使用同一个插值器
     public AnimationSet(boolean shareInterpolator) {
      
     }

使用:

      ScaleAnimation scaleAnimation = new ScaleAnimation(1f, 0.5f, 1f, 0.5f);
      RotateAnimation rotateAnimation = new RotateAnimation(0, 180, imageView.getWidth() / 2, imageView.getHeight() / 2);
      AlphaAnimation alphaAnimation = new AlphaAnimation(1f, 0.5f);
      AnimationSet animationSet = new AnimationSet(false);
      animationSet.addAnimation(scaleAnimation);
      animationSet.addAnimation(rotateAnimation);
      animationSet.addAnimation(alphaAnimation);
      animationSet.setFillAfter(true);
      animationSet.setDuration(2000);
      imageView.startAnimation(animationSet);

使用AnimationSet创建的组合动画是同时执行的,即多个子动画同步运行,如果想子动画依次执行,就不能使用animationSet,需要给每个子动画增加事件监听器,在上一个动画执行完毕的时候执行下一个动画,如:

          scaleAnimation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                imageView.startAnimation(rotateAnimation);
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });

view动画还可以通过xml进行设置,这种方式需要提前设置好,但是在实际项目中有很多动画需要的参数是无法提前知道的,因此通过java代码设置动画是最好的方式。但是不妨碍我们进行学习。xml文件都放在项目的res/anim文件夹中。

<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="2000"
    android:fillAfter="true">
    <translate
        android:fromXDelta=""
        android:fromYDelta=""
        android:toXDelta=""
        android:toYDelta="" />
    <scale
        android:fromXScale=""
        android:fromYScale=""
        android:pivotX=""
        android:pivotY=""
        android:toXScale=""
        android:toYScale="" />
    <rotate
        android:fromDegrees=""
        android:pivotX=""
        android:pivotY=""
        android:toDegrees="" />
    <alpha
        android:fromAlpha=""
        android:toAlpha="" />

</set>

在项目中调用该动画(R.anim.myanimation是上面创建的动画的xml文件):

      Animation animation = AnimationUtils.loadAnimation(this, R.anim.myanimation);
      imageView.startAnimation(animation);

view动画的对控件的改变只是视觉上的改变,并没有从根本上改变,比如平移动画,只是视觉上平移,实际上view还是在原来的位置,比如点击事件,只有点击原始的位置才能触发。

  • 二、帧动画

帧动画就是将一系列图片在一定时间内一张一张的显示出来的过程。主要使用的是AnimationDrawable类。
构造器:

 public AnimationDrawable() {
        
    }

主要方法:

 //visible设置动画是否可见,
 //restart用来设置动画重启时从第几帧开始显示,restart=true,动画重启时从第一帧开始显示,restart=false动画重启时从暂停时的那一帧开始显示
public boolean setVisible(boolean visible, boolean restart) {}

//开始动画
public void start() {}
//停止动画
public void stop() {}
//是否正在执行
public boolean isRunning(){}
//获取动画的帧数,也就是获取有多少张图
public int getNumberOfFrames(){}
//获取指定下标的帧的图
public Drawable getFrame(int index){}
//获取指定下标的帧的持续时间
 public int getDuration(int i){}
 //是否执行一次
 public boolean isOneShot(){}
 //设置动画只执行一次
 public void setOneShot(boolean oneShot)
  //增加子视图和对应的持续时间
public void addFrame(@NonNull Drawable frame, int duration) {}

使用:

        animationDrawable = new AnimationDrawable();
        Drawable drawable1 = getResources().getDrawable(R.drawable.image1);
        Drawable drawable2 = getResources().getDrawable(R.drawable.image2);
        Drawable drawable3 = getResources().getDrawable(R.drawable.image3);
        Drawable drawable4 = getResources().getDrawable(R.drawable.image4);
        Drawable drawable5 = getResources().getDrawable(R.drawable.image5);
        animationDrawable.addFrame(drawable1, 200);
        animationDrawable.addFrame(drawable2, 200);
        animationDrawable.addFrame(drawable3, 200);
        animationDrawable.addFrame(drawable4, 200);
        animationDrawable.addFrame(drawable5, 200);
        animationDrawable.setOneShot(true);

        //开始动画
         private void startFrameAnimation() {
        imageView.setImageDrawable(animationDrawable);
        animationDrawable.start();
        }
        //结束动画
         private void stopFrameAnimation() {
        animationDrawable.stop();
        }

帧动画使用简单,但是容易引起OOM,必须要使用时尽量避免使用大尺寸的图片。

  • 三、属性动画

    属性动画是Android3.0提出的,主要通过数值的不断变化,来改变控件的属性,从而达到产生动画的效果。并且其可以使用于任何java对象上,不在局限于控件。
    属性动画主要依赖两个类:ValueAnimator和ObjectAnimator。
    ####1、ValueAnimator
    

构造器:

    //无参构造器,一般不使用 
    public ValueAnimator() {
     }

常用方法:

    //参数:参数可为多个,数值从第一个参数以int的类型过渡到第2个参数,再从第2个参数过渡到第3个参数,以此类推
    //注:如果参数为一个,查看源码,发现如果参数为一个,动画将不执行,因为系统不知道动画的开始值
     public static ValueAnimator ofInt(int... values)
     //设置过渡的值
     public void setIntValues(int... values)
    //参数:多个颜色值,颜色进行平滑过渡
    public static ValueAnimator ofArgb(int... values)
    //参数:以float的类型平滑过渡
    public static ValueAnimator ofFloat(float... values) 
     public void setFloatValues(float... values)
    //参数:evaluator是估值器(下面会有介绍) 多个对象进行过渡
    public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values)
    public void setObjectValues(Object... values) 
    //参数:设置动画持续时间
    public ValueAnimator setDuration(long duration)
    //设置动画到指定的时间点,playTime在0和动画持续时间之内,大于持续时间按照持续时间处理
    public void setCurrentPlayTime(long playTime)
    //延时播放动画
    public void setStartDelay(long startDelay)
    //设置重复次数
    public void setRepeatCount(int value)
    //设置重复模式
    public void setRepeatMode(@RepeatMode int value)
    //设置数值变化监听器
    public void addUpdateListener(AnimatorUpdateListener listener)
    //移除所有的监听器
    public void removeAllUpdateListeners()
    //移除指定的监听器
    public void removeUpdateListener(AnimatorUpdateListener listener)
     //设置插值器(下面会有解释)
     public void setInterpolator(TimeInterpolator value)
     //设置估值器
     public void setEvaluator(TypeEvaluator value)
     //启动动画
     public void start()
     //取消动画
     public void cancel() 
     //动画结束
     public void end()
     //动画重新开始
     public void resume()
     //动画暂停
     public void pause()

使用:

     ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 10);
     valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
          @Override
          public void onAnimationUpdate(ValueAnimator animation) {
              //从1过渡到10的时候中间值
              Log.i("info", "" + (int)animation.getAnimatedValue());
          }
      });
      valueAnimator.setDuration(10);
      valueAnimator.start();

属性动画的本质就是利用数值的不断变化,改变对象的属性,从而达到动画的效果。如下,是将imageview的宽度从原始宽度过渡到屏幕宽度:

        WindowManager windowManager = getWindowManager();
        Point outPoint = new Point();
        windowManager.getDefaultDisplay().getSize(outPoint);
        int width = outPoint.x;//屏幕的宽度
        int imageViewWidth = imageView.getLayoutParams().width;
        ValueAnimator valueAnimator = ValueAnimator.ofInt(imageViewWidth, width);
        valueAnimator.setDuration(5000);
        valueAnimator.addUpdateListener(new         ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int currenWidth = (int) animation.getAnimatedValue();
                //控件设置新的宽度
                imageView.getLayoutParams().width = currenWidth;
                //重新绘制
                imageView.requestLayout();
            }
        });
        valueAnimator.start();

从上面可以看出ValueAnimator是在值改变以后手动修改对象的属性,来实现动画的。

2、ObjectAnimator

构造器:

  //无参构造器,一般不使用
   public ObjectAnimator() {
   }

常用方法:

    //参数:动画执行的对象,执行动画的对象的属性名字,动画的起始值、过渡值、最终值
    public static ObjectAnimator ofInt(Object target, String propertyName, int... values)
    //参数:动画执行的对象,执行动画的属性名字x和y,执行动画的路径
    //其实就是将path的x、y指定给object的(xPropertyName、yPropertyName)
    public static ObjectAnimator ofInt(Object target, String xPropertyName, String yPropertyName, Path path)
    //颜色值过渡动画
    public static ObjectAnimator ofArgb(Object target, String propertyName, int... values)
    //参数:动画执行的对象,属性的名称,估值器,过渡的对象或最终的对象
    public static ObjectAnimator ofObject(Object target, String propertyName,
            TypeEvaluator evaluator, Object... values) 

其他方法和ValueAnimator的差不多,从上面的方法名以及源码知道ObjectAnimator是自动将数值的变化指定给target对象的属性,其中propertyName就是target对象的某个属性的名字。而自动赋值的前提是target对象的propertyName属性有get和set方法,否则该动画是无法执行的。
ObjectAnimator其实底层也是使用deValueAnimator来进行播放动画的,先解释一个插值器和估值器,以及他们的使用。

  • 估值器(Evaluator)

估值器主要是用来决定数据是如何过渡的,定义过渡的规则。系统有已经写好的估值器,比如:IntEvaluator、IntEvaluator等,当我们需要动画按照自定义的规则执行时,就需要自定义的估值器。
使用:

public class MyCustomEvaluator implements TypeEvaluator<Integer> {
    @Override
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        //写入自定义的规则
        return null;
    }
}

主要就是实现TypeEvaluator的evaluate这个方法,参数:fraction是动画进行的百分比值,startValue和endValue是动画的起始值和最终值。
例子(均匀的改变imageview的透明度)
上代码:

    public class MyCustomEvaluator implements TypeEvaluator<Float> {

          @Override
          public Float evaluate(float fraction, Float startValue, Float endValue) {
                 //匀速改变数值
                 return (Float) (startValue + (endValue - startValue) * fraction);
          }
      }

在Activity中:
     private void startAnimator() {
        ObjectAnimator objectAnimator = ObjectAnimator.ofObject(imageView, "alpha", new MyCustomEvaluator(), 1f, 0.3f);
        objectAnimator.setDuration(2000);
        objectAnimator.start();
     }
  • 插值器(Interpolator)

插值器主要是决定动画过渡的速度,设置是匀速、加速、还是减速或者其他。系统提供了9种插值器供选择。

  • AccelerateInterpolator(@android:anim/accelerate_interpolator) 加速
  • OvershootInterpolator (@android:anim/overshoot_interpolator)快速完成,超出结束值在返回到结束值
  • AccelerateDecelerateInterpolator(@android:anim/accelerate_decelerate_interpolator) 先加速,在减速
  • AnticipateInterpolator(@android:anim/anticipate_interpolator)先退后,再加速执行
  • AnticipateOvershootInterpolator(@android:anim/anticipate_overshoot_interpolator )先退后,再加速,然后再超出结束值时返回结束值
  • BounceInterpolator(@android:anim/bounce_interpolator) 最后阶段弹球的效果
  • CycleInterpolator(@android:anim/cycle_interpolator) 周期性执行动画
  • DecelerateInterpolator(@android:anim/decelerate_interpolator)减速执行动画
  • LinearInterpolator(@android:anim/linear_interpolator)匀速执行动画

当上述插值器无法满足要求时就需要自定义的插值器。
使用:

public class MyCustomInterpolator implements TimeInterpolator {
    @Override
    public float getInterpolation(float input) {
         //此处写入逻辑规则
        return 0;
    }
}

文中有写的不对的欢迎大家指出,一起学习,一起进步。
送上demo,内有购物车增加商品的动画

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,753评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,668评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,090评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,010评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,054评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,806评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,484评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,380评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,873评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,021评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,158评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,838评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,499评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,044评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,159评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,449评论 3 374
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,136评论 2 356

推荐阅读更多精彩内容

  • 【Android 动画】 动画分类补间动画(Tween动画)帧动画(Frame 动画)属性动画(Property ...
    Rtia阅读 6,164评论 1 38
  • 1 背景 不能只分析源码呀,分析的同时也要整理归纳基础知识,刚好有人微博私信让全面说说Android的动画,所以今...
    未聞椛洺阅读 2,711评论 0 10
  • Android 动画种类 View Animation: 视图动画(Tween(补间)动画),只能被用来设置Vi...
    innovatorCL阅读 406评论 0 0
  • 一: 传统 View 动画(Tween/Frame) 1.1 Tween 动画 主要有 4 中:缩放、平移、渐变、...
    dfg_fly阅读 721评论 1 2
  • 如果不是困的特别要命,我总是无法睡到大天亮的。这不?经过了这几日的休整,精神日渐恢复的我,便再也无法昏昏沉沉...
    泡泡鱼dairying阅读 232评论 0 1