自定义Veiw实战《渐变的文字》

news2024/10/6 10:12:57

自定义Veiw实战《渐变的文字》

  • 前言
  • SpannableString
    • 什么时候使用
    • 常用场景
  • 自定义TextView控件
    • 什么时候使用
    • 实战歌词渐变的文字
      • 先看效果
      • 第一步:初始化
      • 第二步:测量文字,并确认文字绘制的起点
      • 第三步:绘制文字
      • 第四步:调用
  • 总结:完整代码

前言

首先跟文字相关的,我们大多数会使用TextView来解决,但是我们的TextView实现的效果又很固定。
当我们想实现一些独特的效果的时候,大多数为两种方法

1、一种是系统提供给我们的API:SpannableString
2、第二种是:自定义View

本文结构为:简单说一下SpannableString,之后实战用自定义View实现歌词效果。
为什么要讲一下SpannableString,因为很多人不知道这个API会直接想去自定义View把问题搞复杂。如果SpannableString能解决拿来用岂不是很舒服。

SpannableString

什么时候使用

有的时候,我们要给一个TextView中的显示的文字设置不同的样式或者响应事件,比如同一个TextView中,有的字是红色,有的字是蓝色,有的字点击之后有响应事件,有的点击之后没有响应事件,甚至我们想在TextView中显示一个数学公式等等,这个时候就需要使用SpannableString来解决这个问题。(当然HTML也可以)
比较常见的地方:所有APP的权限同意,都是不同颜色的文字,并且点击协议可以跳转到协议界面。

常用场景

首先列举一下可以实现的场景再拿出来两个说一下使用:

1.设置TextView的背景颜色
2.给文本设置点击事件
3.设置文本颜色
4.设置删除线效果
5.设置下划线效果
6.在TextView中设置图片
7.基于X轴的缩放
8.设置字体粗体样式
9.上下标的使用
10.设置超链接

1、设置TextView的背景颜色

textView1 = findViewById<View>(R.id.textView1) as TextView
val ss = SpannableString("设置背景颜色")
ss.setSpan(
    BackgroundColorSpan(Color.parseColor("#FFD700")), 0,
    ss.length, Spanned.SPAN_EXCLUSIVE_INCLUSIVE
)
textView1.setText(ss)

首先拿到一个TextView,然后构造一个 SpannableString,构造方法中传入的参数就是我们要显示的文字,然后就是一个最重要的方法,通过setSpan来设置背景色,第一个参数是我们要设置的背景颜色,第二第三个参数是我们要给哪一段的文字设置背景(该段文字的startIndex和endIndex),最后一个参数有四个值:

    public static final int SPAN_INCLUSIVE_EXCLUSIVE = SPAN_MARK_MARK;
 
    public static final int SPAN_INCLUSIVE_INCLUSIVE = SPAN_MARK_POINT;
 
    public static final int SPAN_EXCLUSIVE_EXCLUSIVE = SPAN_POINT_MARK;

    public static final int SPAN_EXCLUSIVE_INCLUSIVE = SPAN_POINT_POINT;

1.前面包括,后面不包括,即在文本前插入新的文本会应用该样式,而在文本后插入新文本不会应用该样式
2.前面包括,后面包括,即在文本前插入新的文本会应用该样式,而在文本后插入新文本也会应用该样式
3.前面不包括,后面不包括
4.前面不包括,后面包括

2、给文本设置点击事件
如果我们只想给一个TextView中的某几个文字设置点击事件,而不想给整个TextView设置点击事件,那么该怎么做?看下面的代码

