【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>

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

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

相关文章

利用K8S技术栈打造个人私有云

1.三个节点&#xff1a;master&#xff0c;slave&#xff0c;client 在Kubernetes集群中&#xff0c;三个节点的职责分别如下&#xff1a; Master节点&#xff1a; docker&#xff1a;用于运行Docker容器。 etcd&#xff1a;一个分布式键值存储系统&#xff0c;用于保存Kuberne…

42、基于神经网络的训练堆叠自编码器进行图像分类(matlab)

1、训练堆叠自编码器进行图像分类的原理及流程 基于神经网络的训练堆叠自编码器进行图像分类的原理和流程如下&#xff1a; 堆叠自编码器&#xff08;Stacked Autoencoder&#xff09;是一种无监督学习算法&#xff0c;由多个自编码器&#xff08;Autoencoder&#xff09;堆叠…

宝塔软件默认安装位置

自带的JDK /usr/local/btjdk/jdk8Tomcat 各个版本都在bttomcat这个文件夹下面&#xff0c;用版本区分。tomcat_bak8是备份文件 /usr/local/bttomcat/tomcat8nginx /www/server/nginxnginx配置文件存放目录 /www/server/panel/vhost/nginxredis /www/server/redismysql /…

nextjs(持续学习中)

return ( <p className{${lusitana.className} text-xl text-gray-800 md:text-3xl md:leading-normal}> Welcome to Acme. This is the example for the{’ } Next.js Learn Course , brought to you by Vercel. ); } 在顶级 /public 文件夹下提供静态资产 **默认 /…

央国企财务专家的“专家课”——中国总会计师协会联合实在智能举办RPA专项培训

近日&#xff0c;中国总会计师协会正式举办了为期五天的「财务数字化思维与实用IT技能提升」专项培训&#xff0c;吸引了来自中铁十五局集团有限公司、中国航空工业规划设计院、中核核电运行管理有限公司、中国北方车辆有限公司、一汽物流有限公司等国企、事业单位及民营企业共…

【权威出版/投稿优惠】2024年水利水电与能源环境科学国际会议(WRHEES 2024)

2024 International Conference on Water Resources, Hydropower, Energy and Environmental Science 2024年水利水电与能源环境科学国际会议 【会议信息】 会议简称&#xff1a;WRHEES 2024 大会时间&#xff1a;点击查看 截稿时间&#xff1a;点击查看 大会地点&#xff1a;…

【Linux】进程间通信3——system V共享内存

1.system V进程间通信 管道通信本质是基于文件的&#xff0c;也就是说操作系统并没有为此做过多的设计工作&#xff0c;而system V IPC是操作系统特地设计的一种通信方式。但是不管怎么样&#xff0c;它们的本质都是一样的&#xff0c;都是在想尽办法让不同的进程看到同一份由操…

压力应变桥信号变送光电隔离放大模块PCB焊接式 差分信号输入0-10mV/0-20mV/0-±10mV/0-±20mV转0-5V/0-10V/4-20mA

概述&#xff1a; IPO压力应变桥信号处理系列隔离放大器是一种将差分输入信号隔离放大、转换成按比例输出的直流信号混合集成厚模电路。产品广泛应用在电力、远程监控、仪器仪表、医疗设备、工业自控等行业。该模块内部嵌入了一个高效微功率的电源&#xff0c;向输入端和输出端…

【深度解析】1688货源拿货价比拼多多贵?为何商家仍选1688

对电商卖家来说&#xff0c;首先需要解决的问题就是货源。 虽然知道1688是个大型综合性的货源平台&#xff0c;但很多卖家还是觉得1688上面的货源很贵&#xff0c;甚至在平台严查无货源的背景下&#xff0c;还是坚持从1688拿货。那么为什么有些拼多多的商品会比1688还便宜呢&a…

openipc:/etc/init.d/目录下的所有启动文件启动分析

openipc /etc/init.d/目录下的所有文件 启动文件解析参考&#xff1a;https://blog.csdn.net/qq_37212828/article/details/107227965 1. rcS文件&#xff0c;是本目录在开机时最先启动的文件&#xff1a; 它会依次启动/etc/init.d/目录下依S开头的文件 #!/bin/sh # Start a…

