Android scroller学习总结

news/2025/1/19 8:42:18/

一、关键在于View的scrollTo scrollBy方法

scrollTo scrollBy  滑动的是view的内容,而不是view本身,这也是和动画的区别  
怎么滑动内容呢?通过滑动view的画布,然后重绘
mScrollX mScrollY分别代表画布相对初始位置滑动的距离(坐标系为视图经典坐标系,向下是y正,向右是x正),滑动时就相当于放胶片电影,画布是原始屏幕,可以进行投影,内容不动,画布往右mScrollX为正,往下mScrollY为正;当然也可以以view内容作为滑动的参考对象,画布不动,内容往左、上滑为正(因为scrollTo和scrollBy的参数正负和以view内容做参考对象一致,所以以view内容为参考对象比较容易记忆)

scrollTo(scrollX, scrollY):
scrollX、scrollY相对于初始位置,为正代表手指左滑、上滑,为负代表手指右滑、下滑

scrollBy里面调用的是scrollTo(mScrollX + x, mScrollY + y),注意mScrollX、mScrollY是会随着滑动不断变化的

Scroller滑动辅助类,用以实现滑动惯性效果和回弹效果,最终还是依靠scrollTo、scrollBy来完成的:

因此Scroller类的基本使用流程可以总结如下:
(1)首先通过Scroller类的startScroll()开始一个滑动动画控制,里面进行了一些轨迹参数的设置和计算,开始位置,滑动距离;
(2)在调用 startScroll()的后面调用invalidate();引起视图的重绘操作,从而触发ViewGroup中的computeScroll()被调用;
(3)在computeScroll()方法中,先调用Scroller类中的computeScrollOffset()方法,里面根据当前消耗时间进行轨迹坐标的计算,然后取得计算出的当前滑动的偏移坐标,调用View的scrollTo()方法进行滑动控制,最后也需要调用invalidate();进行重绘

此外,scroller还有一个fling方法,能够实现惯性滑动,具体用法参考下方代码:

