一个酷炫的Android特效源码

[复制链接]
来自: shareiOS 分类: Android精品源码 上传时间: 2018-2-5 10:36:10
Tag:

项目介绍:

一、小说界面过渡动画

(1)点击Fab,开启过渡界面动画效果,监听事件如下:

  • root.findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() {
  •          @Override
  •          public void onClick(View v) {
  •              root.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
  •                  @Override
  •                  public void onGlobalLayout() {//在一个视图树中的焦点状态发生改变时,所要调用的回调函数的接口类
  •                      root.getViewTreeObserver().removeOnGlobalLayoutListener(this);
  •                      TransitionHelper.startExitAnim(root);//当前界面离开时的动画
  •                  }
  •              });
  •              WindFragment windFragment = new WindFragment();
  •              windFragment.setIntroAnimate(true);//设置WindFragment的动画标志
  •              ((RootActivity) getActivity()).goToFragment(windFragment);//添加进入的Fragment
  •              /**佘略部分代码**/
  •          }
  •      });

[color=rgb(85, 85, 85) !important]复制代码

这里退出动画的实现是这句TransitionHelper.startExitAnim(root),传入的参数是当前Fragment的视图root。TransitionHelper是个动画实现类,主要做了视图进入、离开、恢复这些动画。我们进去看看退出动画的实现。源码如下:
  • public static void startExitAnim(View root) {
  •     exitAnimate((DepthLayout) root.findViewById(R.id.root_dl), 0, 30f, 15, 190, true);
  •     exitAnimate((DepthLayout) root.findViewById(R.id.appbar), MOVE_Y_STEP, 20f, 30, 170, true);
  •     exitAnimate((DepthLayout) root.findViewById(R.id.fab_container), MOVE_Y_STEP * 2f, 20f, 45, 210, true);
  •     exitAnimate((DepthLayout) root.findViewById(R.id.dl2), MOVE_Y_STEP, 20f, 60, 230, true);
  •     exitAnimate((DepthLayout) root.findViewById(R.id.dl3), MOVE_Y_STEP * 2, 20f, 75, 250, true);
  • }

[color=rgb(85, 85, 85) !important]复制代码

以上代码,你可以看出startExitAnim对当前Fragment的视图Root的每个子控件都做了不一样的动画,具体是实现是在exitAnimate(...)方法中,代码比较多,我就不贴了。
主要是开启了6个ObjectAnimator动画做了view的旋转、缩放、平移、阴影等动画,其中有句代码很关键View.setCameraDistance(),设置Camera的距离,表现出透视效果。
一个Fragment做了离开的动画,我们看看它进入的Fragment动画是怎么实现的!上文中Fab监听的代码里有这句getActivity()).goToFragment(windFragment),应该就是另一个Framgen进入的逻辑实现了,跟进去看看!
  • public void goToFragment(final Fragment newFragment) {
  •        getFragmentManager().beginTransaction().add(R.id.fragment_container, newFragment).commit();//添加新的fragment
  •        final Fragment removeFragment = currentFragment;//记录要移除的Fragment
  •        currentFragment = newFragment;
  •        getWindow().getDecorView().postDelayed(new Runnable() {
  •            @Override
  •            public void run() {//延迟两秒后,删除记录删除的Fragment
  •                getFragmentManager().beginTransaction().remove(removeFragment).commit();
  •            }
  •        }, 2000);
  •    }

[color=rgb(85, 85, 85) !important]复制代码

握草,没看到进入的Framgent的动画,奇了怪了。我们进入 WindFragment 看具体实现!你会发现在onCreateView实现了。
  • @Override
  •   public View onCreateView(LayoutInflater inflater, ViewGroup container,
  •                            Bundle savedInstanceState) {
  •       root = inflater.inflate(R.layout.fragment_wind, container, false);
  •       ......
  •       doIntroAnimation();//进入动画
  •       .....
  •       return root;
  •   }

[color=rgb(85, 85, 85) !important]复制代码

而doIntroAnimation方法中调用了TransitionHelper.startIntroAnim(...),你会看到
  • public static void startIntroAnim(View root, AnimatorListenerAdapter introEndListener) {
  •         introAnimate((DepthLayout) root.findViewById(R.id.root_dl), 0, 30f, 15, 180);
  •         introAnimate((DepthLayout) root.findViewById(R.id.appbar), MOVE_Y_STEP, 20f, 30, 170);
  •         introAnimate((DepthLayout) root.findViewById(R.id.fab_container), MOVE_Y_STEP * 2f, 20f, 45, 190);
  •         introAnimate((DepthLayout) root.findViewById(R.id.dl2), MOVE_Y_STEP, 20f, 60, 200);
  •         introAnimate((DepthLayout) root.findViewById(R.id.dl3), MOVE_Y_STEP * 2, 20f, 75, 210).addListener(introEndListener);
  •     }

[color=rgb(85, 85, 85) !important]复制代码

