【Android】使用SeekBar控制数据的滚动

news2024/11/25 20:48:22
项目需求

有一个文本数据比较长,需要在文本右侧加一个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);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return false;
    }

    @Override
    public 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);
    }

    @Override
    public synchronized void setProgress(int progress) {
        super.setProgress(progress);
        onSizeChanged(getWidth(), getHeight(), 0, 0);
    }

    @Override
    protected 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);
    }

    @Override
    public 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) {
        //关键更改2
        int 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">
    <item
        android:width="@dimen/dp_20"
        android:height="@dimen/dp_20">
        <shape android:shape="oval">
            <gradient
                android:angle="180"
                android:endColor="#1C000000"
                android:startColor="#1Cffffff" />
        </shape>
    </item>
    <item
        android:bottom="1dp"
        android:left="1dp"
        android:right="1dp"
        android:top="1dp">
        <shape android:shape="oval">
            <solid android:color="#5EB2FF" />
            <stroke
                android: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.VerticalSeekBar
                        android: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() {
                    @Override
                    public void onProgressChanged(VerticalSeekBar VerticalSeekBar, int progress) {
                        scrollView.scrollTo(0, progress);
                    }

                    @Override
                    public void onStartTrackingTouch(VerticalSeekBar VerticalSeekBar) {

                    }

                    @Override
                    public void onStopTrackingTouch(VerticalSeekBar VerticalSeekBar) {

                    }
                });

                scrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
                    @Override
                    public 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">
    <item
        android:width="@dimen/dp_15"
        android:height="@dimen/dp_15">
        <shape android:shape="oval">
            <gradient
                android:endColor="#1C000000"
                android:startColor="#1Cffffff" />
        </shape>
    </item>
    <item
        android:bottom="1dp"
        android:left="1dp"
        android:right="1dp"
        android:top="1dp">
        <shape android:shape="oval">
            <solid android:color="#5EB2FF" />
            <stroke
                android: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">
        <!--设置滑轨颜色:滑过部分和未滑过部分-->
        <!--未滑过部分滑轨颜色-->
        <item
            android:id="@android:id/background"
            android:height="4dp"
            android:gravity="center">
            <shape>
                <corners android:radius="67dp"/>
                <solid android:color="#4d000000"/>
            </shape>
        </item>
        <!--滑过部分滑轨颜色-->
        <item
            android: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.VerticalSeekBar
                        android: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.coloradmin.cn/o/1833974.html

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

相关文章

【 ARMv8/ARMv9 硬件加速系列 3.5.1 -- SVE 谓词寄存器有多少位?】