textView2 = findViewById<View>(R.id.textView2) as TextView
val ss = SpannableString("点我吧123456")
ss.setSpan(object : ClickableSpan() {
    override fun onClick(widget: View) {
        Toast.makeText(this, "点我呀", Toast.LENGTH_SHORT)
            .show()
    }
}, 0, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
textView2.setText(ss)
// 设置tv2为可点击状态
textView2.setMovementMethod(LinkMovementMethod.getInstance())

setSpan方法中,第一个参数是一个ClickableSpan对象,这里有一个onClick方法,该方法中就是我们对点击事件的响应,后面几个参数跟前面一样,是位置和模式。
行就说到这,还需要什么场景就去查一下吧。

自定义TextView控件

什么时候使用

说白了就是TextView和SpannableString实现不了效果的时候,比如我想实现一个跟进度条联动的渐变歌词。

实战歌词渐变的文字

先看效果

在这里插入图片描述

核心思想:
画布canvas有一个方法canvas.clipRect(),调用了这个方法后接下来只会在这个区域内画内容,超出这个区域的内容就不画了。那么对于我们歌词渐变。
我们先用默认颜色画出全部文本,然后呢,根据变量progress(渐变比例,范围[0,1])和方向direction(确定从左到右渐变还是从右到左)计算出要变色的区域,然后用渐变颜色再画一次文本即可。

开始实现:(后面会附带完整的代码)

第一步:初始化

自定义View首先要初始化我们的自定义属性,
自定义属性CustomTextView
attr.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--第一步-->
    <declare-styleable name="CustomTextView">
        <attr name="text" format="string"/>
        <attr name="text_size" format="dimension" />
        <attr name="text_origin_color" format="color|reference" />
        <attr name="text_change_color" format="color|reference" />
        <attr name="progress" format="float" />
        <attr name="direction">
            <enum name="left" value="0" />
            <enum name="right" value="1" />
            <enum name="top" value="2" />
            <enum name="bottom" value="3" />
        </attr>
    </declare-styleable>
</resources>

使用时在XML中设置我们的自定义属性

<com.example.meng.view.CustomTextView
    android:id="@+id/tv_content"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:background="#44ff0000"
    android:padding="10dp"
    mql:progress="0"
    mql:text="小孟来码-Android"
    mql:text_change_color="#ffff0000"
    mql:text_origin_color="#ff000000"
    mql:text_size="20sp" />

CustomTextView构造函数中获取

//XML中正常使用时候
constructor(context: Context, attrs: AttributeSet) : super(context, attrs){
    //初始化
    val at = context.obtainStyledAttributes(attrs, R.styleable.CustomTextView)
    mText = at.getString(R.styleable.CustomTextView_text) ?: ""
    textSize = at.getDimension(R.styleable.CustomTextView_text_size, SizeUtil.spToPx(context, 16f))
    defaultColor = at.getColor(R.styleable.CustomTextView_text_origin_color, defaultColor)
    changeColor = at.getColor(R.styleable.CustomTextView_text_change_color, changeColor)
    direction = at.getInt(R.styleable.CustomTextView_direction, DIRECTION_LEFT)
    progress = at.getFloat(R.styleable.CustomTextView_progress, 0f)
    at.recycle()
    initPaint()
}

private fun initPaint() {
    paint.textSize = textSize
}

上面就成功的通过自定义的属性获取到了我们需要的自定义属性

第二步:测量文字,并确认文字绘制的起点

这里说一下我们利用draw去绘制文字时,他的起始坐标的问题。

drawText(String text, float x, float y, Paint paint)

方法的参数很简单: text 是文字内容,x 和 y 是文字的坐标。但需要注意:这个坐标并不是文字的左上角,而是一个与左下角比较接近的位置。大概在这里:
在这里插入图片描述
记住这个来看下面获取宽度高度和找起点坐标的代码吧

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

    val width = measure(widthMeasureSpec, true)
    val height = measure(heightMeasureSpec, false)
    setMeasuredDimension(width, height)

    // 绘制Text的起始坐标 这是为了将文字水平居中对齐。
    // 首先,将控件的中心点作为起始点,即getMeasuredWidth() / 2
    // 然后,将文本的宽度除以2,即mTextWidth / 2
    // 得到文本的一半宽度。最后,将文本的一半宽度从起始点左移,
    // 即mTextStartX = getMeasuredWidth() / 2 - mTextWidth / 2,就可以将文本水平居中对齐
    textStartX = measuredWidth / 2 - textWidth / 2
    textStartY = measuredHeight / 2 + textHeight / 2
}

private fun getMeasuredText() {
    //获取文字高度,设置给onMeasure 需要告诉View画多大
    //这里如果你是继承的TextView那么这个可以不用做,因为TextView中的onMeasure会帮你做好。
    val rect = Rect()
    paint.getTextBounds(mText, 0, mText.length, rect)
    textHeight = rect.height()
    textWidth = paint.measureText(mText).toInt()
}

