最近公司产品突然有一个类似支付宝蚂蚁森林的功能,大致功能跟支付宝蚂蚁森林相像,在看了一下支付宝蚂蚁森林的效果之后,打算先撸一个控件出来,等公司效果图出来之后就可以放上去直接使用。
首先我们先大致看下支付宝的蚂蚁森林效果图:

这是目前我实现的效果图:

当我们拿到这个需求时先分析一波,不要忙着就动手开干,不然容易平地翻车。。
需要实现的功能有:

1、自定小圆球,圆球内文字、上下浮动、消失动画;

2、根据数据动态添加小球,并且位置随机分布在小树周围,不能重叠。这点是最重要的,涉及到一个随机位置生成算法的设计。

好了,当我们确定了我们要实现的功能之后就可以逐步开始撸代码了。

自定义圆球

这个比较容易实现,绘制一个圆,再在园内绘制文字,动画实现统一采用的是属性动画来实现,代码如下,注释写的比较详细就不一一解释了,懒...

/*** @describe: 自定义仿支付宝蚂蚁森林水滴View*/public class WaterView extends View {private Paint paint;private ObjectAnimator mAnimator;/*** 文字颜色*/private int textColor = Color.parseColor("#69c78e");/*** 水滴填充颜色*/private int waterColor = Color.parseColor("#c3f593");/*** 球描边颜色*/private int storkeColor = Color.parseColor("#69c78e");/*** 描边线条宽度*/private float strokeWidth = 0.5f;/*** 文字字体大小*/private float textSize = 36;/*** 根据远近距离的不同计算得到的应该占的半径比例*/private float proportion;/*** 水滴球半径*/private int mRadius = 30;/*** 圆球文字内容*/private String textContent="3g";public WaterView(Context context) {super(context);init();}public WaterView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);init();}public WaterView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {paint = new Paint();paint.setAntiAlias(true);}@Overridepublic void draw(Canvas canvas) {super.draw(canvas);drawCircleView(canvas);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);setMeasuredDimension(Utils.dp2px(getContext(), (int) (2 * (mRadius+strokeWidth))),Utils.dp2px(getContext(), (int) (2 * (mRadius+strokeWidth))));}@Overrideprotected void onAttachedToWindow() {super.onAttachedToWindow();start();}@Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();stop();}@Overrideprotected void onVisibilityChanged(@NonNull View changedView, int visibility) {super.onVisibilityChanged(changedView, visibility);if (visibility == VISIBLE) {start();} else {stop();}}private void drawCircleView(Canvas canvas){//圆球paint.setColor(waterColor);paint.setStyle(Paint.Style.FILL);canvas.drawCircle(Utils.dp2px(getContext(), mRadius), Utils.dp2px(getContext(), mRadius), Utils.dp2px(getContext(), mRadius), paint);//描边paint.setColor(storkeColor);paint.setStyle(Paint.Style.STROKE);paint.setStrokeWidth(Utils.dp2px(getContext(), (int) strokeWidth));canvas.drawCircle(Utils.dp2px(getContext(), mRadius), Utils.dp2px(getContext(), mRadius), Utils.dp2px(getContext(), (int) (mRadius+strokeWidth)) , paint);//圆球文字paint.setTextSize(textSize);paint.setColor(textColor);paint.setStyle(Paint.Style.FILL);drawVerticalText(canvas, Utils.dp2px(getContext(), mRadius), Utils.dp2px(getContext(), mRadius), textContent);}private void drawVerticalText(Canvas canvas, float centerX, float centerY, String text) {Paint.FontMetrics fontMetrics = paint.getFontMetrics();float baseLine = -(fontMetrics.ascent + fontMetrics.descent) / 2;float textWidth = paint.measureText(text);float startX = centerX - textWidth / 2;float endY = centerY + baseLine;canvas.drawText(text, startX, endY, paint);}public void start() {if (mAnimator == null) {mAnimator = ObjectAnimator.ofFloat(this, "translationY", -6.0f, 6.0f, -6.0f);mAnimator.setDuration(3500);mAnimator.setInterpolator(new LinearInterpolator());mAnimator.setRepeatMode(ValueAnimator.RESTART);mAnimator.setRepeatCount(ValueAnimator.INFINITE);mAnimator.start();} else if (!mAnimator.isStarted()) {mAnimator.start();}}public void stop() {if (mAnimator != null) {mAnimator.cancel();mAnimator = null;}}public float getProportion() {return proportion;}public void setProportion(float proportion) {this.proportion = proportion;}
}

动态随机添加小球