文章目录 SVE 谓词寄存器(predicate registers)简介SVE 谓词寄存器的位数SVE 谓词寄存器对向量寄存器的控制SVE 谓词寄存器位数计算SVE 谓词寄存器小结SVE 谓词寄存器(predicate registers)简介 ARMv9的Scalable Vector Extension (SVE) 引入了谓词寄存器(Predicate Register…

美团Meitu前端一面,期望27K

面经哥只做互联网社招面试经历分享&#xff0c;关注我&#xff0c;每日推送精选面经&#xff0c;面试前&#xff0c;先找面经哥 1、做的主要是什么项目&#xff0c;桌面端的吗&#xff1f; 2、用的主要是什么技术栈&#xff1f;vue有了解吗&#xff1f; 3、移动端开发一般怎么…

Tuxera NTFS与Paragon NTFS:两款NTFS驱动软件的深度对比 tuxera和paragon NTFS哪个好

在Mac上使用NTFS格式的磁盘&#xff0c;通常需要借助第三方的驱动软件。其中&#xff0c;Tuxera NTFS和Paragon NTFS是两款备受欢迎的选择。虽然它们的基本功能相似&#xff0c;但在细节和使用体验上却有所不同。本文将带你深入了解这两款软件的差异&#xff0c;帮助你做出更明…

三极管原理介绍

三极管 不同封装 基本定义 三极管&#xff0c;全称应为半导体三极管&#xff0c;也称双极型晶体管(BJT)、晶体三极管&#xff0c;是一种控制电流的半导体器件。其作用是把微弱信号放大成幅度值较大的电信号&#xff0c;也用作无触点开关。 三极管是半导体基本元器件之一&…

数据资产驱动的智能化决策:深度剖析数据资产在提升企业决策效率与准确性中的关键作用

在数字化、信息化日益普及的今天&#xff0c;数据已经成为企业发展的重要资产。数据资产不仅能够帮助企业更好地了解市场需求、优化业务流程&#xff0c;还能在决策过程中提供科学、精准的支持。本文将深入剖析数据资产在提升企业决策效率与准确性中的关键作用&#xff0c;探讨…

如何应对 CentOS 的停更?

文章目录 如何应对 CentOS 的停更&#xff1f;Linux发行版CentOS停更后&#xff0c;我们可选的替代品RHEL LinuxRocky Linux公有云 LinuxDebian 系 Linux 如何应对 CentOS 的停更&#xff1f; Linux发行版 Linux内核是开源的&#xff0c;任何人都可以获取源代码&#xff0c;进…

俄罗斯方块小游戏(附源码)

游戏展示 一.导包 import turtle import random 二.定义一个Block类 定义一个Block类&#xff0c;用于表示游戏中的方块&#xff0c;包含颜色和形状。 class Block:def __init__(self, color, tiles):self.color colorself.tiles tiles三.定义了7个不同的Block对象 定义了7…

全光万兆时代来临:信而泰如何推动F5G-A(50PONFTTR)技术发展

技术背景 F5G-A&#xff08;Fifth Generation Fixed Network-Advanced&#xff0c;第五代固定网络接入&#xff09;是固定网络技术的一次重大升级&#xff0c;代表了光纤网络技术的最新发展。F5G-A旨在提供更高的带宽、更低的延迟、更可靠的连接以及更广泛的应用场景。 F5G-A六…

Sunny v1.3.0 官方版 (简洁且漂亮截图应用)

前言 Sunny是一款漂亮又实用的“截图&钉图”的软件&#xff0c;亦支持“屏幕识图”和“OCR”的软件。 一、下载地址 下载链接&#xff1a;http://dygod/source 点击搜索&#xff1a;Sunny 二、安装步骤 1、解压后将Sunny.exe发送到桌面快捷方式 2、启动桌面图标 3、正…

相似性搜索揭秘:向量嵌入与机器学习应用

引言 在当今数据驱动的世界中&#xff0c;有效地检索和利用信息是一项关键挑战。在数据库、搜索引擎和众多应用程序中&#xff0c;寻找相似数据是一项基本操作。传统数据库中&#xff0c;基于固定数值标准的相似项搜索相对直接&#xff0c;通过查询语言即可实现&#xff0c;如…

每日一题——Python实现PAT甲级1144 The Missing Number(举一反三+思想解读+逐步优化)四千字好文

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 我的写法 时间复杂度分析 空间复杂度分析 总体空间复杂度&#xff1a;O(N) 总结 我…

【Vue】——组件的注册与引用(二)

&#x1f4bb;博主现有专栏&#xff1a; C51单片机&#xff08;STC89C516&#xff09;&#xff0c;c语言&#xff0c;c&#xff0c;离散数学&#xff0c;算法设计与分析&#xff0c;数据结构&#xff0c;Python&#xff0c;Java基础&#xff0c;MySQL&#xff0c;linux&#xf…

软件加密的基本概念

软件加密作为信息安全领域的一项重要技术&#xff0c;随着数字化时代的到来&#xff0c;其重要性日益凸显。以下是关于软件加密的详细解析&#xff0c;旨在为读者提供全面且深入的了解。 一、软件加密的基本概念 软件加密&#xff0c;简而言之&#xff0c;就是在数据传输、存储…

在windows 台式机电脑部署GLM4大模型

参考这篇文章在windows笔记本电脑部署GLM4大模型_16g显卡本地部署glm4-CSDN博客 我的环境&#xff08;PC台式机电脑&#xff1a; 处理器 Intel(R) Core(TM) i9-14900K 3.20 GHz 机带 RAM 32.0 GB (31.8 GB 可用)、32G内存、NVIDIA RTX4080&#xff08;16G&#xff09;…

使用 ZTM 增强极空间 NAS 的远程访问能力

入手极空间 Z4Pro 快两个周了&#xff0c;使用体验文章还得再等一等&#xff0c;多一些深度体验的时间。到目前来看&#xff0c;还是很满意的。 背景 今天这篇来说说极空间的远程访问功能&#xff0c;产品页面对远程访问的描述是&#xff1a; 让极空间真正成为你家庭中的网络…

6.17 作业

使用qt实现优化自己的登录界面 要求&#xff1a; 1. qss实现 2. 需要有图层的叠加 &#xff08;QFrame&#xff09; 3. 设置纯净窗口后&#xff0c;有关闭等窗口功能。 4. 如果账号密码正确&#xff0c;则实现登录界面关闭&#xff0c;另一个应用界面显示。 第一个源文件 …

Mybatis --- 动态SQL 和数据库连接池

文章目录 一、什么是动态SQL 重要性二、动态SQL的编写 ---注解三、动态SQL的编写 ---xml3.1 增加场景 if标签3.2 处理代码块内容 --- trim 标签3.3 查询场景 where标签3.4 更新场景 set标签3.5 删除场景 <foreach> 循环标签3.6 include、sql标签 代码重复度问题 四、数据…

vue+element-plus完美实现跨境电商商城网站

目录 一、项目介绍 二、项目截图 1.项目结构图 2.首页 3.中英文样式切换 4.金钱类型切换 5.商品详情 6.购物车 7.登录 ​编辑 8.注册 9.个人中心 三、源码实现 1.项目依赖package.json 2.项目启动 3.购物车页面 四、总结 一、项目介绍 本项目在线预览&am…

Matlab基础篇:绘图与可视化

目录 前言 一、二维绘图 二、图形属性设置 三、多图绘制 四、三维绘图 五、绘图技巧 六、绘图的高级技巧 七、实例示范&#xff1a;绘制多功能图形 八、总结 前言 在数据分析和数学建模中&#xff0c;可视化是一个非常关键的步骤。Matlab 提供了丰富的绘图和可视化工…

自主可控数据库沙龙(北京站 |线下| 报名中)

**数据库沙龙**是一个致力于推动数据库技术创新和发展的高端交流平台&#xff0c;旨在增强国内数据库产业的自主可控性和高质量发展。这个平台汇集了学术界和产业界的顶尖专家、学者以及技术爱好者&#xff0c;通过专题演讲、案例分享和技术研讨等丰富多样的活动形式&#xff0…