这个逻辑有和界面离开时的参不多,开启了多个ObjectAnimator动画做了view的旋转、缩放、平移、阴影等动画。
细心的你会发现,我给的效果和设计图的不同啊,没错,如果只是做过渡动画,还达不到很酷炫的效果,这里还有阴影的效果。
二、小说绘制布局阴影

阴影效果很明显。我们看看Fragment的xml布局是这样的
  •     xmlns:android="http://schemas.android.com/apk/res/android"
  •     xmlns:app="http://schemas.android.com/apk/res-auto"
  •     xmlns:tools="http://schemas.android.com/tools"
  •     android:layout_width="match_parent"
  •     android:layout_height="match_parent"
  •     tools:context=".sample.WaterFragment"
  •     >
  •             android:id="@+id/appbar"
  •         android:layout_width="match_parent"
  •         android:layout_height="@dimen/appbar_height"
  •         android:background="@color/green"
  •         android:layerType="hardware"
  •         app:edge_color="@color/statusbar2"
  •         >
  •                     />
  •    
  •     ......
  •             android:id="@+id/fab_container"
  •             ......
  •         >
  •                     ......
  •             />
  •    


[color=rgb(85, 85, 85) !important]复制代码

你会发现都是一个外层DepthRendrer控件里有几个DepthLayout控件,而DepthRendrer和DepthLayout都继承RelativeLayout。DepthRendrer在初始化的时候设置了视图树中的焦点状态改变时,回调函数监听,计算绘制DepthLayout阴影的范围。
  • void setup() {
  •         getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
  •             @Override
  •             public boolean onPreDraw() {
  •                 for (int i = 0; i < getChildCount(); i++) {//遍历子控件
  •                     View child = getChildAt(i);
  •                     if (child instanceof DepthLayout) {
  •                         //如果是DepthLayout控件 ,就调用DepthLayout的calculateBounds方法计算要绘制阴影的范围
  •                         boolean hasChangedBounds = ((DepthLayout) child).calculateBounds();
  •                         if (hasChangedBounds)
  •                             invalidate();
  •                     }
  •                 }
  •                 return true;
  •             }
  •         });

[color=rgb(85, 85, 85) !important]复制代码

invalidate会调用DepthRendrer中的
drawChild(Canvas canvas, View child, long drawingTime),绘制子 控件阴影。
  • @Override
  •   protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
  •       if (child instanceof DepthLayout && !isInEditMode()) {
  •           DepthLayout dl = (DepthLayout) child;
  •           float[] src = new float[]{0, 0, dl.getWidth(), 0, dl.getWidth(), dl.getHeight(), 0, dl.getHeight()};
  •           if (dl.isCircle()) {//控件是否适圆形的
  •               dl.getCustomShadow().drawShadow(canvas, dl, roundSoftShadow);
  •               if (Math.abs(dl.getRotationX()) > 1 || Math.abs(dl.getRotationY()) > 1)
  •                   drawCornerBaseShape(dl, canvas, src);
  •           } else {
  •               dl.getCustomShadow().drawShadow(canvas, dl, softShadow);
  •               if (dl.getRotationX() != 0 || dl.getRotationY() != 0) {
  •                   if (getLongestHorizontalEdge(dl) > getLongestVerticalEdge(dl))
  •                       drawVerticalFirst(dl, canvas, src);
  •                   else
  •                       drawHorizontalFist(dl, canvas, src);
  •               }
  •           }
  •       }
  •       return super.drawChild(canvas, child, drawingTime);
  •   }

[color=rgb(85, 85, 85) !important]复制代码

这句代码主要是针对不同的控件绘制不同的阴影,比如矩形和圆形绘制阴影的方法是不一样的。
做到以上两步,基本上我们就可以得到上图的效果了。



相关源码推荐:

我来说两句
所有评论(228)
春城计算机 2018-2-5 10:46:49
每次我都积极回帖的,想要安币~
回复
葫芦_eRDJw 2018-2-5 10:51:59
安卓巴士是个不错的网站,我来顶个贴~
回复
码农创新者 2018-2-5 10:53:19
每次我都积极回帖的,想要安币~
回复
tylz 2018-2-5 11:03:33
感谢分享,安卓巴士有你更精彩:lol
回复
一人无 2018-2-5 11:07:13
不错不错,楼主辛苦了。。。
回复
gongags 2018-2-5 11:08:03
安卓巴士是个不错的网站,我来顶个贴~
回复
程梦义 2018-2-5 11:28:30
虽不明,但觉厉!
回复
提取码:  下载次数:81 状态:已购或VIP 售价:15(原价:15)金钱 下载权限:初级码农 
7979 2 81
代码贡献英雄榜
用户名 下载数
联系我们
首页/微信公众账号投稿
帖子代码编辑/版权问题
QQ:435399051,1294855032
如何获得代码达人称号?
如何成为签约作者?
领先的中文移动开发者社区
18620764416
7*24全天服务
意见反馈:1294855032@qq.com

扫一扫关注我们

Powered by Discuz! X3.2© 2001-2019 Comsenz Inc.( 粤ICP备15117877号 )