private fun measure(measureSpec: Int, isWidth: Boolean): Int {
    val mode = MeasureSpec.getMode(measureSpec)
    val size = MeasureSpec.getSize(measureSpec)
    var result: Int = 0

    when (mode) {
        //精准模式
        MeasureSpec.EXACTLY -> {
            result = size
        }

        //最大模式  未指定
        MeasureSpec.AT_MOST, MeasureSpec.UNSPECIFIED -> {
            result = if (isWidth) {
                textWidth
            } else {
                textHeight
            }
        }
    }
    return if (isWidth) result + paddingLeft + paddingRight else result + paddingTop + paddingBottom
}

第三步:绘制文字

绘制文字就是利用canvas.drawText去绘制了。
使用canvas.clipRect()去控制区域,可以看到他的参数

public boolean clipRect(int left, int top, int right, int bottom)

顾名思义就是区域的四个顶点了。通过这个就可以去控制他的区域了
之后就是计算出来他的绘制区域,这里是通过progress来进行计算。
比如textStartX + progress * textWidth:就是起始的X加上progress(0 - 1) 乘 全部字体的宽度。
我们通过改变progress就能控制他的绘制的结束位置。
代码如下:

override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    if (direction == DIRECTION_LEFT){
        drawChangeLeft(canvas)
        drawOriginLeft(canvas)
    } else if (direction == DIRECTION_RIGHT){
        drawChangeRight(canvas)
        drawOriginRight(canvas)
    }
}

private fun drawChangeRight(canvas: Canvas) {
    drawText(canvas, changeColor, (textStartX + (1 - progress) * textWidth).toInt(), textStartX + textWidth)
}

private fun drawOriginRight(canvas: Canvas){
    drawText(canvas, defaultColor, textStartX, (textStartX + (1 - progress) * textWidth).toInt())
}

private fun drawChangeLeft(canvas: Canvas){
    drawText(canvas, changeColor, textStartX, (textStartX + progress * textWidth).toInt())
}

private fun drawOriginLeft(canvas: Canvas) {
    drawText(canvas, defaultColor, (textStartX + progress * textWidth).toInt(), textStartX + textWidth)
}

private fun drawText(canvas: Canvas, color: Int, startX: Int, endX: Int) {
    paint.color = color
    canvas.save()
    canvas.clipRect(startX, 0, endX, measuredHeight)
    canvas.drawText(mText, textStartX.toFloat(), textStartY.toFloat(), paint)
    canvas.restore()
}

//设置进度(动态的改变需要set这个属性)
fun setProgress(progress: Float) {
    this.progress = progress
    invalidate() //重绘
}

第四步:调用

MainActivity

setContentView(R.layout.activity_main)
val tvContent: CustomTextView = findViewById(R.id.tv_content)
val Button1: Button = findViewById(R.id.button_1)
val Button2: Button = findViewById(R.id.button_2)

Button1.setOnClickListener {
    tvContent.textDirection = 0
    ObjectAnimator.ofFloat(tvContent, "progress", 0f, 1f).setDuration(4000).start()
}

Button2.setOnClickListener {
    tvContent.textDirection = 1
    ObjectAnimator.ofFloat(tvContent, "progress", 1f, 0f).setDuration(4000).start()
}

总结:完整代码

不多逼逼,来拿代码
attr.xml的代码上面有,放在values下的attr.xml文件中就行
CustomTextView.kt

const val DIRECTION_LEFT = 0
const val DIRECTION_RIGHT = 1
const val DIRECTION_TOP = 2
const val DIRECTION_BOTTOM = 3

class CustomTextView : View {
    private var mText: String = "小孟来码"
    private var textSize = SizeUtil.spToPx(context, 30f)
    private var defaultColor: Int = 0xff000000.toInt()
    private var changeColor: Int = 0xffff0000.toInt()
    private var direction = DIRECTION_LEFT
    private var progress = 0f

