标题可能不太直观,想了半天也没想到好的,那么就先贴一张具体应用场景的效果图:

就是这一块:


相信大家在做商城类应用时,经常会有相似需求!

本项目实现的效果如下图:

最开始通过RecyclerView实现,也可以,但是在进行嵌套特别是ScrollView等滑动控件时,就会出现触摸bug,即便你将recyclerview禁止滑动也不行,虽说这个bug不算太影响体验,但是对于追求完美的我,不能忍,就再寻找了另一种实现方式:动态add/removeView+属性动画!

原理其实很简单:

首先,分析效果图,ui上显示itemview的个数为始终2,每次向上滑动1,很容易就能想到,在父容器中始终有3个itemview,父容器高度为2个itemview的高度,然后第一个itemview在规定时间内,向上移动一个itemview的高度即可(通过不断设置marginTop),然后父容器remove第一个view,再add下一个view,循环往复!


至于向上滚动时,第一个view的渐隐效果,只需要在属性动画的UpdateListener中,除了不断设置marginTop外,另外就是实时更新view的透明度即可!

animator.addUpdateListener { animation: ValueAnimator ->val value = animation.animatedValue as Intvar layoutParams: LinearLayout.LayoutParams =v.rootView.getChildAt(0).layoutParams as LinearLayout.LayoutParams     layoutParams.topMargin = -valuev.rootView.getChildAt(0).layoutParams = layoutParamsv.rootView.getChildAt(0).alpha = (0.6f - value / height.toFloat())
}

以下时PinTuanView主要代码:

PinTuanView:

package com.byl.pin.viewimport android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.widget.FrameLayout
import android.widget.LinearLayout
import androidx.core.view.children
import com.byl.pin.R
import com.byl.pin.bean.ItemBean
import com.byl.pin.databinding.ViewItemBinding
import com.byl.pin.databinding.ViewPinBinding
import com.byl.pin.util.Utils.dp2Pxclass PinTuanView : FrameLayout {companion object {const val SHOW_COUNT = 2const val TIME_INTERVAL: Long = 3000}val v = ViewPinBinding.inflate(LayoutInflater.from(context), this, true)var listData: ArrayList<ItemBean>? = nullvar scrollTask: ScrollTask? = nullvar preShowIndex = 0constructor(context: Context) : super(context) {initAttributeSet(null)}constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {initAttributeSet(attrs)}constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context,attrs,defStyleAttr) {initAttributeSet(attrs)}private fun initAttributeSet(attrs: AttributeSet?) {}fun setData() {stop()v.rootView.removeAllViews()listData = ArrayList()for (i in 0..3) {val itemBean = ItemBean()itemBean.id = iitemBean.name = "哈哈哈$i"itemBean.endTime = System.currentTimeMillis() + 2 * 24 * 60 * 60 * 1000listData!!.add(itemBean)}//如果list条数为不超过2个,则不执行滚动动画if (listData!!.size <= SHOW_COUNT) {listData!!.forEach {v.rootView.addView(getItemView(it))}return}//超过两个时,先向容器中添加三个Itemfor (i in 0..SHOW_COUNT) {v.rootView.addView(getItemView(listData!![i]))}preShowIndex = SHOW_COUNT + 1//即将显示的数据的index}fun getItemView(itemBean: ItemBean): View {val itemView = ViewItemBinding.inflate(LayoutInflater.from(context), null, false)itemView.tvName.text = itemBean.nameitemView.mCountDownView.setRemainTime(itemBean.endTime)itemView.mCountDownView.start()itemView.mCountDownView.addTimerEndListener {//TODO 倒计时结束}itemView.btnAddTeam.setOnClickListener {clickTeam(itemBean)}return itemView.root}fun start() {if (listData!!.size <= SHOW_COUNT) returnif (scrollTask != null) {removeCallbacks(scrollTask)scrollTask = null}scrollTask = ScrollTask()postDelayed(scrollTask, TIME_INTERVAL)}fun stop() {if (scrollTask == null) returnremoveCallbacks(scrollTask)scrollTask = nullv.rootView.children.forEach {it.findViewById<CountTimerView>(R.id.mCountDownView).stop()}}inner class ScrollTask : Runnable {override fun run() {val height = dp2Px(context, 80f)val animator = ValueAnimator.ofInt(height)animator.duration = 500animator.start()animator.addUpdateListener { animation: ValueAnimator ->val value = animation.animatedValue as Intvar layoutParams: LinearLayout.LayoutParams =v.rootView.getChildAt(0).layoutParams as LinearLayout.LayoutParamslayoutParams.topMargin = -valuev.rootView.getChildAt(0).layoutParams = layoutParamsv.rootView.getChildAt(0).alpha = (0.6f - value / height.toFloat())}animator.addListener(object : AnimatorListenerAdapter() {override fun onAnimationEnd(animation: Animator?) {super.onAnimationEnd(animation)v.rootView.getChildAt(0).findViewById<CountTimerView>(R.id.mCountDownView).stop()v.rootView.removeViewAt(0)if (listData!!.size <= preShowIndex) {preShowIndex = 0}v.rootView.addView(getItemView(listData!![preShowIndex]))preShowIndex++postDelayed(scrollTask, TIME_INTERVAL)//当转完一圈后,刷新数据(这个地方为模拟刷新,可以在实际应用中重新请求接口,达到无感刷新)if (preShowIndex == SHOW_COUNT + 1) {handler.postDelayed({setData()start()}, 1000)}}})}}private lateinit var clickTeam: (itemBean: ItemBean) -> Unitfun addClickTeamListener(clickTeam: (itemBean: ItemBean) -> Unit) {this.clickTeam = clickTeam}}

使用方法非常简单:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:background="@color/white"><com.byl.pin.view.PinTuanViewandroid:id="@+id/mPinTuanView"android:layout_width="match_parent"android:layout_height="wrap_content"/></LinearLayout>
  mPinTuanView.setData()mPinTuanView.start()
  override fun onDestroy() {super.onDestroy()mPinTuanView.stop()}

另外,其中还有自定义的CountTimerView,具体可参考项目源码:

https://download.csdn.net/download/baiyuliang2013/14949415

github:https://github.com/baiyuliang/PinTuanView

拼团列表item自动滚动+倒计时实现相关推荐

  1. Android recyclerview item获焦时更新UI导致列表自动滚动到获焦处

    问题场景描述:scrollview嵌套rv,rv item里有edittext,当edittext处于获焦状态时,item中有数据改变导致更新UI时,此时列表会自动滚动到获焦处. 分析原因:更新UI时 ...

  2. 怎么实现微信小程序云开发拼团功能?

    [微信云开发教程]怎么实现微信小程序云开发拼团功能? 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 [微 ...

  3. 手把手教你设计:拼团活动

    写在前面 最近拼团活动十分流行,光是文章我都写过两篇,但大家貌似对拼团的设计思路并不感冒,反而对具体到原型层面上的更感兴趣.刚好最近我又优化了一遍拼团的活动,所以再写多一篇关于具体如何设计拼团活动的文 ...

  4. 拼团兴起:真团购假低价

    来源 北京商报 记者 王晓然 赵述评 拼团与低价成为相关联的符号后,商家频频打出拼团这张牌,牌桌另一端的消费者受固有印象的影响忽略了牌面上的数字,反而可能以更高的价格购买拼团商品.2月25日,每日优鲜 ...

  5. 全面解析小程序拼团营销玩法,两大经典拼团活动案例分享

    小程序拼团作为当下主流的社交营销玩法,在各行业应用中也是非常广泛的.策划一场成功的拼团活动,可以实现快速裂变传播,带来更多新客和订单. 接下来,我们就介绍一下如何策划一场成功的拼团活动,并分享两个经典 ...

  6. Niushop 拼团活动

    拼团 设置拼团相关活动 拼团是专为卖家推出的一款营销活动,活动基于多人凑团的形式,鼓励买家发起拼团,邀请好友以折扣价购买, 可帮助商家在提高商城销售额的同时带来更多的粉丝. 打开后台-营销-营销中心- ...

  7. 微信小程序拼团后端接口设计规范

    来源:https://share.notestore.cn/ac... 公告列表 接口地址: g=Api&m=Banner&a=lists 返回说明 //正常返回的JSON数据包 {& ...

  8. 小程序拼团,分销逻辑

    一:拼团 1.数据库中需要增加两张表:a.拼团表group b.拼团订单表group_order 2.后台添加一个拼团活动,group表添加一条数据 3.小程序端 a.展示拼团列表 b.点进去一个拼团 ...

  9. java拼团小程序源码(毕设)

    开发环境及工具: 大于Jdk1.8,大于mysql5.5,idea(eclipse),微信小程序开发工具 技术说明: Springboot mybatis html vue.js bootstrap ...

最新文章

  1. linux下bus、devices和platform的基础模型
  2. 基于java+jdbc+servlet+jsp实现图书商城
  3. flutter 移动通知_Flutter移动电商实战 --(24)Provide状态管理基础
  4. [转]Windows Shell 编程 第十四章【来源:http://blog.csdn.net/wangqiulin123456/article/details/7988010】...
  5. html除左侧浮动,html清除浮动的6种方法示例
  6. VTP (vlan trunking protocol)
  7. 在Elasticsearch中索引Java Bean的简单方法
  8. android运行时状态,Android 如何保存Android 运行时状态
  9. listView当中有嵌套了有onClickListener的控件时ListView自身的onItemClick无响应的解决方案...
  10. php的用户认证(有点难度 多看几遍吧)
  11. mysql中locat函数,MySQL中的LOCATE和POSITION函数使用方法 | 很文博客
  12. 【Python实例第22讲】不同聚类算法的比较分析
  13. Django实现统计网站访问次数、访问 ip 、受访页面
  14. 初装vs2010旗舰版 遇到的错误
  15. javascript getDay()方法 语法
  16. 项目:数据库表的梳理
  17. 【leetcode】小行星碰撞
  18. (13.1.2)PMBOK之二:五大过程组及其涉及的输入、输出、工具技术
  19. Dots Entity 删除
  20. 【AAAI 2021】时间序列相关论文汇总

热门文章

  1. ASP.NET Boilerplate v5升级到Abp vNext的改动
  2. 【操作系统】Linux系统中直接优化提升CPU性能(已解决)
  3. 回调地狱终结者——Promise
  4. 移动支付战火连绵,支付宝、微信支付、云闪付APP或将三足鼎立?
  5. python之Bottle框架
  6. .cer证书不能导出.p12证书|苹果证书怎么修改信任设置。
  7. 在html中添加滤镜,HTML中的滤镜
  8. Cisco 9800 WLC PID
  9. 深入浅出的数据分析方法
  10. 阿里云短信服务的签名和模板的审核通过办法(已申请通过)