模仿蚂蚁森林水滴动效

很久没写东西了,又来一下,可能看了这个东效你会觉得很简单,但是如果你看完,我相信你还是会发现简单里面还是有文章,也许并不是看起来那样简单,本文精华在于 性能

老规矩还是先上GIF

也许看到这个图,你就不想再继续看下去了,心想这个动画很简单啊,不就是创建循环创建view,再给每个view的动画,每个view的开始运动的方向随机,再给一个加速器就搞定了嘛,如果你也是这样想那就该把这个文章看完了 分析:

  • 首先创建水滴动画、缩放伴随透明度变化
  • 消失时缩放伴随移动
  • 水滴展示中是一直上下浮动的
  • 每个水滴上下浮动的方向不定
  • 每个水滴运动的速度时而快时而慢(这点也许你看不出,所以我再把抖动的范围加大再来一个GIF)

  首先我们肯定不能用每个view对应一个动画来处理,因为如果我是100低水滴,那岂不是要100个动画,这不得卡死呀,所以肯定是一个动画来完成,开始我第一想到的也是用ValueAnimator来做,但是一个ValueAnimator怎么去控制每个view的运动方向呢,有可能你会说每个view在初始化的时候给一个反向,确实可以解决运动方向不同的问题,但是怎么解决view运动的快慢不一样,并且时而快时而慢呢,并且每个view的运动规律根本不一样,最后我选择了handler来处理,但是到这里你以为完了嘛,继续往下看吧

正题

  • 首先创建view
 1、给view一个随机的方向并且保存到view的tag里
            //随机设置view动画的方向
            view.setTag(R.string.isUp, mRandom.nextBoolean());
 2、随机设置view的位置(我这里并非完全随机,而是给了一些值,然后随机选择这些值)、这里用了一个新的集合保存已经选择到的数,下次选择的时候排除这些值,因为最好水滴不要完全重合嘛。
/**但是其实这不是我最终的方法,先往下看吧,还有彩蛋**/
 /**
     * 获取x轴或是y轴上的随机值
     *
     * @return
     */
    private double getX_YRandom(List<Float> choseRandoms,List<Float> saveRandoms) {
        float random = 0;
        while (random == 0 || saveRandoms.contains(random)) {
            random = choseRandoms.get(mRandom.nextInt(choseRandoms.size()));
        }
  
        saveRandoms.add(random);
        return random;
    }

复制代码

还有一个动画显示view,这个就不展示了,绝对都能搞定

  • 接下来为view设置一个初始的随机加速度(其实也是随机在已有的值中选取,因为速度不能相差太大)
/**控制水滴动画的快慢*/
    private List<Float> mSpds = Arrays.asList(2.0f, 1.7f, 1.5f, 1.3f);
 /**
     * 设置所有子view的加速度
     */
    private void setViewsSpd() {
        for (int i = 0; i < mViews.size(); i++) {
            View view = mViews.get(i);
            setSpd(view);
        }
    }
 /**
     * 设置所有子view的加速度
     */
    private void setViewsSpd() {
        for (int i = 0; i < mViews.size(); i++) {
            View view = mViews.get(i);
            setSpd(view);
        }
    }

复制代码
  • 接下来就是使用handler设置view的偏移量了,这部分也是很关键的,包括了处理水滴运动时而快时而慢
 /**
     * 设置偏移
     */
    private void setOffSet() {
        for (int i = 0; i < mViews.size(); i++) {
            View view = mViews.get(i);
            float spd = (float) view.getTag(R.string.spd);
            float original = (float) view.getTag(R.string.original_y);
            float step = CHANGE_RANGE / BASE_OFFSET_MUL * spd;
            //拿到初始设置的方向
            boolean isUp = (boolean) view.getTag(R.string.isUp);
            float translationY;
            if (isUp) {
                translationY = view.getY() - step;
            } else {
                translationY = view.getY() + step;
            }
            //控制view的移动范围不能大于我们规定的范围,如果到了这个值还要改变view的运动方向
            if (translationY - original > CHANGE_RANGE) {
                translationY = original + CHANGE_RANGE;
                view.setTag(R.string.isUp, true);
            } else if (translationY - original < -CHANGE_RANGE) {
                translationY = original - CHANGE_RANGE;
//每次view运动到最下边,再一次向上运动时改变view的加速度,这样不就做到了view时而快时而慢了么
                setSpd(view);
                view.setTag(R.string.isUp, false);
            }
            view.setY(translationY);
        }
    }

复制代码
  • 接下来水滴点击后的消失动画,也不说了,都行

到这里动效就完了,但是我的工作并没完,打开profiler一看OMG,在初始化view的地方内存剧增,数量稍稍多一点(10个)还会卡主,看来还的优化啊

很明显private double getX_YRandom(List<Float> choseRandoms, List<Float> saveRandoms)这个方法走了太多次,原因就在于我是循环创建view,并且在这个循环内为view随机创建位置,但是为了不完全重合,我这里又一次循环知道是一个不同的值为止,也就是说这里双重循环了

  • 优化随机取用一个值后,就把这个值从集合移除,这样不就不会取到一样的值了么,到这里就真的完了,优化后实测200个都没有一点卡顿,读者可以根据自己需求优化水滴的位置逻辑算法,因为我们产品明确说了最多6滴,所以我现在的水滴位置计算逻辑足够了,还是来个GIF吧
特别说明为了使得效果更易看清我将view的变化范围和加速度取值梯度都设置的比较大
  /**view变化的y抖动范围*/
    private static final int CHANGE_RANGE = 50;
//    private static final int CHANGE_RANGE = 10;//正常的

  /**控制水滴动画的快慢*/
    private List<Float> mSpds = Arrays.asList(2.0f, 1.7f, 1.5f, 1.3f,2.3f);
//    private List<Float> mSpds = Arrays.asList(2.0f, 1.7f, 1.5f, 1.3f);//正常的
复制代码

github连接:WaterView

喜欢就赞一个吧,你的赞是我的动力

Android Profiler使用讲解
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值