Android scrollTo、scrollBy、以及scroller详解 自定义ViewPager

news2024/12/22 20:20:27

Scroller

在这里插入图片描述

VelocityTracker

VelocityTracker 是一个速度跟踪器,通过用户操作时(通常在 View 的 onTouchEvent 方法中)传进去一系列的 Event,该类就可以计算出用户手指滑动的速度,开发者可以方便地获取这些参数去做其他事情。或者手指滑动超过一定速度并松手,就触发翻页。

CustomViewPager

package com.flannery.androidtools.widgets;

import android.content.Context;
import android.graphics.Color;
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.LinearLayout;
import android.widget.Scroller;

/**
 * VelocityTracker is a concept commonly used in computer graphics, physics simulations, and user interface frameworks to calculate the velocity of an object or pointer based on its position over time. It's particularly useful for creating responsive and realistic interactions in applications like games or touch-based user interfaces.
 * In the context of Android development, VelocityTracker refers to a class provided by the Android framework. It's used to track the velocity of motion events, such as touch events, on the screen. This can be useful for implementing various gestures and animations that require knowledge of how quickly a user is moving their finger across the screen.
 * Here's a basic overview of how VelocityTracker works in Android:
 * Initialization: To use VelocityTracker, you need to create an instance of it and associate it with a specific motion event, typically the ACTION_MOVE events in the case of touch gestures.
 * Tracking: As the user interacts with the screen, you feed the VelocityTracker instance with the motion events, which contain the current position of the pointer. The VelocityTracker class calculates the velocity based on the change in position over time.
 * Velocity Retrieval: After you've collected enough motion events, you can retrieve the calculated velocity using the computeCurrentVelocity(int units) method. The units parameter allows you to specify the desired units for the velocity, such as pixels per second.
 *
 * https://www.nhooo.com/note/qadf7m.html
 */
public class CustomViewPager extends ViewGroup {
    private static final String TAG = CustomViewPager.class.getSimpleName();
    private int screenWidth;
    private int screenHeight;
    private int lastMoveX = 0;
    private Scroller scroller; // 滚动计算器
    private VelocityTracker velocityTracker; // 速度跟踪器
    private int MAX_VELOCITY = 600;
    private int curScreen = 0;

    public CustomViewPager(Context context) {
        super(context);
        init(context);
    }

    public CustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public CustomViewPager(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        scroller = new Scroller(context); // 初始化滚动计算器
        // 添加三个View
        LinearLayout layout1 = new LinearLayout(context);
        layout1.setBackgroundColor(Color.RED);
        addView(layout1);
        LinearLayout layout2 = new LinearLayout(context);
        layout2.setBackgroundColor(Color.GREEN);
        addView(layout2);
        LinearLayout layout3 = new LinearLayout(context);
        layout3.setBackgroundColor(Color.BLUE);
        addView(layout3);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i(TAG, "onTouchEvent: onTouchEvent=" + event);
        if (velocityTracker == null) {
            velocityTracker = VelocityTracker.obtain(); // 初始化滚动速度跟踪器
        }
        velocityTracker.addMovement(event);
        int x = (int) event.getX();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastMoveX = x; // 记录下按下的点
                break;
            case MotionEvent.ACTION_MOVE:
                int dis = lastMoveX - x; // 移动的偏移量
                Log.i(TAG, "onTouchEvent: dis=" + dis);
                scrollBy(dis, 0); // 位置滚动
                lastMoveX = x;
                break;
            case MotionEvent.ACTION_UP:
                velocityTracker.computeCurrentVelocity(1000); // 计算需要的位置
                int velocityX = (int) velocityTracker.getXVelocity(); // X轴上的速度
                if (velocityX > MAX_VELOCITY && curScreen > 0) {
                    jump2Screen(curScreen - 1);
                } else if (velocityX < -MAX_VELOCITY && curScreen < getChildCount() - 1) {
                    jump2Screen(curScreen + 1);
                } else {
                    int screen = (getScrollX() + screenWidth / 2) / screenWidth;
                    jump2Screen(screen);
                }
                if (velocityTracker != null) {
                    velocityTracker.recycle();
                    velocityTracker = null;
                }
                break;
        }
        return true;
    }

    public void jump2Screen(int screen) {
        curScreen = screen;
        if (curScreen < 0) {
            curScreen = 0;
        }
        if (curScreen > getChildCount() - 1) {
            curScreen = getChildCount() - 1;
        }
        int dis = curScreen * screenWidth - getScrollX();
        scroller.startScroll(getScrollX(), 0, dis, 0); // 开始滚动
        invalidate();
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        if (scroller.computeScrollOffset()) { // 是否处于偏移量的位置
            scrollTo(scroller.getCurrX(), 0); // 滚动到指定的位置
            postInvalidate(); // 继续滚动
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        screenWidth = MeasureSpec.getSize(widthMeasureSpec);
        screenHeight = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(screenWidth, screenHeight);
        // 给子View设置大小
        for (int i = 0; i < getChildCount(); i++) {
            View view = getChildAt(i);
            view.measure(screenWidth, screenHeight);
        }
    }


    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int leftWidth = 0;
        // 给子View排班
        for (int i = 0; i < getChildCount(); i++) {
            View view = getChildAt(i);
            view.layout(leftWidth, 0, leftWidth + screenWidth, screenHeight);
            leftWidth = leftWidth + screenWidth;
        }
    }
}