    private var paint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)

    private var textHeight = 0
    private var textWidth = 0
    private var textStartX = 0
    private var textStartY = 0

    //利用对象创建的时候
    constructor(context: Context) : super(context)

    //XML中正常使用时候
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs){
        //初始化
        val at = context.obtainStyledAttributes(attrs, R.styleable.CustomTextView)
        mText = at.getString(R.styleable.CustomTextView_text) ?: ""
        textSize = at.getDimension(R.styleable.CustomTextView_text_size, SizeUtil.spToPx(context, 16f))
        defaultColor = at.getColor(R.styleable.CustomTextView_text_origin_color, defaultColor)
        changeColor = at.getColor(R.styleable.CustomTextView_text_change_color, changeColor)
        direction = at.getInt(R.styleable.CustomTextView_direction, DIRECTION_LEFT)
        progress = at.getFloat(R.styleable.CustomTextView_progress, 0f)
        at.recycle()
        initPaint()
    }

    private fun initPaint() {
        paint.textSize = textSize
    }

    private fun getMeasuredText() {
        //获取文字高度,设置给onMeasure 需要告诉View画多大
        //这里如果你是继承的TextView那么这个可以不用做,因为TextView中的onMeasure会帮你做好。
        val rect = Rect()
        paint.getTextBounds(mText, 0, mText.length, rect)
        textHeight = rect.height()
        textWidth = paint.measureText(mText).toInt()
    }

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

        val width = measure(widthMeasureSpec, true)
        val height = measure(heightMeasureSpec, false)
        setMeasuredDimension(width, height)

        // 绘制Text的起始坐标 这是为了将文字水平居中对齐。
        // 首先,将控件的中心点作为起始点,即getMeasuredWidth() / 2
        // 然后,将文本的宽度除以2,即mTextWidth / 2
        // 得到文本的一半宽度。最后,将文本的一半宽度从起始点左移,
        // 即mTextStartX = getMeasuredWidth() / 2 - mTextWidth / 2,就可以将文本水平居中对齐
        textStartX = measuredWidth / 2 - textWidth / 2
        textStartY = measuredHeight / 2 + textHeight / 2
    }

    private fun measure(measureSpec: Int, isWidth: Boolean): Int {
        val mode = MeasureSpec.getMode(measureSpec)
        val size = MeasureSpec.getSize(measureSpec)
        var result: Int = 0

        when (mode) {
            //精准模式
            MeasureSpec.EXACTLY -> {
                result = size
            }

            //最大模式  未指定
            MeasureSpec.AT_MOST, MeasureSpec.UNSPECIFIED -> {
                result = if (isWidth) {
                    textWidth
                } else {
                    textHeight
                }
            }
        }
        return if (isWidth) result + paddingLeft + paddingRight else result + paddingTop + paddingBottom
    }


    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        if (direction == DIRECTION_LEFT){
            drawChangeLeft(canvas)
            drawOriginLeft(canvas)
        } else if (direction == DIRECTION_RIGHT){
            drawChangeRight(canvas)
            drawOriginRight(canvas)
        }
    }

    private fun drawChangeRight(canvas: Canvas) {
        drawText(canvas, changeColor, (textStartX + (1 - progress) * textWidth).toInt(), textStartX + textWidth)
    }

    private fun drawOriginRight(canvas: Canvas){
        drawText(canvas, defaultColor, textStartX, (textStartX + (1 - progress) * textWidth).toInt())
    }

    private fun drawChangeLeft(canvas: Canvas){
        drawText(canvas, changeColor, textStartX, (textStartX + progress * textWidth).toInt())
    }

    private fun drawOriginLeft(canvas: Canvas) {
        drawText(canvas, defaultColor, (textStartX + progress * textWidth).toInt(), textStartX + textWidth)
    }

    private fun drawText(canvas: Canvas, color: Int, startX: Int, endX: Int) {
        paint.color = color
        canvas.save()
        canvas.clipRect(startX, 0, endX, measuredHeight)
        canvas.drawText(mText, textStartX.toFloat(), textStartY.toFloat(), paint)
        canvas.restore()
    }

    //设置进度(动态的改变需要set这个属性)
    fun setProgress(progress: Float) {
        this.progress = progress
        invalidate() //重绘
    }
}

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:mql="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.example.meng.view.CustomTextView
        android:id="@+id/tv_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:background="#44ff0000"
        android:padding="10dp"
        mql:progress="0"
        mql:text="小孟来码-Android"
        mql:text_change_color="#ffff0000"
        mql:text_origin_color="#ff000000"
        mql:text_size="20sp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:gravity="center"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/button_1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="StartLeft" />

        <Button
            android:id="@+id/button_2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_toRightOf="@id/button_1"
            android:text="StartRight" />
    </LinearLayout>

</RelativeLayout>

MainActivity.kt

