Material-Animations-master 学习笔记

Material-Animations-master 学习笔记#

好久都有更新博客了,从入安卓开始,学习,上班,最近跳槽了,去了新东家那,离自己的心中的工作又进了一步,新单位同事,领导都挺好,可惜,事业上刚有起色,感情上却受到打击,哎,写一篇博客安慰一下自己吧。

最近公司没有新的业务,自己也抽空学习一些新东西,比如5.0新出的TransitionAnimation,虽然之前也接触过,想学,不过一直没有时间,最近学着都敲了一遍,感觉蛮不错的,参考的项目就是Material-Animations-master,一个特别棒的介绍过渡动画和Transition的项目。

先总体介绍下,总体分四部分,简单的过渡动画,分享元素的过渡动画,通过Transition实现的view动画,ReveaAimation四种,接下来都以此介绍一下。

简单过渡动画

简单的过渡动画分三种吧,Slide,Fade,Explode,滑动,渐变,爆炸三种,基本的使用方法

        Slide slideTransition=new Slide();
        slideTransition.setSlideEdge(Gravity.LEFT);
        slideTransition.setDuration(getResources().getInteger(R.integer.anim_duration_long));
        getWindow().setReenterTransition(slideTransition);
        getWindow().setExitTransition(slideTransition);

简单的就是new一个Transition对象,做一些基本设置就可以了,动画有了,接下来就是要设置到指定的位置。

        getWindow().setEnterTransition(slideTransition);//设置进入动画
        getWindow().setExitTransition(slideTransition);//设置退出动画
        getWindow().setReturnTransition(slideTransition);//设置返回的动画(这个没具体试过)
        getWindow().setReenterTransition(slideTransition);//设置重新进入的动画

简单的过渡动画就这么简单,接下来就是使用startActivity就可以了,在项目中使用了一下别的东西,比如DataBindig,还有RecyclerView,首页面的跳转是通过SamplesRecyclerAdapter里面统一处理的,封装了两个方法用于跳转的不同情况。在Transition中还有一种就是使用XML去编写Transaction,简单的操作跟属性动画并无区别,新建一个transition文件夹,在里面创建文件就可以了, 并不困难,同样的在使用时候使用TransitonSet进行控制,也有interpolator等属性。

    transition= TransitionInflater.from(this).inflateTransition(R.transition.explode);

简单的inflate操作,不难理解。

分享元素动画

分享元素作为一种非常有视觉层次感的过渡效果,是值得去追求和学习的。
先说首页跳转到shareFragment的分享元素吧,在adapter中设置的点击时间具体代码

     private void transitionToActivity(Class target,SampleViewHolder holder,Sample sample){
        final Pair<View,String>[] pairs=TransitionHelper.
                createSafeTransitionParticipants(activity,false,
                        new Pair<>(holder.binding.sampleIcon,activity.getString(R.string.square_blue_name)),
                        new Pair<>(holder.binding.sampleName,activity.getString(R.string.sample_blue_title)));
        startActivity(target,pairs,sample);
    }

可以看到在使用的过程中出现了一个新的类 Pair,简单来说就是一个容器类,跟Map,Set之类的差不多,不过在这里使用的是View和String。用来标记被共享的元素和共享元素的name。在首页的使用过程中是在Adapter中的,所以这种方式可以使用在一些列表或者图片列表效果中,效果会很棒,通过TransitionHelper.createSafeTransitionParticipants方法创建一个Pair对象数组,包含这目标Activity,是否包含目标statusBar,以及两个包含着View与String对应的Pair对象。
接下来通过

    private void startActivity(Class target, Pair<View, String>[] pairs, Sample sample) {
        Intent i=new Intent(activity,target);
        ActivityOptionsCompat transitionActivityOptions=ActivityOptionsCompat.
                makeSceneTransitionAnimation(activity,pairs);
        i.putExtra("sample",sample);
        activity.startActivity(i,transitionActivityOptions.toBundle());
    }

通过ActivityOptionsCompat.makeSceneTransitionAnimation方法来创建一个ActivityOptions对象,其实在5.0之前或者说在没有分享元素,Transition的时候我们也还是可以通过这种方式来控制要启动的actiivty的动画的,使用之前的补间动画就可以。这样一个简单的分享元素动画就实现了, 不过在项目中,我们可以发现,其实在shareFragment中并不是一个简单的Activity,而是包含着两个Fragment的Activity主体内容并没有在activity中,而且值得注意的是,在共享的两个View 中其中一个是在Activity中另一个则是在包含的Fragment中,而在这个Fragment中没有做一些过多的操作,仅仅是设置了一下过度元素效果,5.0中包含以下效果:

  • changeBounds 改变目标视图的布局边界
  • changeClipBounds 裁剪目标视图边界
  • changeTransform 改变目标视图的缩放比例和旋转角度
  • changeImageTransform 改变目标图片的大小和缩放比例