探索线性回归模型

目录 一 线性回归的理论基础 什么是线性回归? 线性回归的假设 最小二乘法 二 线性回归的数学推导 线性回归参数的推导 多元线性回归 三 线性回归的模型构建 数据准备 训练模型 模型评估 四 线性回归的代码实现 基本实现 多元线性回归 五 线性回归的应用场景 预…

openh264 运动估计搜索原理源码分析

运动估计搜索 运动估计搜索是视频编码中的一个重要步骤&#xff0c;它用于确定视频序列中两个帧之间的运动向量&#xff08;MV&#xff09;。这些运动向量用于预测帧之间的运动&#xff0c;从而减少编码所需的数据量。以下是运动估计搜索的一些关键概念和步骤&#xff1a; 运动…

贪心算法——赶作业(C++)

慢慢来&#xff0c;沉稳一点。 2024年6月18日 题目描述 A同学有n份作业要做&#xff0c;每份作业有一个最后期限&#xff0c;如果在最后期限后交作业就会扣分&#xff0c;现在假设完成每份作业都需要一天。A同学想安排作业顺序&#xff0c;把扣分降到最低&#xff0c;请帮他实…

易备防勒索备份方案与成功案例

随着信息化的发展&#xff0c;数据安全的重要性愈加突出。据 Hiscox 全球网络安全统计&#xff0c;在勒索软件攻击事件当中&#xff0c;64%以上的用户是中小企业。因此&#xff0c;制定完善的灾备策略&#xff0c;是抵御网络威胁的终极方案。而在诸多数据备份方案中&#xff0c…

【Linux】进程控制1——进程创建和进程终止

1.进程创建 1.1.再谈fork 在linux中fork函数时非常重要的函数&#xff0c;它从已存在进程中创建一个新进程。新进程为子进程&#xff0c;而原进程为父进程。 #include <unistd.h> pid_t fork(void);//pid_t为整形 返回值&#xff1a;子进程中的fork()返回0&#xff…

内置类型不够用?试试Python内置类型子类化!

目录 1、经典继承法:直接子类化内置类型 🧬 1.1 了解Python内置类型 1.2 实现子类化的基础步骤 步骤1:定义子类 步骤2:添加自定义行为 步骤3:使用子类 1.3 实战:子类化列表list示例 1.4 优化:重写魔法方法实现自定义行为 2、高级技巧:元类介入定制 🪐 2.1 …

TCP/IP协议,三次握手,四次挥手,常用的协议

IP - 网际协议 IP 负责计算机之间的通信。 IP 负责在因特网上发送和接收数据包。 HTTP - 超文本传输协议 HTTP 负责 web 服务器与 web 浏览器之间的通信。 HTTP 用于从 web 客户端&#xff08;浏览器&#xff09;向 web 服务器发送请求&#xff0c;并从 web 服务器向 web …

智能门锁电池双节升压充电芯片-FP6291支持5V1A输入升压 8.4V双节电池充电

方案背景 可充电锂电池是一种环保、高效的智能锁电池类型&#xff0c;其主要优点是可以循环充电使用、容量大、使用寿命长。与一次性电池相比&#xff0c;可充电锂电池可以循环充电使用&#xff0c;减少了废弃物的产生和对环境的影响。同时&#xff0c;可充电锂电池的容量较大…

细说MCU输出互补型PWM波形的实现方法

目录 一、硬件及工程 二、建立工程 1、TIM1引脚 2、建立工程 &#xff08;1&#xff09;配置GPIO &#xff08;2&#xff09;选择时钟源和Debug模式 &#xff08;3&#xff09;配置定时器 &#xff08;4&#xff09;配置中断 &#xff08;5&#xff09;配置系统时钟 …

怎么去避免手机赚钱的骗局?

要避免手机赚钱的骗局&#xff0c;可以遵循以下一些建议&#xff1a; 1. 谨慎对待高收益承诺&#xff1a;如果一个项目承诺轻松获取高额回报&#xff0c;那么很可能存在风险。真正的高收益往往伴随着高风险&#xff0c;而且需要付出大量的努力和时间。 2. 调查了解相关项目&am…