class MainActivity : AppCompatActivity(){
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val tvContent: CustomTextView = findViewById(R.id.tv_content)
        val Button1: Button = findViewById(R.id.button_1)
        val Button2: Button = findViewById(R.id.button_2)

        Button1.setOnClickListener {
            tvContent.textDirection = 0
            ObjectAnimator.ofFloat(tvContent, "progress", 0f, 1f).setDuration(4000).start()
        }

        Button2.setOnClickListener {
            tvContent.textDirection = 1
            ObjectAnimator.ofFloat(tvContent, "progress", 1f, 0f).setDuration(4000).start()
        }
    }
}

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

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

相关文章

Node.js安装及npm国内镜像配置

node.js中文网站下载&#xff0c;以16.17为例&#xff01;&#xff01;&#xff01;&#xff01; 安装 1.网站链接 CNPM Binaries Mirror (npmmirror.com) 根据自己的版本选择&#xff0c;我是64位选择了zip版 2.下载完成后解压 我选择的目录是&#xff08;E:\Environments…

mac中在html中引入react.development.js、react-dom.development.js报错

错误描述 Uncaught ReferenceError: process is not definedUncaught Invariant Violation: ReactDOM was loaded before React. Make sure you load the React package before loading ReactDOM.Inline Babel script:3 Uncaught ReferenceError: React is not defined解决 1…

react中数组列表的简单新增,删除以及修改实践

react中数组列表的简单新增&#xff0c;删除以及修改实践 效果示例图示例代码 index.jsx示例样式 index.scss 效果示例图 新增图片 编辑图片 示例代码 index.jsx import { useEffect, useState } from "react"; import "./index.scss";// 创建数据 fu…

WebGIS 信息系统-数据库设计

WebGIS 信息系统-数据库设计 E-R 图设计创建数据库及数据表开发环境及环境配置1 .服务器端2. 客户端1 &#xff09;配置Struts22 &#xff09;配置Hibernate3 &#xff09;配置Spring4 &#xff09;配置Web . xml 基于GIS 的交通信息系统采用PostgreSQL 为属性数据库&#xff0…

虚拟机中Ubuntu 22上传框被黑框包裹的解决方法

虚拟机中Ubuntu 22上传框被黑框包裹的解决方法 现象解决方法 现象 在vm17下的ubuntu22使用上传表单时出现了这种不和谐的现象&#xff0c;被领导批评一通。最后费劲心思&#xff0c;找到了这个问题的解决方法。 解决方法 解决方法特别容易&#xff0c;在虚拟机的设置中&…

TypeScript 【type】关键字的进阶使用方式

导语&#xff1a; 在前面章节中&#xff0c;我们了解到 TS 中 type 这个关键字&#xff0c;常常被用作于&#xff0c;定义 类型别名&#xff0c;用来简化或复用复杂联合类型的时候使用。同时也了解到 为对象定义约束接口类型 的时候所使用的是 Interfaces。 其实对于前面&#…

ansible - 安装 -【kodcloud教程】

目录 目录结构、主机清单 【1】安装基础环境 【2】webserver - 安装nginx 【3】安装php环境 【4】lb-server 【5】redis安装 【6】 kodcloud 【7】wordpress-proxy ansible10.0.0.10lb-server10.0.0.11web0110.0.0.15web0210.0.0.16redis10.0.0.20 目录结构、主机清单…

[python][yolov7][深度学习]将yolov7实例分割成一个类几句代码完成实例分割任务

大家都知道,yolov7目前支持图像分类、目标检测和实例分割&#xff0c;而实例分割一般都是用predict.py去预测图片这个如果要引入pyqt5或着嵌入其他python模块有点麻烦&#xff0c;因此需要封装一个类去预测图像&#xff0c;这样我们可以轻松完成各种实例分割任务&#xff0c;封…

virtualbox安装已有的虚拟硬盘文件

按照网上安装virtualbox虚拟机操作&#xff0c;我是安装已有的虚拟硬盘文件。 名称是虚拟机的名称&#xff0c;文件夹是虚拟机安装的文件夹建议大一点。 分配内存&#xff1a; 对于第一次安装已有的vdi虚拟硬盘文件&#xff0c;这里并没有任何显示&#xff08;我下面已经添…

EA代码逆向工程

