实现马蜂窝旅游头像泡泡动画
当pm制定完下一版本需求,打开马蜂窝旅游app准备出去嗨一圈的时候 ,看到了马蜂窝旅游app的一个用户头像动画后。。。(=@__@=) 先看看效果图:
效果分析:
1、涉及到有多个view在做动画操作 这里需要继承FrameLayout来左父布局 供图片做动画操作
2、每个子view的动画路径类似于S型 我这里采用的是三阶贝塞尔曲线和PathMeasure来完成动画运动路径的封装
每个子view动画执行完后 是移除添加新的view进来 还是回收重新利
3、用 本案例是直接移除再添加新的(回收重新利用还没来得及去考虑该怎么写)
4、动画是循环不停的播放 我采用的是RxJava timer()操作符 不断的发送随机延迟消息去通知动画的执行
5、最后就剩下一些停止动画操作的开关设定
实现步骤
1、一些基本的初始化工作
public class HeadBubbleView extends FrameLayout {//这个position很重要 不断的取出图片资源 靠它累加完成的private int position = 0;public HeadBubbleView(@NonNull Context context) {this(context,null);}public HeadBubbleView(Context context, AttributeSet attrs) {super(context, attrs);mContext = context;setFocusable(false);//三阶贝塞尔曲线控制点一controlPointOne = new Point();//三阶贝塞尔曲线控制点二controlPointTwo = new Point();//每个子view的宽高是固定的viewWidth = viewHeight = SizeUtils.dp2px(context, 22);marginLeft = SizeUtils.dp2px(context, 15);marginBot = SizeUtils.dp2px(context, 21);//父View的高度也是固定的height = SizeUtils.dp2px(context, 130);//用于从PathMeasure 中不断的取出 曲线的路径值pos = new float[2];tan = new float[2];initView();}
2、初始化的时候数据的加载状态
private void initView() {//这个ImageView将不执行动画 用于底部不断切换图片展示tempImageView = getImageView();textView = getTextView();initData(tempImageView);}
//创建执行动画的具体角色
private ImageView getImageView() {LayoutParams layoutParams = new LayoutParams(viewWidth, viewHeight);ImageView roundedImageView = new ImageView(getContext());roundedImageView.setScaleType(ImageView.ScaleType.FIT_XY);layoutParams.gravity = Gravity.BOTTOM | Gravity.END;layoutParams.setMargins(0, 0, marginLeft, marginBot);addView(roundedImageView, layoutParams);return roundedImageView;}
//创建用于显示坐标xx来过的TextView
private TextView getTextView() {int bottom = SizeUtils.dp2px(mContext, 23);int right = SizeUtils.dp2px(mContext, 41);LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);layoutParams.gravity = Gravity.END | Gravity.BOTTOM;layoutParams.setMargins(0, 0, right, bottom);TextView tv_name = new TextView(mContext);tv_name.setTextSize(12);tv_name.setTextColor(Color.WHITE);addView(tv_name, layoutParams);return tv_name;}
//第一次加载数据
private void initData(ImageView roundedImageView) {if (null != browseEntities && browseEntities.size() > 0) {//第一次去第0个数据BrowseEntity browseEntity = browseEntities.get(position);if (null != browseEntity) {roundedImageView.setBackgroundResource(browseEntity.drawableId);String username = browseEntity.name;if (!TextUtils.isEmpty(username)) {textView.setText(username + "来过");}}}}
由上面的操作就完成基础显示
3、接下来完成第一阶段动画 由最小缩放到最大
private boolean createAnimView() {if (!isStop) {return true;}ImageView imageView = getImageView();//创建好后 设置缩放到最小imageView.setScaleX(0);imageView.setScaleY(0);initData(imageView);startScaleAnim(imageView);return false;}
//执行缩放动画
private void startScaleAnim(final ImageView imageView) {ValueAnimator valueAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);valueAnimator.setDuration(800);valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {float animatedValue = (float) animation.getAnimatedValue();imageView.setScaleX(0.1f + animatedValue);imageView.setScaleY(0.1f + animatedValue);}});valueAnimator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {if (position == browseEntities.size() - 1) {position = 0;} else {position++;}BrowseEntity browseEntity = browseEntities.get(position);//动画执行完后要立马取出下一个图片 把底部的图片显示更新tempImageView.setBackgroundResource(browseEntity.drawableId);//动画执行完执行平移动画 startTranslationAnimator(imageView);}});valueAnimator.start();}
4.第二阶段的曲线运动缩小动画
private void startTranslationAnimator(final ImageView imageView) {Path path;int seed = (int) (Math.random() * 100);//根据随机数来确定是走左边曲线还是右边曲线if (seed % 2 == 0) {//曲线路径的封装path = createRightPath();} else {//曲线路径的封装path = createLeftPath();}//通过PathMeasure 和ValueAnimator结合 在不同的阶段取出运动路径的x,y值final PathMeasure pathMeasure = new PathMeasure(path, false);final ValueAnimator valueAnimator = ValueAnimator.ofFloat(1.0f, 0.0f);valueAnimator.setDuration(riseDuration);valueAnimator.setInterpolator(new LinearInterpolator());valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {float animatedValue = (float) animation.getAnimatedValue();int length = (int) (pathMeasure.getLength() * animatedValue);//在不同的阶段取出运动路径的x,y值pathMeasure.getPosTan(length, pos, tan);imageView.setTranslationX(pos[0]);imageView.setTranslationY(pos[1]);//同时做透明度动画imageView.setAlpha(animatedValue);if (animatedValue >= 0.5f) {imageView.setScaleX(0.2f + animatedValue);imageView.setScaleY(0.2f + animatedValue);}}});valueAnimator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {//动画执行完就移除ViewremoveView(imageView);}});valueAnimator.start();}
5、三阶赛贝尔曲线的计算 下面以左边的为例
这里我也没有更好的办法去计算 是通过不断预估尝试出来的 如果有大佬在这里有很好的计算方法 请务必告知下
private Path createLeftPath() {Path path = new Path();float nextFloat = new Random().nextFloat();path.moveTo(nextFloat, -height * 1.0f / 1.8f);//曲线控制点一controlPointOne.x = -(viewWidth);controlPointOne.y = -height / 5;//曲线控制点二controlPointTwo.x = -(viewWidth + marginLeft / 2);controlPointTwo.y = (int) (-height * 0.15);//生成三阶贝塞尔曲线path.cubicTo(controlPointOne.x, controlPointOne.y, controlPointTwo.x, controlPointTwo.y, 0, 0);return path;}
最后连贯起来看看效果
6、最后使用RxJava 的timer()操作符 发延迟消息来让整个动画循环执行起来
这里也可以用handler 来发消息处理
public void startAnimation(int innerDelay) {subscribe = Observable.timer(innerDelay, TimeUnit.MILLISECONDS).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<Long>() {@Overridepublic void accept(Long aLong) throws Exception {if (createAnimView()) return;int duration = (int) (1500 * Math.random());if (duration < 500) {duration = 500;}//循环调用startAnimation(500 + duration);}});}//动画执行的一些开关操作
public void stopAnimator() {isStop = false;if (null != subscribe) {subscribe.dispose();}}
到这里整个动画流程到这里就结束了,当然在内存的管理上还没有做到极致 大家可以去自由发挥, 希望这篇水文能帮助到那些有类似需求的同学,我们应该把时间拿去做一些更有用的事情,不过截止到目前 马蜂窝最新版 已经没有该头像的泡泡动画,想必他们也改了吧!
##读者福利限时分享
Android开发资料+面试架构资料 免费分享 点击链接 即可领取
《Android架构师必备学习资源免费领取(架构视频+面试专题文档+学习笔记)》
实现马蜂窝旅游头像泡泡动画相关推荐
- 高仿马蜂窝旅游头像泡泡动画
/ 今日科技快讯 / 近日微信支付分正式全面开放,用户可以直接查询并通过支付分来获得免押服务.目前,微信用户直接打开微信>我>钱包,就可以查看自己的支付分.与支付宝的芝麻信用类似, ...
- 短视频程序源码高仿马蜂窝旅游头像泡泡动画
涉及到有多个view在做动画操作 这里需要继承FrameLayout来左父布局 供图片做动画操作 每个子view的动画路径类似于S型 我这里采用的是三阶贝塞尔曲线和PathMeasure来完成动画运动 ...
- 实现马蜂窝旅游头像泡泡动画,安卓面试项目经验
if (null != browseEntity) { roundedImageView.setBackgroundResource(browseEntity.drawableId); String ...
- 高仿马蜂窝头像泡泡动画
当pm制定完下一版本需求打开马蜂窝旅游app准备出去嗨一圈的时候 看到了马蜂窝旅游app的一个用户头像动画后...(=@__@=) 先看看效果图 效果分析: 涉及到有多个view在做动画操作 这里需要 ...
- 电脑制作泡泡的html代码,Flash教你如何制作吹泡泡动画特效 -电脑资料
教程贴士:这个Flash实例制作了一个有趣的"小丑吹泡泡"动画,主要运用了椭圆.直线工具,以及任意变形和渐变填充等,操作简洁易懂,适合练习, 这个Flash实例制作了一个有趣的&q ...
- android 高光动画,记一个头像高光动画的CSS实现
前言 久违的,又抽时间写个博客(づ ̄3 ̄)づ╭❤-~ 今天想分享一个小动画的实现头像跳动并高光划过效果展示 大家可以先点进去看看效果~点击头像触发动画效果~ 或者直接看两张图片示意~全部代码贴在文字底 ...
- 【报告分享】2021年旅游新国潮大数据报告-马蜂窝旅游(附下载)
摘要:红色旅游之所以能"圈粉"95后,除了年轻人爱国热情不断高涨之外,也离不开红色景区近年来在打造创新体验方面所下的功夫.在大多数年轻人眼中,一次有品质的出行离不开文化底蕴和深度体 ...
- svg+js走路吹泡泡动画js特效代码
下载地址 svg+js走路吹泡泡动画特效代码 dd:
- html5悬浮圆圈背景动画特效,HTML5 canvas梦幻圆形泡泡动画背景特效
background.js是一款HTML5 canvas梦幻圆形泡泡动画背景特效.通过background.js插件,你可以轻松的制作出带渐变效果的气泡动画背景效果,并且背景颜色能在4种颜色间平滑过渡 ...
最新文章
- 最强 Java Redis 客户端
- Win7最高权限问题
- 设计模式之_Iterator_04
- Adwonder笔记
- 提供Gmail与Wallop邀请各两个
- Application,Session,Cookie和ViewState等对象用法和区别
- python和matlab矩阵运算效率_如何写出比 MATLAB 更快的矩阵运算程序?
- 华为HCIE之TS部分整理
- python爬取酷狗音乐_python 爬虫 爬取酷狗音乐
- MYS-6ULX-IOT 开发板测评——Yocto 创建嵌入式 Linux 发行版
- IllegalArgumentException,Mapped Statements collection does not contain value for xxxxx
- matlab自带的优化工具箱,MATLAB 自带优化工具箱(optimization Tool)之遗传算法简述...
- 苹果电脑运行3dsmax的三种方法,你知道吗?
- redis主从配置及主从切换
- 定义变量byte a = (byte)128输出a的结果
- 算法python实现_Relief算法python实现
- NJ 时钟自动调整功能(SNTP)
- JavaScript中的闭包原理
- Git本地仓库与Github远程仓库关联
- 安卓用户初次体验微信公众号信息流改版
热门文章
- 学计算机买宏基好吗,宏基笔记本电脑怎么样 宏基电脑有哪些技术优势
- 肾囊肿有哪些临床表现?
- python三种保留两位小数的方法
- 微软 raid 服务器 操作系统 2003,宝德pr2310n服务器raid配置与win2003系统安装手册.docx...
- 软件测评师之报考大纲(一)
- BAT批处理脚本案例--计算字符串长度
- 负载均衡session解决方案
- vscode 配置C#步骤
- CMake 常用总结一:CMake 单个文件目录
- android老 电池,安卓想要用三年?5000mAh电池不能少,这5款符合标准价格不贵