音频播放动画 频段跳动

在这里插入图片描述

在这里插入图片描述
项目地址:https://github.com/xieyang94/AudioView

这个主要是受到 https://www.jianshu.com/p/76aceacbc243 的影响

但是和我个人的需求不同,主要是和UI的需求不同;就自己打算模仿写一个,如上图所示;

从开始写到现在的模样一共迭代了7个版本;

第一个版本
在这里插入图片描述
就是画出这么一个频段,主要依据就是,将高度平均分成六份,第一个竖线占据两份,第二个四份,第三个占据6份;然后再反着来一遍;静态的图就
在这里插入图片描述
没有好的作图工具,大概就是这么个意思;
找到中分线的位置,这个就是用总高度减去上下的两个padding,除以2就行,但是我的第一版想的太复杂,所以第一版还没有计算中分线,而是硬生生计算出来的上下坐标并绘制;然后计算第二个的上下坐标并绘制,第三个的上下坐标并绘制,后面的三个反着来;
我把这样的六根竖线分成一组,每一根线用一个类表示,里面有个属性就是他的高度;六根线用一个类表示这样一个组合;每个组合六根线,这样一个静态的图就出来了;

接着就是让它动起来,怎么动呢?我想的是让他们以一种速率增加自身的高度,而增加到了极限(控件的宽度-padding),就开始以同样的速度开始减小,减小到第一根线的原始长度又开始增加,就这样的运动;

这样为了判断他们是否到达两个极限,就需要更改他们的增长趋势(正向还是反向),所以每根线又多了一个字段用于记录当前应该是正增长还是负增长;

这样单个的看起来还可以用的

在这里插入图片描述

但是我要的是多组在一块的;

在这里插入图片描述
这样看起来就有点别扭了,每隔五根线就有一个一样的在同时同样运动,看起来比较尴尬;想了想,一组不要6根线,只要4根线,去掉中间最长的两根中的一根,去掉最后一根;这样第二组就和第一组直接对接上了;这样可能会好一点;

在这里插入图片描述

然而并没有,还是有一种起头并进的感觉;太有规律了反而感觉不自然;

不过目前好歹实现了;

第二版:

UI打回来,说看起来太僵硬,还出主意是不是一组线条太少的缘故?
说的有道理,那就试试8根线条的;

在这里插入图片描述

这下感觉更僵硬了,至于更多的10根,50根的更不用想了,最后就一组,一组里面就一百根,肯定跟个梭子似的;

这块算是暂时没办法,那就先把代码优化一下;

第三版:
之前一组里面是放了八根线,也就是八个类,用个List装起来吧;
记录一组初始高度,这个还是好记录的,只记录高度,不记录坐标;看一个组合里面有几根线,还是第一根线占据两份,最长一根线占满,把所有的初始高度记录下来;
之前绘制的时候是一组一组的绘制的,现在直接list遍历绘制;

代码量是减少了不少,但是结果不是想要的;

第四版:

现在想要的就是将有序变成无序,那就加入随机数;
在初始高度上的基础上,加入一个高度在1到总高度的中间随机值;然后超过总高度,再减去这个之间的一个随机值,这样两次随机;这样一高一低两个临界值卡着;低不能低到0,高最高高出总高度的0.5倍,而只要超过高度就进行负增长,这样就始终在增-减-增-减-减-减…大概这样的无序随机中做运动;

在这里插入图片描述
这一版的效果是我想要的;UI也表示接受;

这个和我当初预想的代码逻辑不一样,毕竟我一开始是以有序出发,现在的结果是在有序上面做无序,那我还不如直接就做无序呢;上来初始化n根线的高度,然后绘制的时候,找到中间线进行增减,思路一样;

第五版:
既然已经实现了效果,那就规范一下代码;

一些控制变量搞成自定义属性;删掉没用到的代码;

但是当时只顾得绘制,宽高则没有适配;

第六版:
重写onMeasure方法,计算宽高,高度还好,毕竟涉及到高度的不多,直接在自适应的时候指定一个默认高度;
宽度则要麻烦一点,自适应的时候,计算自身的宽度还好计算,x轴一直往前走;但是当超出屏幕宽度的时候,要么断然舍弃后面的,也指定一个默认高度,但是这样不太友好;
这边做的处理就是当超出屏幕宽度的时候,则计算所有线所占据的宽度,然后用剩余的宽度计算出每根线之间的间距,之前的间距是可以配置的,然后再重新计算宽度;
这样也不是最好的方法,因为5它还面临一个问题,那就是假设线太多了,光线的宽度加起来都超过一个屏幕,这样就不管用了,其实这种也没必要考虑,都挤成这样了,UI那能通的过去?

