Android-_ 巧 _ 仿蚂蚁森林水滴动效,Android 开发技巧
*/
###正题
下面的讲解我将会贴出重要部分的代码,也就是思路关键点,完整代码还是请 clone 项目。
首先创建 view
创建 view 代码块:
/**
添加水滴 view*/private void addWaterView(List<Water> waters) {for (int i = 0; i < waters.size(); i++) {final Water water = waters.get(i);View view = mInflater.inflate(mChildViewRes, this, false);TextView tvWater = view.findViewById(R.id.tv_water);view.setTag(water);tvWater.setText(String.valueOf(water.getNumber()) + "g");view.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View view) {handViewClick(view);}});//随机设置 view 动画的方向 view.setTag(R.string.isUp, mRandom.nextBoolean());setChildViewLocation(view);mViews.add(view);addShowViewAnimation(view);}}
解释
创建 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:
/**
添加显示动画
@param view*/private void addShowViewAnimation(View view) {addView(view);view.setAlpha(0);view.setScaleX(0);view.setScaleY(0);view.animate().alpha(1).scaleX(1).scaleY(1).setDuration(ANIMATION_SHOW_VIEW_DURATION).start();}
接下来为 view 设置一个初始的随机加速度(其实也是随机在已有的值中选取,因为速度不能相差太大)
/控制水滴动画的快慢/private List<Float> mSpds = Arrays.asList(0.5f, 0.3f, 0.2f, 0.1f);/*
设置所有子 view 的加速度/private void setViewsSpd() {for (int i = 0; i < mViews.size(); i++) {View view = mViews.get(i);setSpd(view);}}/*
设置 View 的 spd
@param view*/private void setSpd(View view) {float spd = mSpds.get(mRandom.nextInt(mSpds.size()));//将这个随机的位移速度保存到 view 的 tag 里,这里两个参数 setTag()方法不大了解的可以百度一下 view.setTag(R.string.spd, spd);}
接下来就是开启动画,使用 handler 设置 view 的偏移量了,这部分也是很关键的,还包括了处理水滴时而快时而慢的处理
/**
设置偏移*/private void setOffSet() {for (int i = 0; i < mViews.size(); i++) {View view = mViews.get(i);//拿到上次 view 保存的速度 float spd = (float) view.getTag(R.string.spd);//水滴初始的位置 float original = (float) view.getTag(R.string.original_y);float step = spd;boolean isUp = (boolean) view.getTag(R.string.isUp);float translationY;//根据水滴 tag 中的上下移动标识移动 viewif (isUp) {translationY = view.getY() - step;} else {translationY = view.getY() + step;}//对水滴位移范围的控制 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;// 每次当水滴回到初始点时再一次设置水滴的速度,从而达到时而快时而慢 setSpd(view);view.setTag(R.string.isUp, false);}view.setY(translationY);}}
接下来水滴点击后的消失动画
/**
动画移除 view
@param view*/private void animRemoveView(final View view) {final float x = view.getX();final float y = view.getY();//计算直线距离 float space = getDistance(new Point((int) x, (int) y), mDestroyPoint);
ValueAnimator animator = ValueAnimator.ofFloat(x, 0);//根据距离计算动画执行时间 animator.setDuration((long) (REMOVE_DELAY_MILLIS / mMaxSpace * space));animator.setInterpolator(new LinearInterpolator());animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator valueAnimator) {if (isCancelAnimtion) {return;}float value = (float) valueAnimator.getAnimatedValue();float alpha = value / x;float translationY = y + (x - value) * (maxY - y) / x;setViewProperty(view, alpha, translationY, value);}});animator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {//结束时从容器移除水滴 removeView(view);}});animator.start();}
/**
设置 view 的属性
@param view
@param alpha
@param translationY
@param translationX*/private void setViewProperty(View view, float alpha, float translationY, float translationX) {view.setTranslationY(translationY);view.setTranslationX(translationX);view.setAlpha(alpha);view.setScaleY(alpha);view.setScaleX(alpha);}
处理界面销毁
/**
界面销毁时回调*/@Override
评论