通过这两点,可以发现,对于共享元素,没有要求指定要在同一个界面中,一个在Activity一个在Fragmen,或者两个都在Fragment中,目测只要能够显示都可以,必要的实在xml文件中要设置制定的属相,transitioonName作为别分享元素的标记,要与之前在pair中包括的View和String相对应。然后介绍下Fragment设置共享元素效果的方法。直接在开启的事务中添加addSharedElement()这个方法,传入View和String,当然还是要保持相同的transitionName。更多的就是有两个方法,用来判断是否可以让两个过渡动画同时进行,感觉还是不同时进行好一点。

View animations

这个讲的不是过渡动画,就是简单的view动画,不过不同我们之前学习的补间或者属性动画,这种动画是通过两个不同的scene来实现的,感觉这个才是Transition 的本质,过渡动画和分享元素是它的延伸。scene这个单词翻译过来是场景,那就叫过场动画吧,以便与过渡动画区分一下,并没有切换Activity或者Fragment只是换了一个场景。在android的发展过程中,随着用户数量的整体系统平台的提升,越来越多或者说更加优良,有视觉冲击的动画被使用, 也出现了很多不同的实现动画的形式,除了我们所熟知的帧动画,属性动画,补间动画,更多的矢量图动画,过场动画将被越来越的使用。
在这个项目中使用过场动画有两处,一种简单的改变位置和大小,另一种是改变场景。分别介绍一下。

位置大小

先上代码,很好理解

         TransitionManager.beginDelayedTransition(viewRoot);
        LinearLayout.LayoutParams lp= (LinearLayout.LayoutParams) square.getLayoutParams();
        if(positionChaged){
            lp.gravity= Gravity.CENTER;
        }else {
            lp.gravity=Gravity.LEFT;
        }
        positionChaged=!positionChaged;
        square.setLayoutParams(lp);

其中viewRoot是视图的布局,square是要改变的view。首先会调用TransitionManager.beginDelayedTransition();方法来确定要施展动画的布局和Transition的类型,只添加view就是使用默认的Transition,之后就是简单的更改布局中的属性或者view自身的属性来实现动画效果。

         TransitionManager.beginDelayedTransition(viewRoot);
        ViewGroup.LayoutParams params=square.getLayoutParams();
        if(sizeChanged){
            params.width=saveWidth;
        }else{
            saveWidth=params.width;
            params.width=200;
        }
        sizeChanged=!sizeChanged;
        square.setLayoutParams(params);

更改view大小的代码基本类似,我们可以简单的看一下效果,会发现,这么写其实和写一个属性动画差不多,都是通过改变view自身来改变的,不过对于属性动画来说想要改变位置会主动改变自身的位置,而不是像过场动画一下,去改变父布局的属性,来实现,从这一点来说,过场动画更灵活,也适用更多的场景和复杂的动画,我们继续往下看。

场景变换

作为Transition的基本使用,个人感觉过渡动画并不是Transition的主要功能,简单有效的从一个场景切换到另一个场景,过渡平滑不突兀,这才是Transition应该有的操作。
这AnimationActivity2中有五个Scene,在页面加载的时候就通过TransitionManager.go(scene0);方法来初始化一个场景并添加到Activity中,初始化时通过

        scene0=Scene.getSceneForLayout(sceneRoot,R.layout.activity_animations_scene0,this);
        scene0.setEnterAction(new Runnable() {
            @Override
            public void run() {
                for(int i=0;i<viewsToAnimate.size();i++){
                    View child=viewsToAnimate.get(i);
                    child.animate()
                            .setStartDelay(i*DELAY)
                            .scaleX(1)
                            .scaleY(1);
                }
            }
        });
        scene0.setExitAction(new Runnable() {
            @Override
            public void run() {
                TransitionManager.beginDelayedTransition(activityRoot);
                View title=scene0.getSceneRoot().findViewById(R.id.scene0_title);
                title.setScaleX(0);
                title.setScaleY(0);
            }
        });

先通过getSceneForLayout方法来获得一个Scene对象,而且可以给这个场景设置进入和退出的动作,在初始化的时候需要指定要替换的布局。
之后继续初始化其他四个Scene

        scene1=Scene.getSceneForLayout(sceneRoot,R.layout.activity_animations_scene1,this);
        scene2=Scene.getSceneForLayout(sceneRoot,R.layout.activity_animations_scene2,this);
        scene3=Scene.getSceneForLayout(sceneRoot,R.layout.activity_animations_scene3,this);
        scene4=Scene.getSceneForLayout(sceneRoot, R.layout.activity_animations_scene4,this);

