Android自定义控件(八) Android仿招商银行APP手势解锁

news2024/11/24 6:22:03

前言

目前大部分APP的登录方式有多种类型,其中手势解锁就是其中比较常见的一种方式,经常使用的招商银行APP(IOS)端的手势解锁体验不错的,就仿照它自定义下手势解锁功能。


说明

1、招行APP手势解锁效果


2、绘制分析

来分析下效果图1和图2中需要绘制的元素。

  1. 未执行解锁操作,需要绘制9个灰色小圆点来形成锁盘
  2. 执行解锁操作,绘制大圆、黑色小圆点、圆之间的连线以及圆到手指所在位置的连线
  3. 松手后重置绘制,校验密码是否正确

上面分析了需要绘制的元素,那么元素的绘制条件有哪些?

  • 灰色小圆不需要触摸条件,默认要绘制9个点
  • 元素之间的位置由大圆的半径outerRadius、横向间距landsMargin、纵向间距vertMargin决定
  • 当手指所在范围位于A、B 时,触发大圆以及中间黑色的圆绘制。
  • C是手指当前所在的位置

在这里插入图片描述

再细化下手势解锁的业务逻辑,首先,没有手势操作时,绘制9个灰色小圆作为锁屏面板。

假设,当手指在锁屏面板按下坐标在A或者B的范围内,触发绘制大圆以及黑色的小圆(这是触发大圆绘制的条件),这种状态暂且叫它选中状态
且以为例,当手指再在⑦内**按下**,滑动手指到C,此时以圆为中心绘制到C`的直线。

若是手指滑动的过程中坐标在范围内,将的中心直线连接起来,再连接到C

在整个过程中,若是已经选中状态(如①、②、⑤、⑥等),就不在进行连线处理,这里可以使用一个集合来管理选中的元素。


实现

分析了整个View绘制的要素,下面就来实现它,首先绘制的是解锁面板。


class PatternLockView(context: Context,attributeSet: AttributeSet):View(context) {

    private var dWidth = 0

    private var dHeight = 0

    private var ctx = context

	//上下内边距,优化最上和最下圆显示不全问题
    private val vertPadding = 5f

	//纵向间距
    private val vertMargin = 200f

	//横向间距
    private val landsMargin = 180f
    
	//小圆半径
    private val innerRadius = 20f
	
	//大圆半径
    private val outerRadius = 60f
	
	//小圆画笔	
    private var innerPaint = Paint().apply {
        style = Paint.Style.FILL
        color = context.getColor(R.color.colorLightGrey)
        isAntiAlias = true
        isDither = true
    }
	
	//大圆画笔
    private var outerPaint = Paint().apply {
        style = Paint.Style.STROKE
        color = context.getColor(R.color.colorBlack)
        isAntiAlias = true
        isDither = true
    }
	
	//直线画笔
    private var linePaint = Paint().apply {
        style = Paint.Style.FILL
        color = context.getColor(R.color.colorBlack)
        isAntiAlias = true
        isDither = true
        strokeWidth = 10f
        strokeCap = Paint.Cap.ROUND
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        dWidth = w
        dHeight = h
    }

   override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        canvas.apply {
            //绘制解锁面板
            drawPatternLock(this)
            //解锁过程-绘制大圆
            drawGestureUnlock(this)
            //解锁过程-绘制直线
            if(isMove){ drawUnlockPath(this) }
        }
    }
	
	/**
     * 绘制9个灰色小圆点、大圆和黑色小圆
     */
    private fun drawPatternLock(canvas: Canvas) {
        innerPaint.color = context.getColor(R.color.colorLightGrey)
        var level = 0
        var rNum = 0
        for(i in 0..8){
        	//横向-对应圆①、圆②、圆③
            if(i in 0..2){
                level = 1
                rNum = 1
            }
            //横向-对应圆④、圆⑤、圆⑥
            if(i in 3..5){
                level = 2
                rNum = 3
            }
             //横向-对应圆⑦、圆⑧、圆⑨
            if(i in 6..8){
                level = 3
                rNum = 5
            }
            //纵向-对应圆①、圆④、圆⑦
            if(i % 3 == 0){
                canvas.drawCircle(outerRadius + landsMargin,vertPadding + rNum * outerRadius + (level - 1) * vertMargin,innerRadius,innerPaint)
            }
            //纵向-对应圆②、圆⑤、圆⑧
            if(i % 3 == 1){
                canvas.drawCircle(dWidth / 2f,vertPadding + rNum * outerRadius + (level - 1) * vertMargin,innerRadius,innerPaint)
            }
            //纵向-对应圆③、圆⑥、圆⑨
            if(i % 3 == 2){
                canvas.drawCircle(dWidth -  landsMargin - outerRadius,vertPadding + rNum * outerRadius + (level - 1) * vertMargin,innerRadius,innerPaint)
            }
        }
    }
}

绘制小圆还是比较简单的,只要计算好各个圆之间的位置,横向上的元素纵坐标相同,纵向上的元素横坐标相同,处理下即可绘制。下面着重介绍下手势解锁过程中的绘制。

看到上面onDraw方法中已经调用绘制解锁drawGestureUnlock和绘制解锁路线drawUnlockPath方法,在分析两个方法之前,我们要考虑两个问题:

1、既然是手势解锁,手势如何生成密码,密码如何管理

2、绘制手势路径


  //手指当前的x坐标
  private var moveX = 0f

  //手指当前的y坐标
  private var moveY = 0f

 //当前手指是否是移动状态
  private var isMove = false
	
  //密码管理集合	
  private var pwList:ArrayList<Int> = ArrayList()

  //密码管理临时集合,用于生成密码字符串
  private var pwTempList:ArrayList<Int> = ArrayList()

  //用于管理绘制路径坐标点的集合
  private var pointList:ArrayList<PointF> = ArrayList()

  override fun onTouchEvent(event: MotionEvent): Boolean {
        when(event.action){
            MotionEvent.ACTION_DOWN ->{
                //手指按下的x坐标
                val downX = event.x
                //手指按下的y坐标
                val downY = event.y
                checkPressPos(downX,downY)
                //手指不是移动状态
                isMove = false
            }
            MotionEvent.ACTION_MOVE ->{
                //手指移动x坐标
                moveX = event.x
                //手指移动y坐标
                moveY = event.y
                //手指移动的标准是正切大于6个像素点
                if(sqrt(abs(moveX).pow(2) + abs(moveY).pow(2)) > 6f){
                    isMove = true
                    checkPressPos(moveX,moveY)
                }
            }
            MotionEvent.ACTION_UP ->{
            	//手指不是移动状态
                isMove = false
                //点集合置空
                pointList.clear()
          		//临时密码管理集合新增密码
                pwTempList.clear()
                pwTempList.addAll(pwList)
                //密码管理集合置空
                pwList.clear()
                invalidate()
                checkPassword()
            }
        }
        return true
    }

  	/**
     * 判断手指按下与滑动过程中位置是否在大圆内
     */
    private fun checkPressPos(x: Float, y: Float) {
        val point = PointF()
          if(x > landsMargin && x < landsMargin +  2 * outerRadius && y > vertPadding && y < vertPadding + 2 * outerRadius){
             //判断是坐标点否在圆①内
              if(!pwList.contains(1)){
                  pwList.add(1)
                  point.x = outerRadius + landsMargin
                  point.y = outerRadius + vertPadding
                  pointList.add(point)
              }
          }else if(x > dWidth / 2 - outerRadius && x < dWidth / 2 + outerRadius  && y > vertPadding && y < vertPadding + 2 * outerRadius){
              //判断是坐标点否在圆②内
              if(!pwList.contains(2)){
                  pwList.add(2)
                  point.x =  dWidth / 2f
                  point.y = outerRadius + vertPadding
                  pointList.add(point)
              }
          }else if(x > dWidth - landsMargin -  2 * outerRadius  && x < dWidth - landsMargin && y > vertPadding && y < vertPadding + 2 * outerRadius){
             //判断是坐标点否在圆③内
              if(!pwList.contains(3)){
                  pwList.add(3)
                  point.x =  dWidth - landsMargin -  outerRadius
                  point.y = outerRadius + vertPadding
                  pointList.add(point)
              }
          } else if(x > landsMargin && x < landsMargin +  2 * outerRadius && y > vertPadding + vertMargin + 2 * outerRadius && y < vertPadding + vertMargin + 4 * outerRadius){
            //判断是坐标点否在圆④内
              if(!pwList.contains(4)){
                  pwList.add(4)
                  point.x = landsMargin + outerRadius
                  point.y = vertPadding + vertMargin + 3 * outerRadius
                  pointList.add(point)
              }
          }else if(x > dWidth / 2 - outerRadius && x < dWidth / 2 + outerRadius && y > vertPadding + vertMargin + 2 * outerRadius && y < vertPadding + vertMargin + 4 * outerRadius){
           //判断是坐标点否在圆⑤内
              if(!pwList.contains(5)){
                  pwList.add(5)
                  point.x = dWidth / 2f
                  point.y = vertPadding + vertMargin + 3 * outerRadius
                  pointList.add(point)
              }
          }else if(x > dWidth - landsMargin -  2 * outerRadius  && y > vertPadding + vertMargin + 2 * outerRadius && y < vertPadding + vertMargin + 4 * outerRadius){
          //判断是坐标点否在圆⑥内
              if(!pwList.contains(6)){
                  pwList.add(6)
                  point.x = dWidth - landsMargin -  outerRadius
                  point.y = vertPadding + vertMargin + 3 * outerRadius
                  pointList.add(point)
              }
          }else if(x > landsMargin && x < landsMargin +  2 * outerRadius && y > vertPadding + 2 * vertMargin + 4 * outerRadius && y < vertPadding + 2 * vertMargin + 6 * outerRadius){
            //判断是坐标点否在圆⑦内
              if(!pwList.contains(7)){
                  pwList.add(7)
                  point.x = landsMargin + outerRadius
                  point.y = vertPadding + 2 * vertMargin + 5 * outerRadius
                  pointList.add(point)
              }
          }else if(x > dWidth / 2 - outerRadius && x < dWidth / 2 + outerRadius && y >  vertPadding + 2 * vertMargin + 4 * outerRadius && y < vertPadding + 2 * vertMargin + 6 * outerRadius){
            //判断是坐标点否在圆⑧内
              if(!pwList.contains(8)){
                  pwList.add(8)
                  point.x = dWidth / 2f
                  point.y = vertPadding + 2 * vertMargin + 5 * outerRadius
                  pointList.add(point)
              }
          }else if(x > dWidth - landsMargin -  2 * outerRadius  && y > vertPadding + 2 * vertMargin + 4 * outerRadius && y < vertPadding + 2 * vertMargin + 6 * outerRadius){
             //判断是坐标点否在圆⑨内
              if(!pwList.contains(9)){
                  pwList.add(9)
                  point.x = dWidth - landsMargin -  outerRadius
                  point.y = vertPadding + 2 * vertMargin + 5 * outerRadius
                  pointList.add(point)
              }
          }
        invalidate()
    }


  	/**
     * 手势滑动解锁过程-绘制大圆和黑色小圆
     */
    private fun drawGestureUnlock(canvas: Canvas) {
        innerPaint.color = context.getColor(R.color.colorBlack)
        //密码集合包含圆①,绘制对应的大圆和黑色小圆
        if(pwList.contains(1)){
            canvas.drawCircle(outerRadius + landsMargin,vertPadding + 1 * outerRadius,innerRadius,innerPaint)
            canvas.drawCircle(outerRadius + landsMargin,vertPadding + 1 * outerRadius,outerRadius,outerPaint)
        }
        //密码集合包含圆②,绘制对应的大圆和黑色小圆
        if(pwList.contains(2)){
            canvas.drawCircle(dWidth / 2f,vertPadding + 1 * outerRadius,outerRadius,outerPaint)
            canvas.drawCircle(dWidth / 2f,vertPadding + 1 * outerRadius,innerRadius,innerPaint)
        }
        //密码集合包含圆③,绘制对应的大圆和黑色小圆
        if(pwList.contains(3)){
            canvas.drawCircle(dWidth -  landsMargin - outerRadius,vertPadding + 1 * outerRadius,outerRadius,outerPaint)
            canvas.drawCircle(dWidth -  landsMargin - outerRadius,vertPadding + 1 * outerRadius,innerRadius,innerPaint)
        }
        //密码集合包含圆④,绘制对应的大圆和黑色小圆
        if(pwList.contains(4)){
            canvas.drawCircle(outerRadius + landsMargin,vertPadding + vertMargin + 3 * outerRadius,innerRadius,innerPaint)
            canvas.drawCircle(outerRadius + landsMargin,vertPadding + vertMargin + 3 * outerRadius,outerRadius,outerPaint)
        }
        //密码集合包含圆⑤,绘制对应的大圆和黑色小圆
        if(pwList.contains(5)){
            canvas.drawCircle(dWidth / 2f,vertPadding + vertMargin + 3 * outerRadius,innerRadius,innerPaint)
            canvas.drawCircle(dWidth / 2f,vertPadding + vertMargin + 3 * outerRadius,outerRadius,outerPaint)
        }
        //密码集合包含圆⑥,绘制对应的大圆和黑色小圆
        if(pwList.contains(6)){
            canvas.drawCircle(dWidth -  landsMargin - outerRadius,vertPadding + vertMargin + 3 * outerRadius,innerRadius,innerPaint)
            canvas.drawCircle(dWidth -  landsMargin - outerRadius,vertPadding + vertMargin + 3 * outerRadius,outerRadius,outerPaint)
        }
        //密码集合包含圆⑦,绘制对应的大圆和黑色小圆
        if(pwList.contains(7)){
            canvas.drawCircle(outerRadius + landsMargin,vertPadding + 2 * vertMargin + 5 * outerRadius,innerRadius,innerPaint)
            canvas.drawCircle(outerRadius + landsMargin,vertPadding + 2 * vertMargin + 5 * outerRadius,outerRadius,outerPaint)
        }
        //密码集合包含圆⑧,绘制对应的大圆和黑色小圆
        if(pwList.contains(8)){
            canvas.drawCircle(dWidth / 2f,vertPadding + 2 * vertMargin + 5 * outerRadius,innerRadius,innerPaint)
            canvas.drawCircle(dWidth / 2f,vertPadding + 2 * vertMargin + 5 * outerRadius,outerRadius,outerPaint)
        }
        //密码集合包含圆⑨,绘制对应的大圆和黑色小圆
        if(pwList.contains(9)){
            canvas.drawCircle(dWidth -  landsMargin - outerRadius,vertPadding + 2 * vertMargin + 5 * outerRadius,innerRadius,innerPaint)
            canvas.drawCircle(dWidth -  landsMargin - outerRadius,vertPadding + 2 * vertMargin + 5 * outerRadius,outerRadius,outerPaint)
        }
    }
    

    /**
     * 绘制解锁连线
     */
    private fun drawUnlockPath(canvas: Canvas) {
        for(i in 0 until pointList.size){
        	//密码长度为1
            if(pointList.size == 1){
                canvas.drawLine(pointList[0].x,pointList[0].y,moveX,moveY,linePaint)
            }
            //处理最后一个点
            if(i == pointList.size - 1){
                canvas.drawLine(pointList[i].x,pointList[i].y,moveX,moveY,linePaint)
            }else{
                 //连接所有的点
                 canvas.drawLine(pointList[i].x,pointList[i].y,pointList[i+1].x,pointList[i+1].y,linePaint)
            }
        }
    }
    

手势操作的三个阶段:

  • 手指按下: 手势操作触发onTouchEvent,当手指按下时调用checkPressPos校验当前手指按下的位置在不在9个大圆的坐标范围内,如果在范围内,将圆对应的标识1-9添加到密码管理集合pwList中,将选中的圆的圆心坐标pointF添加到pointList中,后期用于绘制连线path,是否移动标志位isMove置为false,表示非移动状态。

  • 手指滑动: 当手指在锁盘上滑动时也调用checkPressPos,所以在方法中增加了判断,如果手指滑动选中的圆已经被选中了,那么将不再重复添加到集合中,是否移动标志位isMove标志位置为true

  • 手指抬起: 当手指抬起时,校验密码,清空两个集合数据后调用invalidate()触发系统重新绘制。

校验密码逻辑相对简单,这里使用pwTempList临时集合来生成密码字符串,在手指抬起时候pwList已经清空,需要重新绘制UI


   /**
     * 校验手势密码
     */
    private fun checkPassword() {
        if(pwTempList.size in 1..5){
            ctx.toast(ctx.getString(R.string.at_least_6_dots),Toast.LENGTH_SHORT)
            return
        }
        if(pwTempList.size >= 6){
            val sb = StringBuilder()
            pwTempList.forEach { sb.append(it) }
            if(sb.toString() == "1478965"){
                ctx.toast(ctx.getString(R.string.pw_correct),Toast.LENGTH_SHORT)
            }else{
                ctx.toast(ctx.getString(R.string.pw_error),Toast.LENGTH_SHORT)
            }
        }
    }
    

如果连接点不超过6个提示最少6个点,如果超过6个点则生成密码字符串进行对比,我们看下自定义后的效果。


<androidx.constraintlayout.widget.ConstraintLayout 	     	 
xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white">

    <com.ho.customview.widget.PatternLockView
        android:layout_width="match_parent"
        android:layout_height="342dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
        
</androidx.constraintlayout.widget.ConstraintLayout>


结尾

新年快乐~

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

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

相关文章

【技术推荐】前端JS攻防对抗

简介 网络爬虫一直以来是让网站维护人员头痛的事情&#xff0c;即要为搜索引擎开方便之门&#xff0c;提升网站排名、广告引入等&#xff0c;又要面对恶意爬虫做出应对措施&#xff0c;避免数据被非法获取&#xff0c;甚至出售。因此促生出爬虫和反爬虫这场旷日持久的战斗。 爬…

Java中的Arrays类

1、问题Arrays类是什么&#xff0c;Arrays常用方法。2、方法了解Arrays类的概念Arrays 位于java.util包下,Arrays是一个操作数组的工具类。Arrays常用方法Arrays.fill&#xff1a;替换数组原元素&#xff1b;Arrays.sort:对数组进行排序&#xff08;递增&#xff09;&#xff1…

23种设计模式(六)——装饰模式【单一职责】

文章目录意图什么时候使用装饰真实世界类比装饰模式的实现装饰模式的优缺点亦称&#xff1a; 装饰者模式、装饰器模式、Wrapper、Decorator 意图 装饰者模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象扩展新的功能&#xff0c;同时不改变其结构。主要解决…

Allegro如何快速找到差分不耦合处操作指导

Allegro如何快速找到差分不耦合处操作指导 做PCB设计的时候,需要检查差分对不耦合的地方,让差分不耦合的地方高亮出来 具体操作如下 用Allegro172版本打开pcb,选择View选择Vision Manager

抖快社交,变道求生

配图来自Canva可画 抖音、快手再一次杀回了社交市场。 2022年12月底&#xff0c;快手App store版本更新&#xff0c;在原有的快手热榜、朋友动态、快手拍摄的基础上&#xff0c;新增亲密贴贴、快手直播等新锁屏组件&#xff0c;通过强化产品的交互功能&#xff0c;增强用户的…

针对游戏开发CG制作的搬砖人员的资源搜索技巧分享—【持续补充篇】

一.常用搜索技巧分享 1.视频参考类(bilibili,youtube,常用的视频官网,其实可以满足了,再不行就在百度/Google搜一下) 2.教程和代码类 github Bootstrap Well magebox realtimevfx

Python项目(Django框架)天天生鲜在CentOS7.9搭建运行

CentOS安装python3 为方便管理&#xff0c;在CentOS桌面创建一个文件夹&#xff0c;将软件包下载到这里&#xff0c;右键--在终端打开 安装python3.9.7 : wget https://www.python.org/ftp/python/3.9.7/Python-3.9.7.tgz &#xff08;命令前的sudo如果是root用户可以去掉&…

深度学习目标检测基础_sigmoid和softmax函数

文章目录sigmoid和softmaxsigmoid函数softmax函数总结sigmoid和softmax sigmoid和softmax都是分类函数&#xff0c;他们的区别如下 sigmoid函数 Sigmoid 多标签分类问题多个正确答案非独占输出&#xff08;例如胸部X光检查、住院&#xff09;。构建分类器&#xff0c;解决有…

威纶通触摸屏配方功能的使用方法示例

威纶通触摸屏配方功能的使用方法示例 本次和大家分享通过触摸屏内部指针+偏移地址+控制元件实现配方功能的具体方法, 另外以前给大家分享过利用宏指令实现配方功能的方法,具体可参考以下链接中的内容: 威纶通触摸屏的配方功能具体使用方法介绍(宏指令写入PLC) 如下图所示…

Dubbo 服务引用

Dubbo 服务引用 0. 概述 Dubbo 服务引用的时机有两个&#xff0c;第一个是在 Spring 容器调用 ReferenceBean 的 afterPropertiesSet 方法时引用服务&#xff0c;第二个是在 ReferenceBean 对应的服务被注入到其他类中时引用。这两个引用服务的时机区别在于&#xff0c;第一个…

锅圈的新消费“第三条路”走得通吗?

文|螳螂观察 作者|kinki 临近春节&#xff0c;线下餐饮行业在经历了三年的寒冬之后&#xff0c;相信会在今年迎来一个“暖春”。不过&#xff0c;年夜饭一直存在“一桌难求”的现象&#xff0c;结合疫情因素&#xff0c;相信今年仍有不少消费会选择在家用餐。 因此&#xff…

生成随机用户名的测试数据

大家好&#xff0c;才是真的好。 记得我们以前讲过一篇《自动批量生成Notes应用测试数据&#xff01;》&#xff0c;利用Java自动生成大批量的测试数据&#xff0c;今天我们介绍使用LotusScript代码来实现自动生成随机数据&#xff0c;主要是随机的用户名。 我们的方法很简单…

〖百宝书-思维锻炼②〗——知识是人类的供需和营养品

大家好&#xff0c;我是涵子&#xff0c;今天我们来聊聊知识。 &#x1f4ac; 人生格言&#xff1a;Stay foolish, stay kind.&#x1f4ac; &#x1f4eb; 如果文章知识点有错误的地方&#xff0c;请指正&#xff01;和大家一起学习&#xff0c;一起进步&#x1f440; &#x…

Feed 流系统

差不多十年前&#xff0c;随着功能机的淘汰和智能机的普及&#xff0c;互联网开始进入移动互联网时代&#xff0c;最具代表性的产品就是微博、微信&#xff0c;以及后来的今日头条、快手等。这些移动互联网时代的新产品在过去几年间借着智能手机的风高速成长。 这些产品都是Fee…

VueJs中的shallowRef与shallowReactive的使用比较

01shallowRef()函数如果传入基本数据类型,那么shallowRef与ref的作用基本没有什么区别,也就是浅层的ref的内部值将会原样的存储和暴露,并不会被深层递归地转为响应式但如果是对象的话,那么就存在区别了的,shallowRef不处理对象类型的数据其实,它就是只处理基本数据类型的响应式…

从 JMM 透析 volatile 与 synchronized 原理

在面试、并发编程、一些开源框架中总是会遇到 volatile 与 synchronized 。synchronized 如何保证并发安全&#xff1f;volatile 语义的内存可见性指的是什么&#xff1f;这其中又跟 JMM 有什么关系&#xff0c;在并发编程中 JMM 的作用是什么&#xff0c;为什么需要 JMM&#…

信用评分分卡简介introduction of credit score card

背景 随着金融科技初创企业的兴起&#xff0c;过去 5 年中出现了许多新的消费信贷机构&#xff0c;与传统银行展开竞争。他们通常瞄准银行认为规模太小或因金融危机期间发生的后期损失而不得不削减贷款的细分市场。通俗的讲就是消费金融公司瞄准了银行的次贷市场。 这些新的消…

修改Pom文件需要注意的问题

1.从远程nuxaus拉不回来个别包该如何解决 进入仓库目录下&#xff0c;把该包的目录删除了&#xff0c;重新拉 rm -r 包目录 如果还是不行&#xff0c;可能是idea内存不够&#xff0c;尝试关闭暂时不用但是已经打开的项目&#xff0c;减少内存使用&#xff0c;删除包目录重试…

肌电信号采集电路分析

最近在开发肌电信号的采集&#xff0c;表面肌电信号是非常微弱的生物信号&#xff0c;正常人体表面肌电信号赋值为0--1.5mV&#xff0c;主要能量频段集中在10--150Hz。电路主要是根据原始信号&#xff0c;设计相应的放大电路、滤波电路&#xff0c;下面直接放原理图说明。一级放…

生物素点击试剂1255942-07-4,DBCO-PEG4-Biotin,生物素-PEG4-二苯基环辛炔

中英文别名&#xff1a;CAS号&#xff1a;1255942-07-4| 英文名&#xff1a;DBCO-PEG4-Biotin |中文名&#xff1a;二苯基环辛炔-PEG4-生物素&#xff0c;二苯基环辛炔-四聚乙 二醇-生物素物理参数&#xff1a;CASNumber&#xff1a;1255942-07-4Molecular formula&#xff1a;…