就目前的代码而言,可以达到使用度了,我们是该控件的后面跟着一个文本,如果控件的宽度短一点还好,但是如果太长了,也看到了我们上面的处理是在和屏幕(父控件)总长度做的处理,当到达一定的值后,会占据父控件的总宽度,把文本控件挤没了;

这样也有处理方法,那就是在用这个控件的时候,外面嵌套一层布局,这样就让它独享一个父控件;
但是难免嵌套过多;

第七版: 可使用

现在嵌套过多,,就想要这么一个父布局,先满足后面的文本控件,然后剩余的宽度再满足频段控件;因为后面的文本控件的宽度是有限的,所以不会出现文本控件把频段控件挤没了的情况;
自定义吧:

先加个判断,指定就俩控件,多了就抛异常;
先测量第二个文本控件的宽度,然后用父控件的宽度减去第二个控件的宽度,重新组装MeasureSpec,测量第一个控件的宽度;
在高度计算上如果自适应,需要比较两次,先比较俩控件的高度最大值,然后加上padding,再和默认值(这个感觉可以不要了?)以及测量值作比较;
onLayout中就是正常的计算布局;

这样也算是满足了自己的需求;

在这里插入图片描述
同时,因为用到了Handler+子线程的方式,内部类持有外部类的引用导致内存泄漏的问题,静态方法是用不了了,那就用弱引用;

第八版:进行中(卡住了)

但是又出现了另一个尴尬的问题,这个用在单一的位置没有问题,用在列表上就尴尬了,每个ViewHolder里面都有一个子线程只要你运行了就始终在 跑着,总不能运行一个结束就干掉一个子线程,因为用户还有可能再次点击;既然涉及到了线程的问题,那就用线程池吧,而且让用户从外部传入,这样在页面结束的时候shutdown()/shutdownow(),但是等操作的时候才反应过来,这个只是改变他的线程状态,而我的是用一个while(flag)跑起来的的死循环逻辑计算;根本调不出来,要是kotlin协程的isAtive就可以了,但我这是用java写的。。。。;(有道理啊,我可以改成kotlin,直接用协程,才想到);

现在想的解决思路就是找到所有的缓存ViewHolder,然后遍历将flag设置为false结束;但是没找到相应获取缓存ViewHolder的方法(难倒是需要自己将那三级缓存[没用到自定义缓存]加起来,一个个的去找?);问了问之前的同事(做后台的),他说你可以用session的思想,在while那做一个时间间隔判断,然后在当前页面每隔一段时间发送一个刷新;大概就心跳这意思;但是这样同样不是得找到所有的ViewHolder吗,而且这样如果是为了处理当前逻辑在页面上加就会造成这个控件耦合太严重,如果在控件中加,则加入了跟业务相关的东西,太庞杂了;所以也不行;
还有一个问题就是ViewHolder的复用问题,导致控件UI刷新出现问题;

所以这个控件到目前为止,如果只是用于单一的使用,是没有问题的,但是如果用到列表中还任重而道远;如果您有什么好的想法或者思路还希望探讨一下,一起解决这个问题。


2019/09/11补充:

按照昨天的设想,怎么去拿到ViewHolder,咨询了一下,有说通过反射RecyclerView拿到所有的缓存ViewHolder,这个思路很不错,但是反射比较被人诟病(反正我觉得反射挺好的,只不过别人抨击反射的时候,总是拿科学计数法级别的运算来抨击反射的性能不好,但是这样的场景又有多少,到了这种场景还需要你说,谁都知道要各种优化性能啥的,但是大部分的场景不还是可以忽略反射所带来的时间损耗麽,扯远了),但是如果RecyclerView的代码结构如果改掉了,对应的缓存列表不叫那个名字了,就坑了;所以还是避开反射,先在一二级缓存中找,找不到就去三级缓存池中去找,还找不到那说明该index对应的ViewHolder没有,如果有,肯定就会被找到(遍历列表,一个一个的找);
所以目前在释放子线程任务这个问题可以解决了;
再一个问题就是ViewHolder复用带来的控件UI改变的问题;

对于特殊的需求,可以打打擦边球,只要你能明确你的列表不超过二级缓存的数量(大概计算方式就是:当前页面呈现的数量+(2+一行的item数量),就没问题,因为到这里就没用到清除数据的ViewHolder;


项目地址:https://github.com/xieyang94/AudioView

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值