android开发之Android 自定义滑动解锁View

自定义滑动解锁View

  1. 需求如下:

近期需要做一个类似屏幕滑动解锁的功能,右划开始,左划暂停。

  1. 需求效果图如下
    IMG_256
  2. 实现效果展示
    IMG_257
  3. 自定义view如下

/**

  • Desc 自定义滑动解锁View

  • Author ZY

  • Mail sunnyfor98@gmail.com

  • Date 2021/5/17 11:52

*/

@SuppressLint(“ClickableViewAccessibility”)

class SlideSwitchButton : ViewGroup {

constructor(context: Context?) : this(context, null)

constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0)

constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : this(

    context,

    attrs,

    defStyleAttr, 0

)

constructor(

    context: Context?,

    attrs: AttributeSet?,

    defStyleAttr: Int,

    defStyleRes: Int

) : super(context, attrs, defStyleAttr, defStyleRes)

var duration = 300

var isOpen = false

var scrollView: ScrollView? = null

var onSwitchListener: ((isOpen: Boolean) -> Unit)? = null

private var itemHeight = 0

private var itemPadding = 0

private var parentWidth = 0

private val stopImgView: ImageView by lazy {

    ImageView(context).apply {

        setImageResource(R.drawable.f1_svg_btn_stop)

    }

}

private val startImgView: ImageView by lazy {

    ImageView(context).apply {

        setImageResource(R.drawable.f1_svg_btn_start)

    }

}

private val hintView: TextView by lazy {

    TextView(context).apply {

        setTextSize(TypedValue.COMPLEX_UNIT_PX, resources.getDimension(R.dimen.dp_14))

        compoundDrawablePadding = resources.getDimension(R.dimen.dp_5).toInt()

        setTextColor(Color.parseColor("#727b9f"))

    }

}

init {

    setBackgroundResource(R.drawable.f1_sel_bg_slide_btn)

    addView(hintView)

    updateHint()

    addView(stopImgView)

    addView(startImgView)

    var x = 0

    startImgView.setOnTouchListener { v, event ->

        when (event.action) {

            MotionEvent.ACTION_DOWN -> {

                scrollView?.requestDisallowInterceptTouchEvent(true)

                x = event.x.toInt()

            }

            MotionEvent.ACTION_UP -> {

                if (startImgView.x < (parentWidth - startImgView.width) / 2) {

                    play(false)

                } else {

                    play(true)

                }

                scrollView?.requestDisallowInterceptTouchEvent(false)

            }

            MotionEvent.ACTION_MOVE -> {

                val lastX = event.x - x

                if (startImgView.x + lastX > parentWidth - itemPadding - startImgView.width) {

                    return@setOnTouchListener true

                }

                if (startImgView.x + lastX < itemPadding) {

                    return@setOnTouchListener true

                }

                startImgView.x += lastX

            }

        }

        return@setOnTouchListener true

    }

}

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {

    super.onMeasure(widthMeasureSpec, heightMeasureSpec)

    setMeasuredDimension(widthMeasureSpec, resources.getDimension(R.dimen.dp_90).toInt())

    itemPadding = resources.getDimension(R.dimen.dp_5).toInt()

    itemHeight = resources.getDimension(R.dimen.dp_80).toInt()

    parentWidth = MeasureSpec.getSize(widthMeasureSpec)

}

override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {

    stopImgView.layout(

        itemPadding,

        itemPadding,

        itemPadding + itemHeight,

        itemPadding + itemHeight

    )

    startImgView.layout(

        itemPadding,

        itemPadding,

        itemPadding + itemHeight,

        itemPadding + itemHeight

    )

    val len =

        hintView.paint.measureText(hintView.text.toString()) + resources.getDimension(R.dimen.dp_24)

    val let = (r - len) / 2

    hintView.layout(

        let.toInt(),

        resources.getDimension(R.dimen.dp_35).toInt(),

        (let + len).toInt(),

        resources.getDimension(R.dimen.dp_55).toInt()

    )

}

/**

 * flag tue为开始 false为停止

 */

private fun play(flag: Boolean) {

    val mStart = startImgView.x

    val mEnd = if (flag) {

        parentWidth - itemPadding * 2 - startImgView.width.toFloat()

    } else {

        stopImgView.x - itemPadding

    }

    val animatorOBJ =

        ObjectAnimator.ofFloat(startImgView, "translationX", mStart, mEnd)

    animatorOBJ.duration = duration.toLong()

    animatorOBJ.addListener(object : Animator.AnimatorListener {

        override fun onAnimationRepeat(animation: Animator?) {

        }

        override fun onAnimationEnd(animation: Animator?) {

            updateHint(flag)

            if (flag != isOpen) {

                isOpen = flag

                onSwitchListener?.invoke(flag)

            }

        }

        override fun onAnimationCancel(animation: Animator?) {

        }

        override fun onAnimationStart(animation: Animator?) {

        }

    })

    animatorOBJ.start()

}

