Android 漂浮类动效的分析与实现!

尊重原创,欢迎转载,转载请注明: FROM 
GA_studio   http://blog.csdn.net/tianjian4592

注:因部分原因,本篇主要讲解动效分析的思路,不提供源码下载,请见谅 ... ...

上一篇只讲了Canvas中的drawBitmap方法,并且还说的这个方法好像很腻害、能做出很多牛逼效果的样子,接下来这篇文章只是为了作为上一篇文章的一个小栗子,进一步拓展大家利用drawBitmap 完成动效的思路!

好了,先上失真的不能再失真的效果图:

咱们先一起来分析下上面的效果:

假定这是你刚从UE 或动效射鸡湿手里拿到上面的动效设计图,映入眼帘的是苍茫的星空,漂浮的星球营造出的深邃、浩瀚的宇宙,好了,不多BB了,针对上图你会想到什么样的实现方案?

1. 有些同学可能会想到创建对应数量个ImageView,然后针对每一个ImageView使用 Animation或Animator 去做对应的移动效果;

2.采用自己绘制的方式进行实现,不就是漂浮的星球吗,咱都给画出来;

不用说,上面第二种方案肯定更可取,第一种方案有以下几个缺陷:

1. 创建的view 个数过多,性能太差;

2. 灵活性太差,比如UE或产品要增加或减少星球数量,都会是个麻烦事儿;

3. 对每一个view做移动动画,开销太大还不太可控或修改;

针对于此,咱们坚定不移的走自己绘制完成漂浮动效的路线;

既然要绘制,那首先得拿到星球的位图,根据星球的种类拿到所有的位图:

    /**
     * init bitmap info
     */
    private void initBitmapInfo() {

        mBackBitmap = ((BitmapDrawable) mResources.getDrawable(R.drawable.back))
                .getBitmap();
        mBackWidth = mBackBitmap.getWidth();
        mBackHeight = mBackBitmap.getHeight();

        mStarOne = ((BitmapDrawable) mResources.getDrawable(R.drawable.star2))
                .getBitmap();
        mStarOneWidth = mStarOne.getWidth();
        mStarOneHeight = mStarOne.getHeight();

        mStarTwo = ((BitmapDrawable) mResources.getDrawable(R.drawable.star1))
                .getBitmap();
        mStarTwoWidth = mStarTwo.getWidth();
        mStarTwoHeight = mStarTwo.getHeight();

        mStarThree = ((BitmapDrawable) mResources.getDrawable(R.drawable.star3))
                .getBitmap();

        mStarThreeWidth = mStarThree.getWidth();
        mStarThreeHeight = mStarThree.getHeight();

    }

上面拿到了背景和三种类型星球的位图,根据上面的效果,我们来分析下,有哪些特征性数据:

1. 同一种星球有大有小;

2. 彼此之间有透明度的差别;

3. 漂浮的方向不一样;

4. 漂浮的速度不一样;

5. 每个星球都得有自己的位置;

我们暂且只分析这么多,基于此,我们抽象出星球对象:

    /**
     * 星球
     * @author AJian
     */
    private class StarInfo {

        // 缩放比例
        float sizePercent;
        // x位置
        int xLocation;
        // y位置
        int yLocation;
        // 透明度
        float alpha;
        // 漂浮方向
        int direction;
        // 漂浮速度
        int speed;
    }

为了得到上面的部分数据,我们先写一些数据或方法:

1. 为了初始化星球的位置,我们用数组先定义一批星球的位置(基于view宽高的比例),当然大家也可以随机,只是随机可能出现扎堆情况:

private static final float[][] STAR_LOCATION = new float[][] {
            {0.5f, 0.2f}, {0.68f, 0.35f}, {0.5f, 0.05f},
            {0.15f, 0.15f}, {0.5f, 0.5f}, {0.15f, 0.8f},
            {0.2f, 0.3f}, {0.77f, 0.4f}, {0.75f, 0.5f},
            {0.8f, 0.55f}, {0.9f, 0.6f}, {0.1f, 0.7f},
            {0.1f, 0.1f}, {0.7f, 0.8f}, {0.5f, 0.6f}
    };

