android密集架移动动画效果开发

机缘

因公司需要开发密集架相关项目,涉及相关项目需求设计,市场上并未有相关动画效果流出,基于设计开发相关需求

多列密集架情况:

  1. 密集架固定列在最左侧
  2. 密集架固定列在最右侧
  3. 密集架固定列在最中间

收获

最终完成初步效果

实例展示:

android密集架移动效果


部分核心代码

  • 基于需求的复杂性 内部设计是否开启柜体动画,若不开启则直接与硬件通信
  • 密集架向左移动核心代码:
java 复制代码
fun moveToLeft(clickedIndex: Int){
        if (isAnimation){
            if (isAir){
                Log.e("TAG","正在通风不可移动")
                Toast.makeText(this,"正在通风不可移动",Toast.LENGTH_SHORT).show()
                return
            }
            if (clickedIndex==fixRow){
                Log.e("TAG","固定列不可移动")
                Toast.makeText(this,"固定列不可移动",Toast.LENGTH_SHORT).show()
                return
            }
            isStop = false
            mBinding.stopTv.text = "停止"
            val childCount = mBinding.llOut?.childCount ?: 0
            if (fixRow==0) { // 固定列在最左侧
                var beginIndex = -1
                for (i in 1 until childCount){
                    var rowBean = allBeans[i]
                    if (rowBean.currentX==rowBean.destX||rowBean.currentX==rowBean.middleX||rowBean.currentX!=rowBean.rawX){ //说明已经移动到位
                        beginIndex = i
                        break
                    }
                }
                if (beginIndex==-1){
                    Log.e("TAG","没有向右移动过不可向左移动")
                    return
                }
                var delay: Long = 0 // 初始延迟时间
                cancleAllAnimation()
                for (i in beginIndex..clickedIndex){
                    var view = mBinding.llOut?.getChildAt(i)
                    var rowBean = allBeans[i]
                    var viewx = view!!.x
                    if (viewx==rowBean.rawX){ //说明已经移回原位
                        continue
                    }
                    allAnimation[i] = ValueAnimator.ofInt(rowBean.currentX.toInt(), rowBean.rawX.toInt())
                    allAnimation[i]?.startDelay = delay
                    allAnimation[i]?.duration = moveTime
                    allAnimation[i]?.addUpdateListener { animation ->
                        val currentValue = animation.animatedValue as Int
                        // 更新视图的左边距,实现平移动画
                        view?.layout(currentValue.toInt(), view.top, (currentValue + view.width).toInt(), view.bottom)
                        // 更新当前 x 坐标
                        rowBean.currentX = view.left.toFloat()
                        Log.e("TAG", "固定列在最左侧 向左移动 实时更新获取当前 view 对象 x 坐标:${rowBean.currentX}    view 左边距 ${view.left}")
                    }
                    allAnimation[i]?.start()
                    delay+=delayAddTime
                }
            }else if (fixRow==childCount-1){ // 固定列在最右侧
                var delay: Long = 0 // 初始延迟时间
                cancleAllAnimation()
                for (i in 0..clickedIndex){
                    var view = mBinding.llOut?.getChildAt(i)
                    var rowBean = allBeans[i]
                    var viewx = view!!.left.toFloat()
                    rowBean.currentX = viewx
                    if (rowBean.currentX==rowBean.destX){ //说明已经移动到位
                        continue
                    }
                    allAnimation[i] = ValueAnimator.ofInt(rowBean.currentX.toInt(), rowBean.destX.toInt())
                    allAnimation[i]?.startDelay = delay
                    allAnimation[i]?.duration = moveTime
                    allAnimation[i]?.addUpdateListener { animation ->
                        val currentValue = animation.animatedValue as Int
                        // 更新视图的左边距,实现平移动画
                        view?.layout(currentValue, view.top, currentValue + view.width, view.bottom)
                        // 更新当前 x 坐标
                        rowBean.currentX = view.left.toFloat()
                        Log.e("TAG", "固定列在右侧 向左移动 实时更新获取当前 view 对象 x 坐标:${rowBean.currentX}    view 左边距 ${view.left}")
                    }
                    allAnimation[i]?.start()
                    delay+=delayAddTime
                }

            }else{ //固定列在中间
                if (clickedIndex<fixRow){ // 点击位置处于固定列左侧 初始只能向左移动 不可向右移动
                    var delay: Long = 0 // 初始延迟时间
                    var beginIndex = 0
                    for (i in fixRow downTo clickedIndex){
                        var rowBean = allBeans[i]
                        if (rowBean.rawX==rowBean.destX){
                            continue
                        }
                        if (rowBean.currentX==rowBean.destX||rowBean.currentX==rowBean.middleX||rowBean.currentX!=rowBean.rawX){
                            beginIndex=i
                            break
                        }
                    }
//                    for (i in beginIndex..clickedIndex){
//                        allAnimation[i]?.let {
//                            it.cancel()
//                        }
//                    }
                    for (i in beginIndex..clickedIndex){
                        var view = mBinding.llOut?.getChildAt(i)
                        var rowBean = allBeans[i]
                        var viewx = view!!.left.toFloat()
                        rowBean.currentX = viewx
                        if (rowBean.currentX==rowBean.destX){ //说明已经移动到位 向左移动 已经移动到目标位置 不可再次向左移动
                            continue
                        }
                        allAnimation[i] = ValueAnimator.ofInt(rowBean.currentX.toInt(), rowBean.destX.toInt())
                        allAnimation[i]?.startDelay = delay
                        allAnimation[i]?.duration = moveTime
                        allAnimation[i]?.addUpdateListener { animation ->
                            val currentValue = animation.animatedValue as Int
                            // 更新视图的左边距,实现平移动画
                            view?.layout(currentValue, view.top, currentValue + view.width, view.bottom)
                            // 更新当前 x 坐标
                            rowBean.currentX = view.left.toFloat()
                            Log.e("TAG", "固定列在右侧 向左移动 实时更新获取当前 view 对象 x 坐标:${rowBean.currentX}    view 左边距 ${view.left}")
                        }
                        allAnimation[i]?.start()
                        delay+=delayAddTime
                    }
                }else{
                    var delay: Long = 0 // 初始延迟时间
                    var beginIndex = clickedIndex
                    for (i in fixRow..clickedIndex){
                        var rowBean = allBeans[i]
                        if (rowBean.rawX==rowBean.destX){
                            continue
                        }
                        if (rowBean.currentX==rowBean.destX||rowBean.currentX==rowBean.middleX||rowBean.currentX!=rowBean.rawX){
                            beginIndex = i
                            break
                        }
                    }
//                    for (i in beginIndex..clickedIndex){
//                        allAnimation[i]?.let {
//                            it.cancel()
//                        }
//                    }
//                    cancleAllAnimation()
                    for (i in beginIndex .. clickedIndex){ // 固定列在中间 从当前点击位置 降序 固定列位置 判断其是否能左移
                        var view = mBinding.llOut?.getChildAt(i)
                        var rowBean = allBeans[i]
                        var viewx = view!!.x
                        if (viewx == rowBean.rawX) { //说明目前在原位置 不可向左移动
                            continue
                        }
                        allAnimation[i] = ValueAnimator.ofFloat(rowBean.currentX, rowBean.rawX) // 向左移动 移动回初始位置
                        allAnimation[i]?.startDelay = delay
                        allAnimation[i]?.duration = moveTime
                        allAnimation[i]?.addUpdateListener { animation -> val currentValue = animation.animatedValue as Float
                            // 更新视图的左边距,实现平移动画
                            view?.layout(currentValue.toInt(), view.top, (currentValue + view.width).toInt(), view.bottom)
                            // 更新当前 x 坐标
                            rowBean.currentX = view.left.toFloat()
                            Log.e("TAG", "实时更新获取当前 view 对象 x 坐标:${rowBean.currentX}    view 平移距离:${view.left}")
                        }
                        allAnimation[i]?.start()
                        delay+=delayAddTime
                    }
                }
            }
        }else{
            //直接向硬件发送指令 向左移动


        }

    }
  • 密集架向右移动核心代码