private fun updateHint(lock: Boolean = false) {

    val icon = if (lock) {

        hintView.text = "滑动停止"

        ResourcesCompat.getDrawable(resources, R.drawable.f1_svg_left_arrow, null)

    } else {

        hintView.text = "滑动开始"

        ResourcesCompat.getDrawable(resources, R.drawable.f1_svg_right_arrow, null)

    }

    icon?.setBounds(

        0,

        0,

        resources.getDimension(R.dimen.dp_14).toInt(),

        resources.getDimension(R.dimen.dp_12).toInt()

    )

    if (lock) {

        hintView.setCompoundDrawables(icon, null, null, null)

    } else {

        hintView.setCompoundDrawables(null, null, icon, null)

    }

}

fun stop() {

    play(false)

}

fun start() {

    play(true)

}

}

这里需要注意一点:页面过长时,ScrollView和SlideSwitchButton滑动事件会冲突,所以需要吧scrollView传进来

  1. 调用方式如下

/**

  • Desc 自定义滑动解锁View

  • Author ZY

  • Mail sunnyfor98@gmail.com

  • Date 2021/5/28 17:48

*/

class SlideSwitchButtonActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState)

    setContentView(R.layout.f1_act_main)

    btn_start.scrollView = scrollView

    btn_start.onSwitchListener = {

        if (it) {

            Toast.makeText(this,"开始操作",Toast.LENGTH_LONG).show()

            btn_start.start()

        } else {

            Toast.makeText(this,"停止操作",Toast.LENGTH_LONG).show()

            btn_start.stop()

        }

    }

}

}

之前封装了一版ZyFrame框架,集工具类、自定义组件、网络请求框架一体,感觉用起来有些厚重,接下来会抽时间做拆分,ZyFrame保留网络请求功能,ZyUI专做自定义组件,ZyTool专做工具类,大概就这样。

文章来源:网络 版权归原作者所有

上文内容不用于商业目的,如涉及知识产权问题,请权利人联系小编,我们将立即处理

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

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

相关文章

开发工具Eclipse的使用之导入项目(import)

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Eclipse使用的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.导读 二.详细操作步骤 1.右击项…

【深度学习】StyleGANv2 2019 论文,Analyzing and Improving the Image Quality of StyleGAN

StyleGAN论文&#xff1a; 《A Style-Based Generator Architecture for Generative Adversarial Networks》 论文&#xff1a;https://arxiv.org/abs/1812.04948 代码&#xff1a; https://github.com/NVlabs/stylegan StyleGANv2论文&#xff1a; 《Analyzing and Improving …

电池的正极是带正电?

首先说明结论&#xff1a;电池正极带正电&#xff0c;负极带负电。 一个错误的实例&#xff1a; 如果说电流是从电池正极流动到电池负极&#xff0c;那么电子就是从负极流动到正极&#xff0c;那么正极就是带负电。----这个说法是错误的。这是因为&#xff0c;根据那么很出名…

简绘ChatGPT支持Midjourney绘图 支持stable diffusion绘图

简绘支持Midjourney绘图和stable diffusion绘图。 这意味着简绘具备Midjourney绘图和stable diffusion绘图功能的支持。

无涯教程-Perl - redo函数

描述 此函数将重新启动当前循环,而不会强制判断控制语句。块中不再执行任何语句。如果存在继续块,将不会执行。如果指定了LABEL,则在LABEL标识的循环开始时重新开始执行。 语法 以下是此函数的简单语法- redo LABELredo返回值 此函数不返回任何值。 例 以下是显示其基本…

Shell编程之条件测试、if语句、case语句

条件语句 一、条件测试1.1 测试命令1.1 文件测试1.2 整数比较1.3 字符串比较1.4 逻辑测试1.4.1 逻辑与 &&1.4.2 逻辑或 || 1.4.3 组合应用1.5 多个命令组合执行 ( ) { } 二、if语句2.1单分支结构2.2 多分支结构2.4 if语句练习2.4.1 单分支2.4.2 简单的交互式分数反馈 三…

元宇宙核能发电VR模拟仿真实训教学为建设新型电力系统提供重要支撑

随着“碳达峰、碳中和”目标与建设新型能源体系的提出&#xff0c;在元宇宙环境下建设电力系统是未来发展的趋势。以物联网、区块链、数字孪生、混合现实等技术为主要代表的元宇宙技术体系及其在电力和能源系统中的应用&#xff0c;将会促进智能电网的发展&#xff0c;为建设新…

VR安全宣传系列:防触电虚拟现实体验

在电气工作中&#xff0c;安全问题始终是重中之重。为了更好地提高公众的电气安全意识和技能&#xff0c;广州华锐互动开发了一种基于虚拟现实技术的模拟系统——VR防触电虚拟体验系统。这种系统可以模拟各种因操作不当导致的触电事故场景&#xff0c;并提供沉浸式的体验&#…

利用OpenSSL实现私有 CA 搭建和证书颁发

