【Android】使用SeekBar控制数据的滚动
项目需求
有一个文本数据比较长,需要在文本右侧加一个SeekBar,然后根据SeekBar的上下滚动来控制文本的滚动。
项目实现
我们使用TextView来显示文本,但是文本比较长的话,需要在TextView外面套一个ScrollView,但是我们现在这个文本是上下滚动的,很巧不巧的是我们的文本在一个上下滚动的Recyclerview的item里面,这下就很搞了,因为两个都是上下滚动的,我们需要做一个处理。
首先,自定义一个ScrollView
public class NonScrollableScrollView extends ScrollView {public NonScrollableScrollView(Context context) {super(context);}public NonScrollableScrollView(Context context, AttributeSet attrs) {super(context, attrs);}public NonScrollableScrollView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overridepublic boolean onTouchEvent(MotionEvent ev) {return false;}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {return false;}
}
重写其触摸事件方法使其不响应触摸事件。所有这样的话我们的TextView就不能通过自己滚动了,然后我们通过这个SeekBar来控制TextView的滚动
接下来是对SeekBar的修改,以下部分内容来自知乎
https://zhuanlan.zhihu.com/p/622534050
@SuppressLint("AppCompatCustomView")
public class VerticalSeekBar extends SeekBar {private boolean isTopToBottom = false;//显示进度方向是否从上到下,默认false(从下到上)public VerticalSeekBar(Context context) {super(context);}public VerticalSeekBar(Context context, AttributeSet attrs) {super(context, attrs);TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.VerticalSeekBar, 0, 0);try {isTopToBottom = ta.getBoolean(R.styleable.VerticalSeekBar_isTopToBottom, false);} finally {ta.recycle();}}public VerticalSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}public void setOnSeekBarChangeListener(OnSeekBarChangeListener l) {mOnSeekBarChangeListener = l;}void onStartTrackingTouch() {if (mOnSeekBarChangeListener != null) {mOnSeekBarChangeListener.onStartTrackingTouch(this);}}void onStopTrackingTouch() {if (mOnSeekBarChangeListener != null) {mOnSeekBarChangeListener.onStopTrackingTouch(this);}}protected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(h, w, oldh, oldw);}@Overridepublic synchronized void setProgress(int progress) {super.setProgress(progress);onSizeChanged(getWidth(), getHeight(), 0, 0);}@Overrideprotected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(heightMeasureSpec, widthMeasureSpec);setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());}protected void onDraw(Canvas c) {if (isTopToBottom) {//显示进度方向 从上到下c.rotate(90);c.translate(0, -getWidth());} else {//显示进度方向 从下到上c.rotate(-90);c.translate(-getHeight(), 0);}super.onDraw(c);}@Overridepublic boolean onTouchEvent(MotionEvent event) {if (!isEnabled()) {return false;}switch (event.getAction()) {case MotionEvent.ACTION_DOWN:onStartTrackingTouch();trackTouchEvent(event);break;case MotionEvent.ACTION_MOVE:trackTouchEvent(event);attemptClaimDrag();break;case MotionEvent.ACTION_UP:trackTouchEvent(event);onStopTrackingTouch();break;case MotionEvent.ACTION_CANCEL:onStopTrackingTouch();break;}return true;
// getParent().requestDisallowInterceptTouchEvent(true);
// return super.onTouchEvent(event);}private void trackTouchEvent(MotionEvent event) {//关键更改2int progress = getMax() - (int) (getMax() * event.getY() / getHeight());//触摸进度方向 从下到上if (isTopToBottom) {progress = (int) (getMax() * event.getY() / getHeight());//触摸进度方向 从上到下}setProgress(progress);if (mOnSeekBarChangeListener != null) {mOnSeekBarChangeListener.onProgressChanged(this, progress);}}private void attemptClaimDrag() {if (getParent() != null) {getParent().requestDisallowInterceptTouchEvent(true);}}public boolean dispatchKeyEvent(KeyEvent event) {if (event.getAction() == KeyEvent.ACTION_DOWN) {KeyEvent newEvent = null;switch (event.getKeyCode()) {case KeyEvent.KEYCODE_DPAD_UP:newEvent = new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_DPAD_RIGHT);break;case KeyEvent.KEYCODE_DPAD_DOWN:newEvent = new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_DPAD_LEFT);break;case KeyEvent.KEYCODE_DPAD_LEFT:newEvent = new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_DPAD_DOWN);break;case KeyEvent.KEYCODE_DPAD_RIGHT:newEvent = new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_DPAD_UP);break;default:newEvent = new KeyEvent(KeyEvent.ACTION_DOWN,event.getKeyCode());break;}KeyEvent.DispatcherState dispatcherState = new KeyEvent.DispatcherState();dispatcherState.isTracking(event);return newEvent.dispatch(this, dispatcherState, event);}return false;}/*** 设置显示进度方向** @param isTopToBottom true 方向从上到下*/public void setTopToBottom(boolean isTopToBottom) {this.isTopToBottom = isTopToBottom;}private OnSeekBarChangeListener mOnSeekBarChangeListener;public interface OnSeekBarChangeListener {void onProgressChanged(VerticalSeekBar VerticalSeekBar, int progress);void onStartTrackingTouch(VerticalSeekBar VerticalSeekBar);void onStopTrackingTouch(VerticalSeekBar VerticalSeekBar);}
}
需要在attrs文件里面添加 (需要注意,因为在知乎上面没有这个东西)
<declare-styleable name="VerticalSeekBar"><attr name="isTopToBottom" format="boolean" /></declare-styleable>
设置 progress_vertical_drawable2
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"><item android:id="@android:id/background"><shape><corners android:radius="5dp" /><solid android:color="#D9EFFF" /></shape></item><item android:id="@android:id/progress"><scale android:scaleWidth="100%"><shape><corners android:radius="5dp" /><solid android:color="#5EB2FF" /></shape></scale></item><item android:id="@android:id/secondaryProgress"><scale android:scaleWidth="100%"><shape><corners android:radius="5dp" /><solid android:color="#5EB2FF" /></shape></scale></item>
</layer-list>
设置ic_thumb
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"><itemandroid:width="@dimen/dp_20"android:height="@dimen/dp_20"><shape android:shape="oval"><gradientandroid:angle="180"android:endColor="#1C000000"android:startColor="#1Cffffff" /></shape></item><itemandroid:bottom="1dp"android:left="1dp"android:right="1dp"android:top="1dp"><shape android:shape="oval"><solid android:color="#5EB2FF" /><strokeandroid:width="6dp"android:color="#FFFFFF" /></shape></item>
</layer-list>
设置Style
<!--自定义SeekBar样式--><style name="SeekbarStyle"><item name="android:indeterminateDrawable"><!--未知资源时显示-->@android:drawable/progress_indeterminate_horizontal</item><item name="android:progressDrawable">@drawable/progress_vertical_drawable2</item><item name="android:max">100</item><item name="android:progress">0</item><item name="android:maxHeight">@dimen/dp_60</item>
<!-- <item name="android:minHeight">@dimen/dp_10</item>--><item name="android:thumb">@drawable/ic_thumb</item>
<!-- <item name="android:thumbOffset">@dimen/dp_20</item>--></style>
然后就可以在xml布局中使用了
<com.complex.app.view.VerticalSeekBarandroid:id="@+id/seekBar_Text"style="@style/SeekbarStyle"android:layout_width="wrap_content"android:layout_height="@dimen/dp_60"android:background="@android:color/transparent"android:splitTrack="false"app:isTopToBottom="true" />
android:splitTrack="false"是为了让这个滑块周围的背景变的透明,不然就只能是一个正方形的滑块图案了
然后我们在RecyclerView的Adapter里面进行设置
protected void convert(BaseViewHolder helper, ElectronicFencePoint item) {NonScrollableScrollView scrollView = helper.getView(R.id.ns_scroll);VerticalSeekBar seekBar = helper.getView(R.id.seekBar_Text);scrollView.post(() -> {int maxScroll = scrollView.getChildAt(0).getHeight() - scrollView.getHeight();if (maxScroll <= 0) {//这里我的逻辑是当TextView的文本显示内容不多不需要滑动的时候,设置滑块滑动到底部显示seekBar.setProgress(seekBar.getMax());} else {//当TextView的文本很多,需要滑动的时候,将滑块放在顶部seekBar.setProgress(0);seekBar.setMax(maxScroll);}});seekBar.setOnSeekBarChangeListener(new VerticalSeekBar.OnSeekBarChangeListener() {@Overridepublic void onProgressChanged(VerticalSeekBar VerticalSeekBar, int progress) {scrollView.scrollTo(0, progress);}@Overridepublic void onStartTrackingTouch(VerticalSeekBar VerticalSeekBar) {}@Overridepublic void onStopTrackingTouch(VerticalSeekBar VerticalSeekBar) {}});scrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {@Overridepublic void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {seekBar.setProgress(scrollY);}});
}
补充:
开始滑动前:
开始滑动后
这个只需要修改一下样式就好了
ic_thumb
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"><itemandroid:width="@dimen/dp_15"android:height="@dimen/dp_15"><shape android:shape="oval"><gradientandroid:endColor="#1C000000"android:startColor="#1Cffffff" /></shape></item><itemandroid:bottom="1dp"android:left="1dp"android:right="1dp"android:top="1dp"><shape android:shape="oval"><solid android:color="#5EB2FF" /><strokeandroid:width="2dp"android:color="#FFFFFF" /></shape></item>
</layer-list>
progress_vertical_drawable2
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"><!--设置滑轨颜色:滑过部分和未滑过部分--><!--未滑过部分滑轨颜色--><itemandroid:id="@android:id/background"android:height="4dp"android:gravity="center"><shape><corners android:radius="67dp"/><solid android:color="#4d000000"/></shape></item><!--滑过部分滑轨颜色--><itemandroid:id="@android:id/progress"android:height="6dp"android:gravity="center"><clip><shape><corners android:radius="67dp"/><solid android:color="#2196F3"/></shape></clip></item>
</layer-list>
SeekbarStyle
<!--自定义SeekBar样式--><style name="SeekbarStyle" parent="Widget.AppCompat.SeekBar"><item name="android:progressDrawable">@drawable/progress_vertical_drawable2</item><item name="android:thumb">@drawable/ic_thumb</item></style>
xml应用
<com.southgnss.digitalconstruction.view.VerticalSeekBarandroid:id="@+id/seekBar_Text"style="@style/SeekbarStyle"android:layout_width="@dimen/dp_20"android:layout_height="@dimen/dp_60"android:background="@null"android:splitTrack="false"app:isTopToBottom="true" /></LinearLayout>
相关文章:

【Android】使用SeekBar控制数据的滚动
项目需求 有一个文本数据比较长,需要在文本右侧加一个SeekBar,然后根据SeekBar的上下滚动来控制文本的滚动。 项目实现 我们使用TextView来显示文本,但是文本比较长的话,需要在TextView外面套一个ScrollView,但是我…...

新能源汽车的能源动脉:中国星坤汽车电缆在新能源汽车电气化中的应用!
随着新能源汽车行业的蓬勃发展,汽车电缆组件作为汽车电气系统的核心组成部分,其重要性日益凸显。中国星坤汽车电缆组件以其卓越的性能和创新技术,为汽车的电能传输、信号传递和控制提供了坚实的保障。本文将深入解析星坤汽车电缆组件的特性、…...
AVL许可证查询系统
在数字化时代,软件已经成为企业运营的核心组成部分。然而,随着软件应用的不断增加,许可证管理也变得越来越复杂。AVL许可证查询系统作为企业软件资产管理的重要工具,能够帮助企业实现对软件许可证的全面掌控。本文将深入探讨AVL许…...

四个步骤,帮你成为价值导向型项目经理
在企业数字化转型的浪潮下,项目管理的方向逐渐从任务导向转变为以价值交付为导向。在快速变化的市场环境中,仅仅关注项目任务的完成已不足以确保项目的成功,需要更加注重项目的最终成果和价值,确保项目能够为组织带来实际的价值和…...
Python3 使用 clickhouse-connect 操作 clickhouse
版本: Python 3.7 x86 clickhouse 24.6.1.3573 clickhouse-connect 0.6.22 代码一: # pip install clickhouse-connectimport clickhouse_connect# 准备参数 host "192.168.1.112" port 8123 username "default" passw…...
Python脚手架系列-DrissionPage
记录DrissionPage模块使用中的一些常常复用的代码,持续更新… 接管谷歌浏览器 from DrissionPage import ChromiumPage, ChromiumOptionsco ChromiumOptions().set_local_port(4249) driver ChromiumPage(addr_or_optsco)创建driver,如果浏览器已开启优先接管&am…...
Java中如何调用mysql中函数
在Java中调用MySQL中的函数(无论是存储函数还是自定义函数),通常是通过JDBC(Java Database Connectivity)来完成的。以下是一个简单的步骤说明和示例代码,展示如何在Java中调用MySQL中的函数。 步骤 添加…...

Huggingface-cli 登录最新版(2024)
安装Huggingface-cli pip install -U "huggingface_hub[cli]"设置好git的邮箱和用户名和huggingface的github账号一致 git config --global user.mail xxx git config --global user.name xxx登录 复制token,划红线的地方,在命令行中点击右…...
Java学习 - Docker管理和容器命令 实例
docker管理 查看docker版本,检测是否可用 sudo docker version查看docker 系统信息 sudo docker infodocker容器命令 容器状态 容器标识 容器长uuid容器短uuid容器名字 查看容器状态 sudo docker status [容器标识1] [容器标识2] [容器标识n]深入查看容器信息 su…...
下载工程resources目录下的模板excel文件
一、添加依赖 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.1.0</version> </dependency> 二、编写接口 GetMapping("/downloadTemplate")public void downlo…...

音频基础知识和音频指标
音频基础知识 声音 声音(sound)是由物体振动产生的声波。物体在一秒钟之内振动的次数叫做频率,单位是赫兹,字母Hz。人耳可以识别的声音频率在 20 Hz~20000 Hz之间; 声音三要素: 响度 响度,…...

使用Vue CLI在其他磁盘创建项目出现错误及解决
Vue CLI是Vue.js官方推出的脚手架工具,可以帮我们快速的创建Vue项目框架。 我们创建Vue项目时一般默认都是在C盘,但由于某些因素我们需要在其他磁盘上创建Vue项目。 通过“winr”打开终端时默认位置都是C盘,但是Vue CLI不接受绝对路径作为参…...
关于lamda表达式的使用
Lambda表达式是一种匿名函数,即没有函数名的函数,它可以以更简洁、更灵活的方式编写代码。以下是Lambda表达式的常用方式: 无参数,无返回值: 如果抽象方法不带参数且不返回值,可以使用空括号和主体编写Lam…...
Android替换默认的按键音
替换audio_assets.xml文件 此文件在AudioService.java被调用 <!--文件位置 /frameworks/base/core/res/res/xml/--> <audio_assets version"1.0"><group name"touch_sounds"><asset id"FX_KEY_CLICK" file"Effect…...

Windows 服务器Nginx 下载、部署、配置流程(图文教程)
不定期更新 目录 一、下载Nginx安装包 二、上传安装包 三、启动Nginx 四、Nginx常用命令 五、Nginx(最小)配置详解 六、Nginx(基础)配置详解 七、反向代理 八、负载均衡 九、动静分离 十、报错 一、下载Nginx安装包 四…...

基于Redis实现共享session登录
搭配食用:Redis(基础篇)-CSDN博客 项目实现前的 Mysql中的表: 表说明tb_user用户表tb_user_info用户详情表tb_shop商户信息表tb_shop_type商户类型表tb_blog用户日记表(达人探店日记)tb_follow用户关注表tb_voucher优…...
shell函数的定义
shell函数的定义 定义:将命令序列按照格式写在一起.格式指的是函数的固定格式 作用:方便重复使用,还可以做成函数库,集中在一起,随时可以传参调用,大的工程分割成小的模块,提高代码的可读性. 函数的格式 vim hanshu1.shfunction shopping {命令序列}shopping () {命令…...

vue部署宝塔nginx配置(获取用户ip地址、反代理访问api接口、websocket转发)
以下配置为我自己的需求,因人而异,如果只是单纯的前端非交互页面,可以不用修改配置。 代码及注释,如下: #解决vue-router设置mode为history,去掉路由地址上的/#/后nginx显示404的问题location / {proxy_htt…...

Jenkins教程-3-github自动化测试任务构建
上一小节我们学习了Jenkins在windows和mac系统上安装搭建环境的方法,本小节我们讲解一下Jenkins构建github自动化测试任务的方法。 接下来我们以windows系统为例,讲解一下构建实际自动化测试任务的具体步骤。 安装git和github插件 点击进入Jenkins插件…...

0元体验苹果macOS系统,最简单的虚拟机部署macOS教程
前言 最近发现小伙伴热衷于在VMware上安装体验macOS系统,所以就有了今天的帖子。 正文开始 首先,鉴于小伙伴们热衷macOS,所以小白搜罗了一圈macOS系统,并开启了分享通道。 本次更新的系统版本是: macOS 10.13.6 ma…...

CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

FFmpeg:Windows系统小白安装及其使用
一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...
华为OD最新机试真题-数组组成的最小数字-OD统一考试(B卷)
题目描述 给定一个整型数组,请从该数组中选择3个元素 组成最小数字并输出 (如果数组长度小于3,则选择数组中所有元素来组成最小数字)。 输入描述 行用半角逗号分割的字符串记录的整型数组,0<数组长度<= 100,0<整数的取值范围<= 10000。 输出描述 由3个元素组成…...