2. 获取星球大小的方法(基于原始Bitmap缩放比例):

    /**
     * 获取星球大小
     */
    private float getStarSize(float start, float end) {
        float nextFloat = (float) Math.random();
        if (start < nextFloat && nextFloat < end) {
            return nextFloat;
        } else {
            // 如果不处于想要的数据段,则再随机一次,因为不断递归有风险
            return (float) Math.random();
        }

    }

3. 定义三种不同快慢的漂浮速度:

        mFloatTransLowSpeed = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 0.5f,
                mResources.getDisplayMetrics());
        mFloatTransMidSpeed = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 0.75f,
                mResources.getDisplayMetrics());
        mFloatTransFastSpeed = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1f,
                mResources.getDisplayMetrics());

4. 获取星球漂浮方向的方法:

    /**
     * 初始化星球运行方向
     */
    private int getStarDirection() {
        Random random = new Random();
        int randomInt = random.nextInt(4);
        int direction = 0;
        switch (randomInt) {
            case 0:
                direction = LEFT;
                break;
            case 1:
                direction = RIGHT;
                break;
            case 2:
                direction = TOP;
                break;
            case 3:
                direction = BOTTOM;
                break;

            default:
                break;
        }
        return direction;
    }

有了上面的数据和方法,我们首先初始化一定数量的星球数据:

    /**
     * 初始化星球信息
     */
    private void initStarInfo() {

        StarInfo starInfo = null;
        Random random = new Random();
        for (int i = 0; i < mStarCount; i++) {
            // 获取星球大小比例
            float starSize = getStarSize(0.4f, 0.9f);
            // 初始化星球大小
            float[] starLocation = STAR_LOCATION[i];
            starInfo = new StarInfo();
            starInfo.sizePercent = starSize;

            // 初始化漂浮速度
            int randomSpeed = random.nextInt(3);
            switch (randomSpeed) {
                case 0:
                    starInfo.speed = mFloatTransLowSpeed;
                    break;
                case 1:
                    starInfo.speed = mFloatTransMidSpeed;
                    break;
                case 2:
                    starInfo.speed = mFloatTransFastSpeed;
                    break;

                default:
                    starInfo.speed = mFloatTransMidSpeed;
                    break;
            }

            // 初始化星球透明度
            starInfo.alpha = getStarSize(0.3f, 0.8f);
            // 初始化星球位置
            starInfo.xLocation = (int) (starLocation[0] * mTotalWidth);
            starInfo.yLocation = (int) (starLocation[1] * mTotalHeight);
            log("xLocation = " + starInfo.xLocation + "--yLocation = "
                    + starInfo.yLocation);
            log("stoneSize = " + starSize + "---stoneAlpha = "
                    + starInfo.alpha);
            // 初始化星球位置
            starInfo.direction = getStarDirection();
            mStarInfos.add(starInfo);
        }

    }

有了这些数据,我们已经可以将星球绘制在屏幕上:

 private void drawStarDynamic(int count, StarInfo starInfo,
            Canvas canvas, Paint paint) {

        float starAlpha = starInfo.alpha;
        int xLocation = starInfo.xLocation;
        int yLocation = starInfo.yLocation;
        float sizePercent = starInfo.sizePercent;

        xLocation = (int) (xLocation / sizePercent);
        yLocation = (int) (yLocation / sizePercent);

        Bitmap bitmap = null;
        Rect srcRect = null;
        Rect destRect = new Rect();

        if (count % 3 == 0) {

            bitmap = mStarOne;
            srcRect = mStarOneSrcRect;
            destRect.set(xLocation, yLocation,
                    xLocation + mStarOneWidth, yLocation
                            + mStarOneHeight);
        } else if (count % 2 == 0) {
            bitmap = mStarThree;
            srcRect = mStarThreeSrcRect;
            destRect.set(xLocation, yLocation, xLocation
                    + mStarThreeWidth, yLocation + mStarThreeHeight);
        } else {
            bitmap = mStarTwo;
            srcRect = mStarTwoSrcRect;
            destRect.set(xLocation, yLocation, xLocation
                    + mStarTwoWidth, yLocation + mStarTwoHeight);
        }

        paint.setAlpha((int) (starAlpha * 255));
        canvas.save();
        canvas.scale(sizePercent, sizePercent);
        canvas.drawBitmap(bitmap, srcRect, destRect, paint);
        canvas.restore();

    }