利用OpenSSL实现私有 CA 搭建和证书颁发 一、私有 CA 搭建1. 安装openssl2. 配置 openssl3. 生成 CA 自己的私钥4. 生成 CA 自己的自签证书5. 验证自签证书 二、向私有CA申请证书流程1. 生成应用私钥文件2. 根据应用私钥生成证书申请文件3. 向CA请求颁发证书4. 验证应用证书5. …

2022年09月 C/C++(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

第1题&#xff1a;指定顺序输出 依次输入3个整数a、b、c,将他们以c、a、b的顺序输出。 时间限制&#xff1a;1000 内存限制&#xff1a;65536 输入 一行3个整数a、b、c&#xff0c;以空格分隔。 0 < a,b,c < 108 输出 一行3个整数c、a、b&#xff0c;整数之间以一个空格分…

腾讯云服务器标准型CVM实例详细介绍S5/S6/SA2/SR1/SA3/S4等

腾讯云CVM服务器标准型实例的各项性能参数平衡&#xff0c;标准型云服务器适用于大多数常规业务&#xff0c;例如&#xff1a;web网站及中间件等&#xff0c;常见的标准型云服务器有CVM标准型S5、S6、SA3、SR1、S5se等规格&#xff0c;腾讯云服务器网来详细说下云服务器CVM标准…

使用sqlplus连接oracle,提示ORA-01034和ORA-27101

具体内容如下 PL/SQL Developer 处 登录时 终端处 登录时 ERROR: ORA-01034: ORACLE not available ORA-27101: shared memory realm does not exist Process ID: 0 Session ID: 0 Serial number: 0 解决方法是执行以下命令 sqlplus /nolog conn / as sysdba startup …

0001nginx简介、相关模型与原理

文章目录 一. 什么是Nginx二. ngnix的一些模型1、nginx的进程模型2、worker的抢占&#xff08;锁&#xff09;机制模型3. nginx事件处理模型 三. nginx加载静态资源的过程 一. 什么是Nginx Nginx是一个高性能HTTP反向代理服务器&#xff0c;以下是nginx的相关能力 反向代理&am…

JDK 8 升级 JDK 17 全流程教学指南

JDK 8 升级 JDK 17 首先已有项目升级是会经历一个较长的调试和自测过程来保证允许和兼容没有问题。先说几个重要的点 遇到问题别放弃仔细阅读报错&#xff0c;精确到每个单词每一行&#xff0c;不是自己项目的代码也要点进去看看源码到底是为啥报错明确你项目引入的包&#x…

【Transformer】自注意力机制Self-Attention | 各种网络归一化Normalization

1. Transformer 由来 & 特点 1.1 从NLP领域内诞生 "Transformer"是一种深度学习模型&#xff0c;首次在"Attention is All You Need"这篇论文中被提出&#xff0c;已经成为自然语言处理&#xff08;NLP&#xff09;领域的重要基石。这是因为Transfor…

word横向页面侧面页码设置及转pdf后横线变竖线的解决方案

在处理材料的时候&#xff0c;会遇到同一个文档里自某一页开始&#xff0c;页面布局是横向的&#xff0c;这时候页码要设置在侧面&#xff0c;方法是双击页脚&#xff0c;然后在word工具栏上选择“插入”——>“文本框”——>“绘制竖版文本框”&#xff0c;然后在页面左…

C++小游戏贪吃蛇源码

graphics.h是针对DOS下的一个C语言图形库 (c也可以) 目前支持下载此头文件的常用的有两种: 1. EGE (Easy Graphics Engine)2. EasyX Graphics LibraryEGE, 全名Easy Graphics Engine, 是windows下的简易绘图库&#xff0c;是一个类似BGI(graphics.h)的面向C/C语言新手的图形库…

P11-Transformer学习1.1-《Attention Is All You Need》

Transformer目录:《Transformer Paper》1.0 CV Transformer必读论文5篇_汉卿HanQ的博客-CSDN博客 前文参考:Transformer1.0-预热_汉卿HanQ的博客-CSDN博客 全文1w3字左右&#xff0c;按照论文翻译个人理解精读&#xff0c;如果对你有所帮助&#xff0c;欢迎点个赞哦&#xff…

springboot基础

springboot基础 一、springboot课程介绍 Spring Boot 提供一种快速使用spring的方式&#xff0c;基于约定大于配置的思想&#xff0c;可以让开发者不必在配置与逻辑业务中来回进行思维切换&#xff0c;全身心的投入到业务的代码编写中&#xff0c;从而大大提高了开发效率。20…

2022年12月 C/C++(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

第1题&#xff1a;加一 输入一个整数x&#xff0c;输出这个整数加1后的值&#xff0c;即x1的值。 时间限制&#xff1a;1000 内存限制&#xff1a;65536 输入 一个整数x(0 ≤ x ≤ 1000)。 输出 按题目要求输出一个整数。 样例输入 9 样例输出 10 以下是使用C语言编写的解决方案…