这里我采用的是集成FrameLayout 通过设置小球数据,动态将小球add进去,比较简便,在这里最重要是动态随机添加小球的算法,解决了这个算法就好办了。通过仔细观察支付宝蚂蚁森林的效果实现,我们可以发现一般小球都是在树的正上方随机分布的。所以我想以小树的根为中心,小树的高度为半径为一个扇形,在这个扇形上方随机摆放小球。

公式:坐标 = 旋转角度 * 半径 * 根据远近距离的不同计算得到的应该占的半径比例

圆上任一点(x1,y1)坐标的计算公式:

x1 = x0 + r * cos(ao * 3.14 /180 )

y1 = y0 + r * sin(ao * 3.14 /180 )

具体实现代码如下:

/*** @describe: 支付宝蚂蚁森林水滴能量*/public class WaterFlake extends FrameLayout {private OnWaterItemListener mOnWaterItemListener;/*** 小树坐标X*/private float treeCenterX = 0;/*** 小树坐标Y*/private float treeCenterY = 0;/*** 小树高度*/private int radius = 80;/*** 开始角度*/private double mStartAngle = 0;/*** 是否正在收集能量*/private boolean isCollect = false;public WaterFlake(@NonNull Context context) {super(context);}public WaterFlake(@NonNull Context context, @Nullable AttributeSet attrs) {super(context, attrs);}public WaterFlake(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overridepublic boolean onTouchEvent(MotionEvent event) {if (event.getAction() == MotionEvent.ACTION_DOWN) {int x = (int) event.getX();int y = (int) event.getY();Rect rect = new Rect();for (int i = 0; i < getChildCount(); i++) {getChildAt(i).getHitRect(rect);if (rect.contains(x, y)) {if (mOnWaterItemListener != null) {getChildAt(i).performClick();mOnWaterItemListener.onItemClick(i);startAnimator(getChildAt(i));return true;}}}}return super.onTouchEvent(event);}@Overridepublic boolean performClick() {return super.performClick();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);measureChildren(widthMeasureSpec, heightMeasureSpec);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {int childCount = getChildCount();if (childCount==0){return;}int left, top;// 根据tem的个数,计算角度float angleDelay = -180 / childCount;for (int i = 0; i < childCount; i++) {WaterView child = (WaterView) getChildAt(i);mStartAngle %= 180;//设置CircleView小圆点的坐标信息//坐标 = 旋转角度 * 半径 * 根据远近距离的不同计算得到的应该占的半径比例
//            则圆上任一点为:(x1,y1)
//            x1   =   x0   +   r   *   cos(ao   *   3.14   /180   )
//            y1   =   y0   +   r   *   sin(ao   *   3.14   /180   )if (child.getVisibility() != GONE) {left = (int) (getTreeCenterX() + radius * Math.cos(mStartAngle * 3.14 / 180) * (child.getProportion() / radius * 2));top = (int) (getTreeCenterY() + radius * Math.sin(mStartAngle * 3.14 / 180) * (child.getProportion() / radius * 2));child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredWidth());}mStartAngle += angleDelay;}}/*** 设置小球数据,根据数据集合创建小球数量** @param modelList 数据集合*/public void setModelList(List<WaterModel> modelList, float treeCenterX, float treeCenterY) {this.treeCenterX = treeCenterX;this.treeCenterY = treeCenterY;for (int i = 0; i < modelList.size(); i++) {WaterView waterView = new WaterView(getContext(),(i+1)+"g");waterView.setProportion(Utils.getRandom(radius, radius + 80));addView(waterView);}}/*** 设置小球点击事件** @param onWaterItemListener*/public void setOnWaterItemListener(OnWaterItemListener onWaterItemListener) {mOnWaterItemListener = onWaterItemListener;}public interface OnWaterItemListener {void onItemClick(int pos);}private void startAnimator(final View view) {if (isCollect) {return;}isCollect = true;ObjectAnimator translatAnimatorY = ObjectAnimator.ofFloat(view, "translationY", getTreeCenterY());translatAnimatorY.start();ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f);alphaAnimator.start();AnimatorSet animatorSet = new AnimatorSet();animatorSet.play(translatAnimatorY).with(alphaAnimator);animatorSet.setDuration(3000);animatorSet.start();animatorSet.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {removeViewInLayout(view);isCollect = false;}});}public float getTreeCenterX() {return treeCenterX;}public float getTreeCenterY() {return treeCenterY;}
}

小球摆放随机算法有多种实现方式,这只是其中一种,写的不好的地方,还望各位指正,欢迎大家一起交流学习。

目前代码还有一些地方需要完善的,逐步更新。。。

TODO

优化小球随机生成算法,保证每个小球尽量不会重叠

【黄啊码】安卓实现支付宝中的蚂蚁森林效果相关推荐

  1. 仿支付宝蚂蚁森林效果

    CustomWaterView 项目地址:xiaohaibin/CustomWaterView  简介::star: 仿支付宝蚂蚁森林效果 更多:作者   提 Bug 标签: 实现原理文章:https ...

  2. html5仿蚂蚁森林效果代码,vue仿支付宝蚂蚁森林水滴

    APP 需要做一个类似蚂蚁森林的功能模块,动效和蚂蚁森林接近,可以有多个水滴,可以控制位置,水滴上下浮动. gif图如下所示: soogif.gif v-for="(item, index) ...

  3. 老司机带你顺手撸一个支付宝蚂蚁森林效果

    老司机,不存在的,其实我还算不上,哈哈... 最近公司产品突然有一个类似支付宝蚂蚁森林的功能,大致功能跟支付宝蚂蚁森林相像,在看了一下支付宝蚂蚁森林的效果之后,本来这种东西用RN实现是最好不过的,不过 ...

  4. 类似蚂蚁森林html5游戏源码,js仿照 蚂蚁森林 效果

    如图js仿照 蚂蚁森林 效果 css ** 葫芦籽动画效果 */ /* animation */ .a-swing{-webkit-animation:1s ease;-moz-animation:1 ...

  5. 30 行代码实现蚂蚁森林自动收能量(附送源码)

    点击上方 IT牧场 ,选择 置顶或者星标技术干货每日送达! blog.csdn.net/article/details/113734855 推荐:https://www.xttblog.com/?p= ...

  6. 30 行Python代码实现蚂蚁森林自动收能量(附送源码)

    公众号 "菜鸟学Python", 设为 "星标" 带你一起学Python 编辑:业余草 blog.csdn.net/article/details/113734 ...

  7. 【产品】支付宝蚂蚁森林产品体验报告

    0 前言 1 产品档案 2 产品底层逻辑 2.1 乐于助人的免费公益 2.2 人性:竞争,占有 2.3 个人价值体现 3 产品亮点 3.1 增加用户使用支付宝的频次 3.2 种树社交 3.3 企业形象 ...

  8. python模拟支付宝蚂蚁森林的能量产生过程_支付宝蚂蚁森林中,哪些行为可以产生更多的能量?...

    支付宝作为一款第三方支付应用,几乎涵盖了半数的第三方支付市场.而随着支付宝功能的不断完善与更新,支付宝所产生的生态圈更是让用户紧紧地连接在了一起.比如在使用支付宝时,我们不仅可以将其当做线下移动支付的 ...

  9. Android 仿支付宝蚂蚁森林动画效果

    Android 动画可以归纳为以下几种: 视图动画(View 动画) 帧动画(Frame 动画.Drawable 动画) 属性动画 触摸反馈动画(Ripple Effect) 揭露动画(Reveal ...

最新文章

  1. Django介绍和虚拟环境(django特点、MVC、MVT、Django学习资料)
  2. python异步生成器
  3. 【机器学习PAI实践二】人口普查统计
  4. windows server如何加强云服务器的安全性
  5. java 单例方法_Java-单例模式 - 惊觉
  6. Filezilla日文字符文件看不到或显示乱码的解决办法
  7. css2d变形模块,CSS变形transform(2d)
  8. 装卸码头设备市场深度分析及发展研究预测报告
  9. BRAF蛋白F595S G615R突变的影响
  10. 基于ssm的房屋出租网
  11. android 系统中的时区设置
  12. 免费高清视频素材下载网站
  13. 【腾讯Bugly干货分享】微信终端跨平台组件 mars 系列(二) - 信令传输超时设计
  14. 给小白的论文写作方法!实用率99%!
  15. python3爬取淘女郎图片
  16. 中国最强AI超级服务器问世,每秒提供AI计算2000万亿次
  17. ZOJ 3598 Spherical Triangle(计算几何 球面三角形内角和)
  18. hadoop shuffle 学习
  19. uni-app获取节点信息
  20. web项目常见报错解决方法

热门文章

  1. wps软件测试线上面试题分享
  2. java课程设计-音乐播放器_Java程序设计课程设计报告音乐播放器
  3. PPT中如何做炫酷帘幕动画?操作很简单,一起看看吧
  4. (cocos2d-js游戏)测试你的反应速度----------基本逻辑(上)
  5. spring 源码 窥视二
  6. 学生党适合做什么兼职,学生党兼职项目推荐
  7. access自动自动累计余额_云表:逐行累计余额的设计方法(填报篇)
  8. ubuntu 安装 windows 字体 美化
  9. 电梯新时达系统用什么样的服务器,新时达(AS380)系统UCMP国标功能
  10. 基于JPA实现多表连接查询