接下来要考虑的只是如何让星球动起来,有了以上数据和思路,相信大家让星球动起来就不是难事了,只需要根据星球运动的方向,每次重绘的时候将星球的x、y增加或减小对应大小即可:

private void resetStarFloat(StarInfo starInfo) {
        switch (starInfo.direction) {
            case LEFT:
                starInfo.xLocation -= starInfo.speed;
                break;
            case RIGHT:
                starInfo.xLocation += starInfo.speed;
                break;
            case TOP:
                starInfo.yLocation -= starInfo.speed;
                break;
            case BOTTOM:
                starInfo.yLocation += starInfo.speed;
                break;
            default:
                break;
        }
    }

这时候有部分同学可能会说了,尼玛, 星球直接移出屏幕了怎么办,这个问题相信大家都能解决,只是一个值的判断和重新修复,不再多言;

最后针对这一类动效小谈一下,其实很大一部分效果和上面的动效是类似的,不信?我举几个栗子:

1. 雪花飘落的效果

尼玛,扯淡呢!雪花和这类似?雪花从上往下飞,并且还旋转;

针对于此,我们只需要在抽取对象的时候加上旋转角度和旋转速度(对于旋转有问题的话,可以参考一个绚丽的loading动效分析与实现!),至于从上往下飞的问题,我们只需要修改x、y的更新策略即可;

2. 很多桌面类应用的花瓣飘落、落英缤纷效果;

基本都是采用以上的分析和实现原理,重要的是对于数据的抽取和灵活运用,其他的也就是根据具体的需求动态的更新需要更新的数据,比如位置、大小、透明度等等;

所以,从上面来看,这一类效果其实并不复杂,我们所需要做的只是将复杂动效进行分解、抽取,然后找到每一个小点最适合的实现方式,大的动效化小,然后逐个击破;

我在写的过程中会尽可能的把思路描述清楚,因为在我看来,做动效,最主要的还是在于效果的拆解、衔接、解决的思路,思路清晰了,解决方案一般也就明了了;

时间: 2024-10-12 21:49:17

Android 漂浮类动效的分析与实现!的相关文章

iOS开发Facebook POP动效库使用教程

如果说Origami这款动效原型工具是Facebook Paper的幕后功臣,那么POP便是Origami的地基.感谢Facebook开源了POP动效库,让人人都能制作出华丽的动效.我们只需5步,便能搞定酷炫的动效. 步骤1: 安装 使用CocoaPods安装POP,只需要在Podfile中加入这么一行: pod 'pop', '~> 1.0' 或者如果想要手动添加,那么参考POP Github中的描述: 除此之外,你还可以将工程添加到工作区里面,然后采用提供的配制文件.或者手动复制POP子目录

Facebook POP动效库使用教程

编者注:用Origami作iOS动效的同学如果愁怎么实现,可以把这个给开发看看作为参考哦 如果说Origami这款动效原型工具是Facebook Paper的幕后功臣,那么POP便是Origami的地基.感谢Facebook开源了POP动效库,让人人都能制作出华丽的动效.我们只需5步,便能搞定酷炫的动效. 步骤1: 安装 使用CocoaPods安装POP,只需要在Podfile中加入这么一行: pod 'pop', '~> 1.0' 或者如果想要手动添加,那么参考POP Github中的描述:

动效-APP设计的肢体语言