java 复制代码
    fun moveToRight(clickedIndex: Int){
        if (isAnimation){
            if (isAir){
                Log.e("TAG","正在通风不可移动")
                Toast.makeText(this,"正在通风不可移动",Toast.LENGTH_SHORT).show()
                return
            }
            if (clickedIndex==fixRow){
                Log.e("TAG","固定列不可移动")
                Toast.makeText(this,"固定列不可移动",Toast.LENGTH_SHORT).show()
                return
            }
            isStop = false
            mBinding.stopTv.text = "停止"
            val childCount = mBinding.llOut?.childCount ?: 0
            if (fixRow==0){ // 固定列在最左侧
                var delay: Long = 0 // 初始延迟时间
                cancleAllAnimation()
                for (i in childCount-1 downTo clickedIndex){
                    var view = mBinding.llOut?.getChildAt(i)
                    var rowBean = allBeans[i]
                    var viewx = view!!.x
                    if (viewx==rowBean.destX){ //说明已经移动到位
                        continue
                    }
                    allAnimation[i] = ValueAnimator.ofFloat(rowBean.currentX, rowBean.destX)
                    allAnimation[i]?.startDelay = delay
                    allAnimation[i]?.duration = moveTime
                    allAnimation[i]?.addUpdateListener { animation ->
                        val currentValue = animation.animatedValue as Float
                        // 更新视图的左边距,实现平移动画
                        view?.layout(currentValue.toInt(), view.top, (currentValue + view.width).toInt(), view.bottom)
                        // 更新当前 x 坐标
                        rowBean.currentX = view.left.toFloat()
                        Log.e("TAG", "实时更新获取当前 view 对象 x 坐标:${rowBean.currentX}    view 平移距离:${view.left}")
                    }
                    allAnimation[i]?.start()
                    delay+=delayAddTime
                }
            }else if (fixRow==childCount-1){ // 固定列在最右侧
                var delay: Long = 0 // 初始延迟时间
                var beginIndex = -1
                for (i in fixRow downTo clickedIndex){
                    var rowBean = allBeans[i]
                    if (rowBean.currentX==rowBean.destX||rowBean.currentX==rowBean.middleX||rowBean.currentX!=rowBean.rawX){
                        beginIndex = i
                        break
                    }
                }
                cancleAllAnimation()
                for (i in beginIndex downTo clickedIndex){
                    var view = mBinding.llOut?.getChildAt(i)
                    var rowBean = allBeans[i]
                    var viewx = view!!.x
                    if (viewx==rowBean.rawX){ //说明已经移回原位
                        continue
                    }
                    allAnimation[i] = ValueAnimator.ofInt(rowBean.currentX.toInt(), rowBean.rawX.toInt())
                    allAnimation[i]?.startDelay=delay
                    allAnimation[i]?.duration = moveTime
                    allAnimation[i]?.addUpdateListener { animation ->
                        val currentValue = animation.animatedValue as Int
                        // 更新视图的左边距,实现平移动画
                        view?.layout(currentValue, view.top, currentValue + view.width, view.bottom)
                        // 更新当前 x 坐标
                        rowBean.currentX = view.left.toFloat()
                        Log.e("TAG", "固定列在右侧 向左移动实时更新获取当前 view 对象 x 坐标:${rowBean.currentX}    view 左边距 ${view.left}")
                    }
                    allAnimation[i]?.start()
                    delay+=delayAddTime
                }
            }else{ //固定列在中间
                if (clickedIndex<fixRow){
                    var delay: Long = 0 // 初始延迟时间
                    var beginIndex = fixRow
                    for (i in fixRow downTo clickedIndex){
                        var rowBean = allBeans[i]
                        if (rowBean.rawX==rowBean.destX){
                            continue
                        }
                        if (rowBean.currentX==rowBean.destX||rowBean.currentX==rowBean.middleX||rowBean.currentX!=rowBean.rawX){
                            beginIndex=i
                            break
                        }
                    }
//                    cancleAllAnimation()
//                    for (i in beginIndex downTo clickedIndex){
//                        allAnimation[i]?.let {
//                            it.cancel()
//                        }
//                    }
                    for (i in beginIndex downTo clickedIndex){
                        var view = mBinding.llOut?.getChildAt(i)
                        var rowBean = allBeans[i]
                        var viewx = view!!.x
                        if (viewx==rowBean.rawX){ //说明已经移回原位
                            continue
                        }
                        allAnimation[i] = ValueAnimator.ofInt(rowBean.currentX.toInt(), rowBean.rawX.toInt())
                        allAnimation[i]?.startDelay=delay
                        allAnimation[i]?.duration = moveTime
                        allAnimation[i]?.addUpdateListener { animation ->
                            val currentValue = animation.animatedValue as Int
                            // 更新视图的左边距,实现平移动画
                            view?.layout(currentValue, view.top, currentValue + view.width, view.bottom)
                            // 更新当前 x 坐标
                            rowBean.currentX = view.left.toFloat()
                            Log.e("TAG", "固定列在右侧 向左移动实时更新获取当前 view 对象 x 坐标:${rowBean.currentX}    view 左边距 ${view.left}")
                        }
                        allAnimation[i]?.start()
                        delay+=delayAddTime
                    }
                }else{
                    var delay: Long = 0 // 初始延迟时间
//                    cancleAllAnimation()
//                    for (i in childCount-1 downTo clickedIndex){
//                        allAnimation[i]?.let {
//                            it.cancel()
//                        }
//                    }
                    for (i in childCount-1 downTo clickedIndex){
                        var view = mBinding.llOut?.getChildAt(i)
                        var rowBean = allBeans[i]
                        var viewx = view!!.x
                        if (viewx==rowBean.destX){ //说明已经移动到位
                            continue
                        }
                        allAnimation[i] = ValueAnimator.ofFloat(rowBean.currentX, rowBean.destX)
                        allAnimation[i]?.startDelay = delay
                        allAnimation[i]?.duration = moveTime
                        allAnimation[i]?.addUpdateListener { animation ->
                            val currentValue = animation.animatedValue as Float
                            // 更新视图的左边距,实现平移动画
                            view?.layout(currentValue.toInt(), view.top, (currentValue + view.width).toInt(), view.bottom)
                            // 更新当前 x 坐标
                            rowBean.currentX = view.left.toFloat()
                            Log.e("TAG", "实时更新获取当前 view 对象 x 坐标:${rowBean.currentX}    view 平移距离:${view.left}")
                        }
                        allAnimation[i]?.start()
                        delay+=delayAddTime
                    }
                }
            }
        }else{
            //向右移动直接向硬件发送 指令
        }
    }

Tips

  • 柜体移动复杂性涉及多个方面,目前仅android端开发完成,与硬件交互方面同步移动暂未处理(若要实现或许可以通过使用view坐标轴来实现)
相关推荐
千里马学框架1 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台1 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone1 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc1 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo1 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077001 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼1 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone1 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen1 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone1 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui