Android 页面滑动悬浮资源位动画+滑动监听解决方案

news2024/10/7 14:21:36

一、介绍

        在日常业务开发过程中,我们有好多资源位悬浮在页面上,特别是电商以及促销页面,有些公司恨不得把整个页面像叠汉堡一样,一层一层加内容,目的是想让更多的人通过他们的资源来完成更便捷的操作。

        但是资源是会覆盖到正常的内容,如果页面在静止的时候,资源悬停下来,滑动的时候隐藏起来,这样可以最大程度让滑动过程内容完全被消费者查阅。

二、分析

常见的有recycleview或者webview,都是viewGroup。我们只需要监听到页面滑动,但是不是所有的页面都知道滑动监听。或者能够拿到正确的滑动状态。

但是所有的view都有一个方法:

    public void setOnScrollChangeListener(OnScrollChangeListener l) {
        getListenerInfo().mOnScrollChangeListener = l;
    }
    public interface OnScrollChangeListener {
        /**
         * Called when the scroll position of a view changes.
         *
         * @param v The view whose scroll position has changed.
         * @param scrollX Current horizontal scroll origin.
         * @param scrollY Current vertical scroll origin.
         * @param oldScrollX Previous horizontal scroll origin.
         * @param oldScrollY Previous vertical scroll origin.
         */
        void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY);
    }

这个是view提供的。不管是view还是viewGroup。

我们可以通过监听view在window的坐标的变化,来判断当前view是否滚动。

三、解决方案

        通过分析,我们可以通过监听view来模拟滑动监听。正常滑动回调的时机在150毫秒之间是可以完成的,我们可以通过计时器来获取滑动最后一次时间与当前的时间做对比,这样可以根据业务去调整滑动与停止的时间差。

滑动监听

Demo:

class CountFlinerStatus {


    private  var time: Timer?=null

    private lateinit var scrollListener: ScrollStateCallback
    private var taskTime: Long = 0
    public fun scroll(scrollY: Int) {
        taskTime = System.currentTimeMillis()
        scrollListener?.let {
            it.onScrollState(true)
        }
        startTask()
    }

    public fun addScrollListener(scrollListener: ScrollStateCallback) {

        this.scrollListener=scrollListener
    }

    private fun startTask() {
        if (time == null) {
            time = Timer()
            time?.schedule(object : TimerTask() {
                override fun run() {

                    val newTime = System.currentTimeMillis()
                    if (newTime - taskTime > 200) {
                        //已停止

                        scrollListener?.let {
                            it.onScrollState(false)
                        }
                        cancelTask()
                    } else {
                        //还在滑动
                        scrollListener?.let {
                            it.onScrollState(true)
                        }
                    }

                }
            }, 1000,200)

        }

    }

    private fun cancelTask() {
        if (time != null) {
            time?.cancel();
            time = null;
        }
    }


    public interface ScrollStateCallback {
        public fun onScrollState(flying: Boolean)
    }

}

 动画:

动画是根据滑动回调进行执行,这里面要记住view的起始位置(x或者y)

class FlingerAnmationManager {

    companion object {

        val startMillTime: Long = 600

        fun startToLeft(image: View) {


            var with = image.measuredWidth

            val animator = ObjectAnimator()
            animator.setPropertyName("X");
            animator.setFloatValues(-(with * 0.5f))

            animator.setDuration(startMillTime)
            val action = AnimatorSet()
            action.play(animator)
            action.setTarget(image)

            action.start()

        }

        fun startToRight(image: View) {


            var with = image.measuredWidth

            val animator = ObjectAnimator()
            animator.setPropertyName("X");
            val disWidth = image.context.resources.displayMetrics.widthPixels
            animator.setFloatValues(disWidth - (with * 0.5f))

            animator.setDuration(startMillTime)
            val action = AnimatorSet()
            action.play(animator)
            action.setTarget(image)
            action.addListener(object : AnimatorListenerAdapter() {
                override fun onAnimationEnd(animation: Animator) {
                    super.onAnimationEnd(animation)


                }

                override fun onAnimationStart(animation: Animator) {
                    super.onAnimationStart(animation)

                }
            })
            action.start()

        }

        fun reBackLocation(image: View) {

            var mleft = if (image.tag != null) image.tag as Float else image.marginLeft
            val animator = ObjectAnimator()
            animator.setPropertyName("X");
            animator.setFloatValues(mleft?.toFloat())
            animator.setDuration(startMillTime)

            val action = AnimatorSet()
            action.play(animator)
            action.setTarget(image)


            action.start()
        }


    }
}

实战

第一步:

初始化滑动监听

            manager = CountFlinerStatusManager()
            manager.addScrollListener(object : ScrollStateCallback {
                override fun onScrollState(flying: Boolean) {
                    if (!isAdded) return
                    runOnUiThread {
                        if (flying) {
                           onChildTouch(MotionEvent.ACTION_MOVE)
                        } else {
                            onChildTouch(MotionEvent.ACTION_UP)
                        }
                    }
                }
            })

第二步:

监听view滑动

contentView.setOnScrollChangeListener(object : View.OnScrollChangeListener {
    override fun onScrollChange(
        v: View?,
        scrollX: Int,
        scrollY: Int,
        oldScrollX: Int,
        oldScrollY: Int
    ) {

        if (oldScrollY == 0 && contentRv.contentView.scrollState == 0)
            return
        manager.scroll(scrollY)
    }
})

第三步:

处理滑动事件,在处理滑动之前,一定先记下view的坐标,否则在执行动画会出错

        view.postDelayed(object : Runnable {
            override fun run() {
                view.tag = view.x
            }
        }, 500)

处理动画

var viewFling :Boolean=false
    @Synchronized
    fun onChildTouch(action: Int) {

        when (action) {
            MotionEvent.ACTION_MOVE -> {
                if (viewFling == false) {
                    viewFling = true
                    FlingerAnmationManager.startToRight(view)
                }
            }
            MotionEvent.ACTION_UP -> {
                if (viewFling) {
                    viewFling = false
                    FlingerAnmationManager.reBackLocation(view)
                }
            }
        }

    }

四、总结

通过以上分析加实战,我们已完成处理好了资源滑动监听+动画。

这里核心:自定义自己的滑动监听机制,这个实现了,基本已成功了一半,剩下的就是动画的调试。

动画一定要先记住view的默认坐标,否则你讲无法恢复到起始位置。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/502561.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HarmonyOS版的“抖音”长啥样?有图有真相

“鸿蒙系统实战短视频App 从0到1掌握HarmonyOS”系列课程是面向HarmonyOS实战的视频教程,该课程会通过构建一个真实的短视频App来向读者展示HarmonyOS的全过程。 本节将演示基于HarmonyOS短视频App的核心功能。通过了解该App的功能,也能初步对本课程的内…

C++——类和对象(4)

作者&#xff1a;几冬雪来 时间&#xff1a;2023年5月8日 内容&#xff1a;C类和对象内容讲解 目录 前言&#xff1a; 1.操作符重载&#xff08;续&#xff09;&#xff1a; 前置和后置&#xff1a; 日期减日期&#xff1a; <<操作符&#xff1a; 结尾&#xff…

顶级白帽黑客必备的十大黑客技术

1.熟悉Linux系统和命令行操作&#xff1a; Linux是黑客的基石&#xff0c;几乎所有黑客工具和技术都是在Linux平台上运行的&#xff0c;熟悉Linux系统和命令行操作是必须的。 2.掌握网络协议和TCP/IP模型&#xff1a; 了解TCP/IP模型、网络协议和通信流程是黑客攻击的基础&a…

Python-exe调用-控制台命令行执行-PyCharm刷新文件夹

文章目录 1.控制台命令行执行1.1.os.system()1.2.subprocess.getstatusoutput()1.3.os.popen() 2.PyCharm刷新文件夹3.作者答疑 1.控制台命令行执行 主要三种方式实现。 1.1.os.system() 它会保存可执行程序中的打印值和主函数的返回值&#xff0c;且会将执行过程中要打印的…

Diesel 基础

Diesel 2.0.4 官网 github API Documentation 一个安全的&#xff0c;可扩展的ORM和Rust查询构建器 Diesel去掉了数据库交互的样板&#xff0c;在不牺牲性能的情况下消除了运行时错误。它充分利用了Rust的类型系统来创建一个“感觉像Rust”的低开销查询构建器。 支持数据库…

操作系统基础知识介绍之可靠性与可用性(包含MTTF、MRBF、MTTR等)

计算机是在不同的抽象层上设计和构建的。 我们可以通过计算机递归地下降&#xff0c;看到组件将自身放大为完整的子系统&#xff0c;直到我们遇到单个晶体管。 尽管有些故障很普遍&#xff0c;例如断电&#xff0c;但许多故障仅限于模块中的单个组件。 因此&#xff0c;一个模块…

Python每日一练:小艺的口红(暴力、二分、图论三种方法)代写匿名信

文章目录 前言0、题目一、暴力查找二、二分查找三、有序二叉树总结&#xff08;代写匿名信&#xff09; 前言 很明显小艺的口红问题是考的是查找算法&#xff0c;对于这种一次性查找&#xff0c;直接暴力就行了&#xff0c;当然咱是为了学习&#xff0c;所以用来练练各种查找&…

【Linux】基础IO_文件系统

环境&#xff1a;centos7.6&#xff0c;腾讯云服务器Linux文章都放在了专栏&#xff1a;【Linux】欢迎支持订阅 相关文章推荐&#xff1a; 【Linux】冯.诺依曼体系结构与操作系统 【C/进阶】如何对文件进行读写&#xff08;含二进制&#xff09;操作&#xff1f; 【Linux】基础…

【9种】ElasticSearch分词器详解,一文get!!!| 博学谷狂野架构师

ElasticSearch 分词器 作者: 博学谷狂野架构师GitHub&#xff1a;GitHub地址 &#xff08;有我精心准备的130本电子书PDF&#xff09; 只分享干货、不吹水&#xff0c;让我们一起加油&#xff01;&#x1f604; 概述 分词器的主要作用将用户输入的一段文本&#xff0c;按照一定…

二十一、线索转换1:点击转换按钮加载信息、搜索市场活动

功能需求 *在线索转换页面,展示:fullName,appellation,company,owner 流程图 代码实现 1.ClueMapper /*** 通过id查询线索详情* param id 线索id* return 对应id的线索*/Clue selectClueForDetailById(String id); ClueMapper.xml <select id"selectClueForDetailByI…

考研数学武忠祥 高等数学0基础课笔记

函数和映射 常见的函数 取整函数的基本性质 函数的有界性 例题 sinx 是从-1到1的&#xff0c;但是x是无界的 遇到这种带sin的&#xff0c;就要试着取特殊值&#xff0c;让它为1或者为0 函数的单调性 函数的奇偶性 函数的周期性 举例 数学中Q表示有理数集&#xff0c;下面…

Docker服务编排(Docker Compose) :部署上线nginx+springboot项目

Docker服务编排(Docker Compose) 微服务应用一般包含若干个微服务每个微服务一般会部署多个实例&#xff0c;如果每个微服务需要手动启停 维护工作量大 从Dockerfile build image 或者去dockerhub拉去image 创建多个容器 管理容器 Docker Compose 一个编排多容器分布式…

设计原则之【接口隔离原则】

文章目录 一、什么是接口隔离原则二、实例三、总结接口隔离原则与单一职责原则的区别 一、什么是接口隔离原则 接口隔离原则&#xff08;Interface Segregation Principle, ISP&#xff09;是指用多个专门的接口&#xff0c;而不使用单一的总接口&#xff0c;客户端不应该依赖…

自学Java多久可以就业?Java这样自学实习都能过万!

昨天有00后学妹私信小源&#xff0c;她在学校已经学过java、C等相关课程&#xff0c;未来想走计算机的方向&#xff0c;问我建议还要学习什么语言&#xff0c;是否需要继续学Java?今天好程序员简单介绍下Java必学的技术&#xff01;想自学Java的真的可以试一试&#xff01; 一…

哈希数据结构的概念、实现和应用

一、认识哈希表 1.unordered_set和unordered_map STL实现了两个数据结构unordered_map和unordered_set顾名思义&#xff0c;因为底层的实现方式不同&#xff0c;它们成为了无序的map和set&#xff0c;但是它们的使用与普通的map和set是一样的。 我们可以通过代码测试两种数据…

【力扣--622】设计循环队列

&#x1f58a;作者 : D. Star. &#x1f4d8;专栏 : 数据结构 &#x1f606;今日分享 : 丢脸其实并没有那么可怕&#xff0c;我们可以从另一个角度来想&#xff1a;别人能够记住我了&#xff0c;而且过了还有多少人能记得我呢&#xff1f;虽然这种出场不太优雅&#x1f606; 设…

python制作散点动图

目录 示例1&#xff1a;简单的散点图示例2&#xff1a;添加颜色和大小示例3&#xff1a;实时更新动图完整代码 本教程将介绍如何使用Python制作散点动图。我们将通过三个示例代码&#xff0c;从易到难&#xff0c;逐步说明如何使用Python绘制出散点动图。 示例1&#xff1a;简单…

图书馆客流人数统计分析系统方案

智慧客流人数统计分析系统可以帮助图书馆管理者更好地管理人群流量。系统能够自动统计区域内的人流量高峰期&#xff0c;并通过数据分析提供更加合理的管控&#xff0c;从而提区域内人群流动性&#xff0c;避免拥堵的情况。 AI客流视觉监控 客流量管控分析系统意义 讯鹏客流量管…

雪花算法生成ID

1.简介 SnowFlake 中文意思为雪花&#xff0c;故称为雪花算法。最早是 Twitter 公司在其内部用于分布式环境下生成唯一 ID。在2014年开源 scala 语言版本。 雪花算法的原理就是生成一个的 64 位比特位的 long 类型的唯一 id。 最高 1 位固定值 0&#xff0c;因为生成的 id 是…

Python的HTTP库及示例

13.3 HTTP库 HTTP&#xff08;Hyper Text Transfer Protocol&#xff09;是一个客户端和服务器端请求和应答的标准。客户端是终端用户&#xff0c;服务器端是网站。客户端发起一个到服务器上指定端口的HTTP请求&#xff0c;服务器向客户端发回一个状态行和响应的消息。 可以…