package com.example.meettingactivityimport android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.VelocityTracker
import android.view.View
import android.view.ViewGroup
import android.widget.Scrollerclass CustomViewGroup : ViewGroup {var mView: View? = nullvar mX = 0f //每次滑动的横坐标位置var homePos = 0f //初始位置var lastPos = 0f //上次滑动的位置var dx = 0f //每次滑动后距离初始位置的距离private val scroller: Scrollerprivate var velocityTracker: VelocityTracker? = nullconstructor(context: Context) : this(context, null)constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)constructor(context: Context, attrs: AttributeSet?, defAttr: Int) : super(context,attrs,defAttr) {scroller = Scroller(context)}override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {Log.i("wjc", "mes childCount=$childCount")super.onMeasure(widthMeasureSpec, heightMeasureSpec)measureChildren(widthMeasureSpec, heightMeasureSpec)}override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {for (i in 0 until childCount) {mView = getChildAt(i)mView?.let {it.layout(i * it.measuredWidth, t, (i + 1) * it.measuredWidth, b)}}}/*** 一、使用scrollTo*/
//    override fun onTouchEvent(event: MotionEvent?): Boolean {
//        event?.let { event ->
//            mX = event.x
//            when (event.action) {
//                MotionEvent.ACTION_DOWN -> {
//                    //1.最终dx是起点-终点的值加上scrollX,所以这里直接加在起点处
//                    homePos = event.x + scrollX
//                }
//
//                MotionEvent.ACTION_MOVE -> {
//                    dx = homePos - mX
//                    scrollTo(dx.toInt(), scrollY)
//                }
//
//                else -> {}
//            }
//        }
//        //2.消费事件,不然无法获取滚动事件
//        return true
//    }/*** 二、使用scrollBy*/
//    override fun onTouchEvent(event: MotionEvent?): Boolean {
//        event?.let { event ->
//            mX = event.x
//            when (event.action) {
//                MotionEvent.ACTION_DOWN -> {
//                    lastPos = event.x
//                }
//
//                MotionEvent.ACTION_MOVE -> {
//                    //1.scrollBy里面调用的也是scrollTo(mScrollX + x, mScrollY + y),所以这里dx等于两次事件滑动的距离
//                    dx = lastPos - mX
//                    scrollBy(dx.toInt(), scrollY)
//                    lastPos = mX
//                }
//
//                else -> {}
//            }
//        }
//        //2.消费事件,不然无法获取滚动事件
//        return true
//    }/*** 三、使用Scroller*/override fun onTouchEvent(event: MotionEvent?): Boolean {event?.let { event ->mX = event.xif (velocityTracker == null) {velocityTracker = VelocityTracker.obtain()}velocityTracker!!.addMovement(event)when (event.action) {MotionEvent.ACTION_DOWN -> {lastPos = event.xif (!scroller.isFinished) {scroller.abortAnimation()}}MotionEvent.ACTION_MOVE -> {dx = lastPos - mXscroller.startScroll(scroller.finalX, scroller.finalY, dx.toInt(), 0)invalidate()lastPos = mX}MotionEvent.ACTION_UP -> {velocityTracker!!.computeCurrentVelocity(1000)val initialVelocity = velocityTracker!!.xVelocity.toInt()Log.i("wjc", "initialVelocity=$initialVelocity")scroller.fling(scroller.finalX,scroller.finalY,-initialVelocity,0,0,Int.MAX_VALUE,0,0)velocityTracker!!.recycle()velocityTracker = null}else -> {}}}//2.消费事件,不然无法获取滚动事件return true}/*** 该方法会在view.draw中调用,在这里继续使用scrollTo进行滑动*/override fun computeScroll() {super.computeScroll()if (scroller.computeScrollOffset()) {scrollTo(scroller.currX, scroller.currY)invalidate()}}}


http://www.ppmy.cn/news/164577.html

相关文章

技术分享-向电池巨头批量供货的芯驰-E3系列的实际用法案例

芯驰首席架构师孙鸣会上表示,仅单个800M的CPU内核,如果用来做BMS,可以同时精准地监控40~60个电芯的状态; 如果用来做电机控制,可以同时做4个电机的高精度的闭环控制,而如果用来做网关路由&#…

Lr性能测试查看服务器带宽,LR性能测试报告-WebGIS.docx

LR性能测试报告-WebGIS 结果报告WebGIS性能测试概述测试目的测试5分钟可以生成多少个专题产品工作流,建议使用多少进程运行。测试矢量底图、影像底图可以支持多少并发用户数(响应时间在5秒内)。建议使用多少进程运行以及并发人数。测试前台标绘站点与后台生成站点&a…

Office--CVE-2017-11882【远程代码执行】

Office远程代码执行漏洞现POC样本 最近这段时间CVE-2017-11882挺火的。关于这个漏洞可以看看这里:https://www.77169.com/html/186186.html 今天在twitter上看到有人共享了一个POC,https://twitter.com/gossithedog/status/932694287480913920,http://ow…

msf生成webshell_CVE-2017-11882漏洞复现结合MSF拿电脑shell

两个代码分别贴上 [Python] 纯文本查看 复制代码import argparse import sys RTF_HEADER R"""{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Calibri;}} {\*\generator Riched20 6.3.9600}\viewkind4\uc1 \pard\sa200\sl…

利用Office公式编辑器特殊处理逻辑的免杀技术分析(CVE-2017-11882)

利用Office公式编辑器特殊处理逻辑的免杀技术分析(CVE-2017-11882) 阅读量 44989 | 评论 3 分享到: 发布时间:2018-09-11 10:00:14 背景 2018年8月24日,360威胁情报中心捕获到一个专门为乌克兰语使用者设计的…

[转] 2018年最新桌面CPU性能排行天梯图(含至强处理器)

【FROM】 http://www.idn100.com/zuzhuangdiannaopeizhi-pc2849/ 排名 处理器 图例 分数 1 Intel Xeon Platinum 8173M @ 2.00GHz 28860 2 Intel Xeon Gold 6154 @ 3.00GHz 27789 3 Intel Core i9-7980XE @ 2.60GHz 27736 4 Intel…

计算机学生台式机推荐,开学啦 开学啦 热门学生电脑大推荐

【IT168 资讯】八月就要过去了,九月开学季正在向莘莘学子们招手。经过一个暑假的休整,现在又是学生回到课堂学习知识、开动脑筋的时候了。不过千万不要忘了,既要健康用脑,也要善用电脑。在教育信息化的今天,电脑早已变…

111.(cesium篇)cesium地球自转

听老人家说:多看美女会长寿 地图之家总目录(订阅之前建议先查看该博客) 文章末尾处提供保证可运行完整代码包,运行如有问题,可“私信”博主。 效果如下所示: 下面献上完整代码,代码重要位置会做相应解释 <html lang="en">