自定义歌曲试听SeekBar

在这里插入图片描述
看到这个效果,可能会想到完全自定义一个控件,其实我们在系统Seekbar的基础上,将progressDrawable中progress背景设为透明后,叠加绘制试听状态下的进度区域即可

class PlayerSeekBar @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0,
    defStyleRes: Int = 0,
) : SeekBar(context, attrs, defStyleAttr, defStyleRes) {

    private var tryPlayable = true
    private var tryPlayableStartPos = 10
    private var tryPlayableEndPos = 60
    private val normalProgressDrawable: Drawable? =
        context.getDrawable(R.drawable.bg_player_seekbar)
    private val fakeProgressDrawable: Drawable? =
        context.getDrawable(R.drawable.bg_player_seekbar_fake)

    private val tryPlayableBgPaint: Paint by lazy {
        Paint().apply {
            isAntiAlias = true
            style = Paint.Style.FILL_AND_STROKE
            color = context.getColor(R.color.player_try_playable_progress_color)
        }
    }

    private val tryPlayableProgressPaint by lazy {
        Paint().apply {
            isAntiAlias = true
            style = Paint.Style.FILL_AND_STROKE
            color = context.getColor(R.color.player_track_color)
        }
    }

    private var playSeekBarChangeListener: OnPlaySeekBarChangeListener? = null

    init {
        setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                playSeekBarChangeListener?.onProgressChanged(seekBar, progress, fromUser)
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {
                playSeekBarChangeListener?.onStartTrackingTouch(seekBar)
            }

            override fun onStopTrackingTouch(seekBar: SeekBar?) {
                playSeekBarChangeListener?.onStopTrackingTouch(seekBar)
                if (isOverTryPlayableAre()) {
                    playSeekBarChangeListener?.onOverTryPlayableArea()
                }
            }
        })
    }

    private fun isOverTryPlayableAre(): Boolean {
        return tryPlayable && (progress > tryPlayableEndPos || progress < tryPlayableStartPos)
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        if (tryPlayable) {
            val tryPlayableProgress =
                progress.coerceAtLeast(tryPlayableStartPos).coerceAtMost(tryPlayableEndPos)
            // 试听区域背景
            drawTryPlayableRect(canvas, tryPlayableBgPaint, tryPlayableStartPos, tryPlayableEndPos)
            // 试听区域进度
            drawTryPlayableRect(
                canvas,
                tryPlayableProgressPaint,
                tryPlayableStartPos,
                tryPlayableProgress
            )
        }

    }

    private fun drawTryPlayableRect(canvas: Canvas?, paint: Paint, startPos: Int, endPos: Int) {
        val percent = (endPos - startPos) * 1.0F / (max - min)
        val left =
            paddingLeft + (startPos - min) * 1.0F / (max - min) * (width - paddingLeft - paddingRight)
        val top = paddingTop.toFloat()
        val right = left + (width - paddingLeft - paddingRight) * percent
        val bottom = (height - paddingBottom).toFloat()
        canvas?.drawRect(left, top, right, bottom, paint)
    }

    fun setTryPlayable(tryPlayable: Boolean) {
        this.tryPlayable = tryPlayable
        progressDrawable = if (tryPlayable) {
            fakeProgressDrawable
        } else {
            normalProgressDrawable
        }
        invalidate()
    }

    fun setTryPlayProgress(tryPlayableStartPos: Int, tryPlayableEndPos: Int) {
        this.tryPlayableStartPos = tryPlayableStartPos
        this.tryPlayableEndPos = tryPlayableEndPos
        invalidate()
    }

    fun setOnPlaySeekBarChangeListener(listener: OnPlaySeekBarChangeListener) {
        this.playSeekBarChangeListener = listener
    }

    interface OnPlaySeekBarChangeListener : OnSeekBarChangeListener {
        // 超出试听区域
        fun onOverTryPlayableArea()
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

客服中心的客户关系管理核心功能

根据国外的调查&#xff0c;拥有客服中心的运营机构&#xff0c;可以保持85%左右的客户忠诚度&#xff0c;而接受过专业培训的客户中心可以将客户忠诚度提高到99%。客服中心作为客户关系管理的前沿&#xff0c;通过提供服务、实时沟通、搜集与分析客户信息、预测客户需求来提升…

SQL常见函数整理 —— lead()向下偏移

1. 用法 是在窗口函数中使用的函数&#xff0c;它用于获取当前行的下一行&#xff08;后一行&#xff09;的某个列的值。具体来说&#xff0c;LEAD() 函数可用于查找任何给定行的下一行&#xff08;后一行&#xff09;的值&#xff0c;同时也可控制行数偏移量&#xff08;offse…

每日汇评:澳元多头着眼于50%的斐波那契水平

澳元兑美元跳涨至三个月高点上方&#xff0c;并从多种因素中获得支撑&#xff1b; 对美联储已经结束加息的预期继续严重打压美元&#xff1b; 对中国出台更多刺激措施的乐观情绪和积极的风险基调也有利于澳元&#xff1b; 澳元兑美元周一连续获得强劲的后续积极牵引力&#xff…

在列表控件上显示提示信息

当我们在实现列表控件上的提示信息的时候&#xff0c;我们需要处理的一个难点是处理列表条目的折叠和展开这两种情况。 所谓列表条目的折叠&#xff0c;即在大图标模式(Large Icon Mode)下&#xff0c;列表条目的文字过长而被截断的情况。当用户选择这个条目后&#xff0c;条目…

损失函数总结(十五):MSLELoss、RMSLELoss

损失函数总结&#xff08;十五&#xff09;&#xff1a;MSLELoss、RMSLELoss 1 引言2 损失函数2.1 MSLELoss2.2 RMSLELoss 3 总结 1 引言 在前面的文章中已经介绍了介绍了一系列损失函数 (L1Loss、MSELoss、BCELoss、CrossEntropyLoss、NLLLoss、CTCLoss、PoissonNLLLoss、Gau…

城市生命线丨市政综合管廊监测系统的效果

市政综合管廊&#xff0c;又被称为城市生命线&#xff0c;是我们在地下建造的一个智慧而高效的空间。它把市政、电力、通讯、燃气、给排水等各种管线集于一体&#xff0c;解决了城市中反复开挖路面、架空线网密集、管线事故频发等问题&#xff0c;为城市运行提供了重要的基础设…

C#,怎么修改(VS)Visual Studio 2022支持的C#版本

一些文字来自于 Microsoft . &#xff08;只需要读下面的红色文字即可&#xff01;&#xff09; 1 C# 语言版本控制 最新的 C# 编译器根据项目的一个或多个目标框架确定默认语言版本。 Visual Studio 不提供用于更改值的 UI&#xff0c;但可以通过编辑 .csproj 文件来更改值。…

浅谈餐饮业油烟污染现状及在线监测系统的设计与应用

贾丽丽 安科瑞电气股份有限公司 上海嘉定 201801 摘要&#xff1a;城市餐饮业油烟污染成了困扰城区环境保护部门和人民群众日常生活的主要问题。油烟污染已经成为我国一个重大的污染源&#xff0c;是形成PM2.5的重要污染源之一&#xff0c;为了解决餐饮业油烟管理方面存在的问…

linux镜像的下载,系统下载(个人使用)

文章目录 一、系统之家二、国内镜像源三、Centos官网四、安装成功截图五、镜像类型的区别参考文档 一、系统之家 系统之家官网 二、国内镜像源 下载镜像地址&#xff1a; 1、官网地址&#xff1a;https://www.centos.org/ 2、阿里镜像站&#xff1a;https://mirrors.aliyu…

人工智能基础_机器学习041_Sigmoid函数详解_Sigmoid损失函数推导_最大似然函数推导---人工智能工作笔记0081

然后我们再来看一下sigmoid函数的推导过程,可以看到首先我们把 sigmoid的函数写成两种情况 可以看到P(y|x;theta) = htheta(x), y=1 这个时候y=1 也就是是一种分类,然后另一种,就是相减, 是1-htheta(x) 可以看到,把两个公式河道一起就得到了下面的概率公式. 这里是有关概率…

被OpenAI开除后,创始人奥特曼在微软找到了新工作

微软首席执行官纳德拉宣布&#xff0c;OpenAI创始人Sam Altman和Brockman及其同事将加入微软。随后&#xff0c;Altman转发了他的推特。 此前&#xff0c;外媒消息称&#xff0c;OpenAI首席科学家伊尔亚苏茨克维&#xff08;Ilya Sutskever&#xff09;周日晚告知公司员工&…

Dubbo快速实践

文章目录 架构相关概念集群和分布式架构演进 Dubbo概述Dubbo快速入门前置准备配置服务接口配置Provider配置Consumer Dubbo基本使用总结 本文参考https://www.bilibili.com/video/BV1VE411q7dX 架构相关概念 集群和分布式 集群&#xff1a;很多“人”一起 &#xff0c;干一样…

有哪些相见恨晚的stm32学习的方法?

有哪些相见恨晚的stm32学习的方法&#xff1f; 单片机用处这么广&#xff0c;尤其是STM32生态这么火&#xff01;如何快速上手学习呢&#xff1f; 你要考虑的是&#xff0c;要用STM32实现什么&#xff1f;为什么使用STM32而不是用8051&#xff1f;是因为51的频率太低&#xff…

requests库出现AttributeError问题的修复与替代方法

在使用App Engine时&#xff0c;开发者们通常会面临需要发送爬虫ip请求的情况&#xff0c;而Python中的requests库是一个常用的工具&#xff0c;用于处理爬虫ip请求。然而&#xff0c;在某些情况下&#xff0c;开发者可能会遇到一个名为AttributeError的问题&#xff0c;特别是…

软件数字签名是什么?软件数字签名有什么作用?

在当今互联网时代&#xff0c;网络安全威胁日益增加&#xff0c;恶意软件层出不穷&#xff0c;为了防止下载到恶意软件&#xff0c;用户在下载软件时都会确认其是安全可信的。由此&#xff0c;企业需要证明其发布的软件真实可信且未被篡改&#xff0c;如何证明这一点呢&#xf…

MATLAB常用绘图函数的使用

文章目录 绘制一图一线绘制一图多线用法一&#xff1a;plot用法二&#xff1a;hold on 绘制一图多图其他形式的坐标图分段函数绘制方法一&#xff1a;分段写函数的定义域值域方法二&#xff1a;判断定义域方法三&#xff1a;if else 判断 横纵坐标范围设置标题、轴标签、图例、…

JVM基础- 垃圾回收器

基本介绍 Java虚拟机&#xff08;JVM&#xff09;中的垃圾回收器是用来自动管理内存的关键组件。它负责识别并回收不再使用的内存&#xff0c;从而防止内存泄漏。不同的JVM实现提供了多种垃圾回收器&#xff0c;每种回收器都有其特定的使用场景和性能特点。以下是一些常见的JV…

16路模拟信号转RS-485/232,Modbus RTU 通讯协议数据采集24位A/D转换模块 YL29

特点&#xff1a; ● 16路模拟信号采集&#xff0c;隔离转换 RS-485/232输出 ● 采用24位AD转换器&#xff0c;测量精度优于0.05% ● 通过RS-485/232接口可以程控校准模块精度 ● 信号输入 / 输出之间隔离耐压3000VDC ● 宽电源供电范围&#xff1a;8 ~ 32VDC ● 可靠性高…

【从入门到起飞】JavaSE—带你了解Map,HashMap,TreeMap的使用方法

&#x1f38a;专栏【Java基础】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【The truth that you leave】 &#x1f970;欢迎并且感谢大家指出我的问题 文章目录 &#x1f33a;双列集合的特点&#x1f384;Map&#x1f354;Ma…