引言:如果把APP比作一位美女,那么icon是她的证件照,界面是她的形体,而动效则是她的肢体语言. 在如今玲琅满目的App中,如何脱颖而出?设计师要考虑的,不光是产品如何更合理的展现结构与功能,更重要的是思考自己的App是否能做到简便易懂的同时,又给用户新颖感?此时,有限的屏幕空间紧靠文字的提示是不够的,App需要更多的新鲜血液--"动效设计".动效设计可以拓展空间内容,简化引导流程,降低学习成本,更重要的是给用户带来意想不到--类似于"Cool"的惊喜,它就像人类

UI动效设计从入门到项目实战 高清无密 百度云盘

高薪设计师必修课 AE移动UI动效设计从入门到实战 如今诸多企业已经意识到动效在产品用户体验中的重要性,单纯的满足功能性的设计已经out了,动效设计已然成为未来UI设计师必备的能力!本课程采用基础理论与实战案例相结合的教学方式,手把手带你学习炫酷的动效设计! 第1章 课程简介 介绍该课程的学习内容,以及课程内的案例效果展示 1-1 课程介绍 第2章 动效基础知识学习 动效基础操作知识点梳理,快速掌握AE面板等基础操作知识要点,了解动效实现基本原理. 2-1 AE软件界面初识 2-2 菜单栏讲解

Android 一个绚丽的loading动效分析与实现!

http://blog.csdn.net/tianjian4592/article/details/44538605 前两天我们这边的头儿给我说,有个 gif 动效很不错,可以考虑用来做项目里的loading,问我能不能实现,看了下效果确实不错,也还比较有新意,复杂度也不是非常高,所以就花时间给做了,我们先一起看下原gif图效果: 从效果上看,我们需要考虑以下几个问题: 1.叶子的随机产生: 2.叶子随着一条正余弦曲线移动: 3.叶子在移动的时候旋转,旋转方向随机,正时针或逆时针: 4.叶子遇到

Android头像下拉缩放动效

头像下拉缩放动效 头像下拉缩放这个在IOS中很常见,最近在Github上也看到了类似的效果,所以决定把它集成到我现在做的项目中去. Github上的开源地址:https://github.com/Frank-Zhu/PullZoomView 先上2张效果图 PullToZoomView的使用 这个开源框架的使用主要用到的是PullToZoomListViewEx和PullToZoomScrollViewEx的2个类库,PullToZoomListViewEx这个是ListView的下拉效果,暂时

android动效开篇

大神博客:http://blog.csdn.net/tianjian4592/article/details/44155147 在现在的Android App开发中,动效越来越受到产品和设计师同学的重视,如此一来,也就增大了对开发同学的考验,虽说简单的动效:如移动,旋转,缩放,渐变或普通的界面跳转相对简单,但在目前日益激烈的竞争条件下,出彩复杂的动效也越来越多,并且很多效果已经无法直接用android提供的Animation或Animator框架进行实现,需要通过自定义View或ViewGrou

一个绚丽的Downloading动效分析与实现

闲逛之余,看到一个不错的downloading动效,这个动效用CJJ的话说难度还好,但本人觉得还比较灵动.带感.俏皮.有新意,好了话不多说,咱们先来撸一张高清无码gif图: 撸完,咱可以将整个动效简单划分为以下流程: 1. BeforeProgress(显示进度前); 2. InProgress(显示进度中); 3.Failed(失败动画); 4.Done(完成动画); 下面咱们一起对以上流程进行分析与实现: 1. BeforeProgress(显示进度前): 同样,咱们一起撸一下第一部分高清无

Android使用SVG矢量图打造酷炫动效!

尊重原创,欢迎转载,转载请注明: FROM  GA_studio   http://blog.csdn.net/tianjian4592 一个真正酷炫的动效往往让人虎躯一震,话不多说,咱们先瞅瞅效果: 这个效果我们需要考虑以下几个问题: 1. 这是图片还是文字: 2. 如果是图片该如何拿到图形的边沿线坐标,如果是文字呢? 3. 如果拿到了边沿线坐标,如何让光线沿着路径跑动: 4. 怎么处理过程的衔接: 以上四个问题似乎不是太好处理,而这几个问题也正好是这个效果精华所在,接下来咱们一个一个进行考虑