在场景初始化之后就可以通过java TransitionManager.go(scene1,new ChangeBounds());方法来更换场景并且可以指定切换场景间的动画。看过项目的人都清楚,如果单纯的让我们用属性动画去做的话,那个工作量可不是一般的大。在复杂布局的切换中使用这种改变场景的方式明显的更为方便和便捷。

RevealAnimation

RevealAnimation 中文不准确的翻译:揭露动画(有点不雅)。这个里面涉及的有些多,一步步分开来说。
首先是进入的动画,一个橘黄色的小球的共享元素动画。这动画的过程中,可能是本人个人水平有限,仔细观察后发现其实移动的路径是曲线而且退出和进入时的路径是不同的,而且在代码中并没有指定移动的路径,猜测是共享元素过程中默认设置的。有待研究。接下来就按照颜色去分析。

绿色

在点击绿色按钮之后会从布局的中间偏下的位置开始一个Reveal动画,查看调用的方法我们可以找个这个:

    /**
     *创建Reveal动画并执行
     *
     * @param viewRoot 要执行动画的布局
     * @param color 揭露的颜色
     * @param cx 揭露点的X坐标
     * @param cy 揭露点的Y坐标
     * @return 返回创建成功的动画
     */
        private Animator animateRevealColorFromCoordinates(ViewGroup viewRoot, int color, int cx, int cy) {
        float finalRadius= (float) Math.hypot(viewRoot.getWidth(),viewRoot.getHeight());

        Animator anim=ViewAnimationUtils.createCircularReveal(viewRoot,cx,cy,0,finalRadius);
        viewRoot.setBackgroundColor(ContextCompat.getColor(this,color));
        anim.setDuration(getResources().getInteger(R.integer.anim_duration_long));
        anim.setInterpolator(new AccelerateDecelerateInterpolator());
        anim.start();
        return anim;
    }

首先通过math.hypot一个没有见过的数学方法来求出要执行的最终的半径,hypot方法的意思是求两个数平方和的平方根,白话的意思就是求直角三角形斜边长。用在这里的意思就是求布局对角线的长度。之后通过ViewAnimationUtils.createCircularReveal()方法创建一个RevealAnimator,需要的参数有布局,坐标点,起始半径和最终半径。设置时间和差值器之后就可以运行了,使用并不难。

红色

点击红色按钮与点击绿色按钮的动画有两点不同,一是会有一个红球的位移,二是在红球右侧的蓝球和橘黄色球会往右有一个简单的位移和缩小,至于揭露动画的部分其实就是一个颜色的改变。


    final ViewGroup.LayoutParams originalParams = btnRed.getLayoutParams();
      Transition transition = TransitionInflater.from(this).inflateTransition(R.transition.changebounds_with_arcmotion);
      transition.addListener(new Transition.TransitionListener() {
          @Override
          public void onTransitionStart(Transition transition) {
          }
    
          @Override
          public void onTransitionEnd(Transition transition) {
              animateRevealColor(bgViewGroup, R.color.sample_red);
              body.setText(R.string.reveal_body3);
              body.setTextColor(ContextCompat.getColor(RevealActivity.this, R.color.theme_red_background));
              btnRed.setLayoutParams(originalParams);
          }
    
          @Override
          public void onTransitionCancel(Transition transition) {
          }
    
          @Override
          public void onTransitionPause(Transition transition) {
    
          }
    
          @Override
          public void onTransitionResume(Transition transition) {
    
          }
      });
      TransitionManager.beginDelayedTransition(bgViewGroup, transition);
      RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
      layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
  btnRed.setLayoutParams(layoutParams);

简单看来就是先获得当前的布局状态,之后开启一个之前用过的Transition,设置新的布局属性,这个主要是用来实现红球从底部移动到屏幕中部,之后开启一个揭露动画,之前介绍过就不多赘述了,比较奇怪的是在代码中并没有看到关于在红球移动过程中对其他几个球的动画代码,从这一点上来看,过场动画的强大,会默认的帮我们实现一些符合现实情景的动作。

剩下的蓝球和黄球其实就是改变揭露动画的起始位置,其他的并没有太大的变化,就说到这。

总结

关于动画的东西其实我写了很多,主要是个人比较喜欢这种东西,从最基础的帧动画,补间动画,再到属性动画,多种不同方式去实现属性动画,再到5.0的过渡动画和过场动画,分享元素,更多的还有SVG矢量图动画等等,随着Android系统的发展,有越来越多的形式能够使我们的APP变得更加贴近生活,更能吸引人。我们也要不断的学习心的东西,才不会被时代淘汰掉。

以后可能会换个地方写文章,争取每周一篇,可以的话也会弄一个个人的博客,文章也会同步更新到简书。

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

推荐阅读更多精彩内容