资料

Android scrollTo、scrollBy、以及scroller详解
Android Scroller详解
Android自定义ViewPager实例
Android View 的滚动原理和 Scroller、VelocityTracker 类的使用

在这里插入图片描述

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

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

相关文章

研磨设计模式day10中介者模式

目录 场景 思考 解决思路 模式讲解 调用示意图 中介者模式的优缺点 中介者模式的本质 何时选用 场景 如果没有主板&#xff0c;电脑各个配件怎么交互呢&#xff1f; 有些配件接口不同&#xff0c;必须把数据接口进行转换才能匹配上,无敌复杂。 有了主板之后就是下面这…

人工智能技术的主要类别

人工智能技术主要类别&#xff1a; 机器学习&#xff1a; 监督学习&#xff1a;使用带有标签的训练数据来训练模型&#xff0c;使其能够预测未知数据的标签。常见任务包括分类和回归。无监督学习&#xff1a;使用无标签的训练数据&#xff0c;模型通过发现数据中的模式、聚类或…

在idea上使用git的reset操作后,出现的四个选项Soft、Mixed、Hard、Keep选择说明

出现场景 选择已经commit的版本,点击Reset Current Branch to Here 然后便会出现下述四个选项 下面便对这个四个选项进行总结说明 原理 git revert是用于“反做”某一个版本,以达到撤销该版本的修改的目的 Soft Soft选项:在选择的回退点之后的所有更改将会保留并被gi…

预测下一波物联网网络安全挑战

本文讨论从孤立的物联网设置过渡到互连环境的复杂性&#xff0c;不断扩大的攻击面以及这种演变带来的微妙复杂性。 深入探讨标准化的紧迫性、级联故障的威胁以及利益相关者之间模糊的责任界限。 鉴于从孤立的物联网设备到互连的物联网环境的转变&#xff0c;这给网络安全带来…

研磨设计模式day12迭代器模式

目录 场景 解决方案 解决思路 代码示例 代码改造 Java实现迭代器 迭代器模式的优点 思考 何时选用 场景 大公司收购了一个小公司&#xff0c;大公司的工资系统采用List来记录工资列表&#xff0c;而小公司是采用数组&#xff0c;老板希望通过决策辅助系统来统一查看…

Axure RP

Axure RP 简介下载安装汉化注册 简介 Axure RP&#xff08;Rapid Prototyping&#xff09;是一款交互式原型设计工具&#xff0c;用于创建高保真的交互式界面原型和线框图。它主要用于用户体验&#xff08;UX&#xff09;和用户界面&#xff08;UI&#xff09;设计&#xff0c…

4.RabbitMQ高级特性 幂等 可靠消息 等等

一、如何保证生产者生产消息100%的投递成功 保障消息的成功发出保障MQ节点的成功接收发送端收到MQ节点&#xff08;Broker&#xff09;确认应答完善的消息进行补偿机制 1. 理解Confirm确认消息机制 消息的确认&#xff0c;是指生产者投递消息后&#xff0c;如果Broker收到消…

【C语言进阶(7)】内存函数 —— 使用方法 + 模拟实现

文章目录 前言Ⅰ 内存函数⒈memcpy⒉memmove⒊memcmp⒋memset Ⅱ 模拟实现⒈模拟实现 memcpy⒉模拟实现 memmove⒊模拟实现 memcmp⒋模拟实现 memset 前言 内存操作函数的优势 字符串函数只能操作字符串的内容&#xff0c;局限性很大。而内存函数可以操作任意类型的数据&…

Kali 安装浩劫(Havoc Command and Control Framework)

拉取 github 上的项目到本地进入 Havoc 目录 git clone https://github.com/HavocFramework/Havoc.git cd Havoc下载基于 Kali 的一系列软件 sudo apt install -y git build-essential apt-utils cmake libfontconfig1 libglu1-mesa-dev libgtest-dev libspdlog-dev libboost…