下载安装 链接&#xff1a;https://pan.baidu.com/s/1xQ2q-_cSt_DTI3zIDvxkFw 提取码&#xff1a;wq83 使用教程&#xff1a; 构建类图 打开EA&#xff0c;点击左上角的图标新建项目。 起一个项目名称&#xff0c;"逆向工程测试"。 新建好后的页面&#xff1a; …

Bootstrap 网格系统

文章目录 Bootstrap 网格系统什么是网格&#xff08;Grid&#xff09;&#xff1f;什么是 Bootstrap 网格系统&#xff08;Grid System&#xff09;&#xff1f;移动设备优先策略内容布局渐进增强 Bootstrap 网格系统&#xff08;Grid System&#xff09;的工作原理媒体查询网格…

自学黑客(网络安全),一般人我劝你还是算了吧(自学网络安全学习路线--第十一章 网络安全技术下)【建议收藏】

文章目录 一、自学网络安全学习的误区和陷阱二、学习网络安全的一些前期准备三、自学网络安全学习路线一、入侵检测系统1、入侵检测系统模型2、入侵检测系统分类3、入侵检测系统部署 二、VPN1、VPN工作原理2、VPN的优点3、VPN的分类4、VPN的工作原理5、VPN的主要技术 一、自学网…

使用OpenXML库替换docx文档(Word文档)中的特定字段

在批量生成Word文档的应用中&#xff0c;最常见的需求莫过于替换掉文档中的特定字段以生成新的文档。利用OpenXML库可轻松实现这一需求。 不完善版本 首先放出最简单然而有bug的版本&#xff1a; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wor…

第6讲:使用ajax技术实现模拟百度搜索功能(xml数据)

使用ajax技术实现模拟百度搜索功能&#xff0c;本案例使用原生态xmlhttprequest对象&#xff0c;GET方法通讯&#xff0c;后台使用map保存搜索数据&#xff0c;查询到对应数据后&#xff0c;返回xml格式数据&#xff0c;前端使用responseXML属性返回xml格式数据&#xff0c;结合…

6.安卓移动端开发

开发概览 Android官网 提供了开发环境&#xff0c;也就是android平台&#xff0c;即android SDK&#xff0c;即android版本 SDK版本和API版本的关系&#xff08;安卓的版本是个位数和小数形式增长&#xff0c;API版本是以个位数正则&#xff0c;所以API版本号和android版本号不…

图像梯度——Sobel、Scharr、Laplacian

图像梯度-Sobel算子 dst cv2.Sobel(src, ddepth, dx, dy, ksize) src: 图像数组变量ddepth: 图像的深度&#xff0c;一般填-1&#xff0c;表示与原始图像深度一致&#xff1b; cv2.CV_64F表示每一个像素点值为64位浮点数&#xff0c;是OpenCV定义的数据类型dx和dy分别表示水平…

车端服务器架构「升级」

过去几年&#xff0c;随着整车电子架构从分布式向集中式升级&#xff0c;域控制器&#xff08;通常分为五大域&#xff1a;动力域、底盘域、座舱域、智驾域、车身域&#xff09;带动供应链进入增值周期&#xff0c;背后隐藏的则是供应商的洗牌。 以座舱为例&#xff0c;从传统的…

远程桌面发生身份验证错误,要求的函数不受支持

windows10专业版&#xff1a; 解决方法&#xff1a; 使用微软官方建议修改本地组策略&#xff1a; winr弹出运行窗口&#xff0c;输入gpedit.msc,打开本地组策略 计算机配置>管理模板>系统>凭据分配>加密Oracle修正 选择启用并选择易受攻击。 windows10家庭版&a…

Bug - 为什么不能打开Tmocat官网

今天在敲代码的时候碰到一个bug&#xff0c;登录不上Tmocat官网&#xff0c;后来查了查是不能使用代理模式进行连接网站&#xff1a; 解决方法&#xff0c;换成手机WIFE热点&#xff1a; 登录成功&#xff1a; 小开心^_^

445端口是啥?445端口怎么关闭?

445端口是Windows系统中的SMB协议&#xff0c;用于文件共享和网络打印功能。然而&#xff0c;这个端口也是黑客攻击的重要入口之一。那么&#xff0c;如何关闭445端口&#xff0c;保护自己的计算机安全呢&#xff1f; 关闭445端口的方法 1.在“控制面板”中打开“管理员工具”…