改进YOLO系列:7.添加CA注意力机制

添加CA注意力机制 1. CA注意力机制论文2. CA注意力机制原理3. CA注意力机制的配置3.1common.py配置3.2yolo.py配置3.3yaml文件配置1. CA注意力机制论文 论文题目:Coordinate Attention for Efficient Mobile Network Design 论文链接:Coordinate Attention for Effi…

400电话系统的数据分析和优化对企业的发展和增长有什么具体的好处?

对企业而言&#xff0c;通过400电话系统的数据分析和优化可以带来以下具体好处&#xff0c;促进企业的发展和增长&#xff1a; 优化客户满意度&#xff1a;通过数据分析和优化&#xff0c;企业可以更好地了解客户的需求和偏好&#xff0c;针对性地提供个性化的服务。这将提升客…

如何评估分类模型的好坏

如何评估分类模型的好坏 评估分类预测模型的质量&#xff0c;常用一个矩阵、三条曲线和六个指标。 一个矩阵&#xff1a;混淆矩阵&#xff1b;三条曲线&#xff1a;ROC曲线、PR曲线、KS曲线&#xff1b;六个指标&#xff1a;正确率Acc、查全率R、查准率P、F值、AUC、BEP值、KS…

「快学Docker」Docker容器安全性探析

「快学Docker」Docker容器安全性探析 引言容器安全性威胁Docker容器安全性目录容器镜像安全性主机与容器隔离访问控制运行时监控与防御网络安全性Docker容器安全性最佳实践 总结 引言 在当今快速发展的软件开发和部署领域&#xff0c;容器化技术已经成为一种不可或缺的工具。然…

Zotero文件同步方案:Zotero + Koofr + GooleDrive/OneDrive

Zotero文件同步方案&#xff1a;Zotero Koofr GooleDrive/OneDrive 背景知识ZoteroKoofrGoogleDrive/OneDrive配置步骤注意事项参考资料 觉得文章有收获&#xff0c;欢迎关注公众号鼓励一下作者呀~ 在学习的过程中&#xff0c;也搜集了一些量化、技术的视频及书籍资源&#x…

【业务功能篇83】微服务SpringCloud-ElasticSearch-Kibanan-docke安装-应用层实战

五、ElasticSearch应用 1.ES 的Java API两种方式 Elasticsearch 的API 分为 REST Client API&#xff08;http请求形式&#xff09;以及 transportClient API两种。相比来说transportClient API效率更高&#xff0c;transportClient 是通过Elasticsearch内部RPC的形式进行请求…

Win11安装VMware中的镜像的下载

首先&#xff0c;下载好VMware之后需要许可证&#xff0c;在VMware选择许可证填上即可&#xff08;可以解决一部分VMware创建虚拟机过程中出现的问题&#xff09;。 百度网盘自取&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/17gBySqoPi2HeGJJlalp-VQ 提取码&…

学信息系统项目管理师第4版系列01_导读

2023年对于信息系统项目管理师&#xff08;以下简称“高项”&#xff09;的考生来说真是命运多舛的一年&#xff0c;上半年改大纲换教材&#xff0c;下半年改机考换考法&#xff0c;真是一言难尽啊。 不过&#xff0c;“天要下雨&#xff0c;娘要嫁人”&#xff0c;该考试拿证…

Linux:Nginx服务与搭建

目录 一、Nginx概述 二、Nginx三大作用&#xff1a;反向代理、负载均衡、动静分离 三、Nginx和Apache 3.1Nginx和Apache的差异 3.2Nginx和Apache的优缺点比较 四、编译安装niginx 五、创建Nginx 自启动文件 六、Nginx的信号使用 6.1信号 七、升级 nginx1.18 nginx1.2…

java 里面 long 转换int内存分析

了解补码知识点 要将补码转换为十进制&#xff0c;需要确定补码的符号位。如果补码的符号位为1&#xff0c;则表示为负数&#xff0c;否则表示为正数。 假设我们有一个补码为1 0110 1011 1100 1101 1000 0011 1101 1100 0010 1101 1111 1101 1100 0001 1100 0011 0100 首先&a…

无涯教程-进程 - 组会话控制

在本章中&#xff0c;我们将熟悉进程组&#xff0c;会话和作业控制。 进程组(Process Groups ) - 进程组是一个或多个进程的集合&#xff0c;一个进程组由一个或多个共享相同进程组标识符(PGID)的进程组成。 会话(Sessions) - 它是各种进程组的集合。…