鸿蒙开发入门day16-拖拽事件和手势事件

(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,还请三连支持一波哇ヾ(@^∇^@)ノ)

目录

拖拽事件

概述

拖拽流程

​手势拖拽

​鼠标拖拽

拖拽背板图

开发步骤

通用拖拽适配

多选拖拽适配

手势事件

gesture(常规手势绑定方法)

priorityGesture(带优先级的手势绑定方法)

parallelGesture(并行手势绑定方法)

单一手势

点击手势(TapGesture)

长按手势(LongPressGesture)

拖动手势(PanGesture)


拖拽事件

概述

拖拽框架提供了一种通过鼠标或手势触屏的方式传递数据,即从一个组件位置拖出数据,并拖入到另一个组件位置上进行响应,拖出一方提供数据,拖入一方接收和处理数据。该操作可以让用户方便地移动、复制或删除指定内容。

  • 拖拽操作:在某个能够响应拖出的组件上长按并滑动触发的拖拽行为,当用户释放时,拖拽操作结束;
  • 拖拽背景(背板):用户所拖动数据的形象化表示,开发者可通过onDragStart的CustomerBuilder或DragItemInfo设置,也可以通过dragPreview通用属性设置;
  • 拖拽内容:拖动的数据,使用UDMF统一API UnifiedData 进行封装;
  • 拖出对象:触发拖拽操作并提供数据的组件;
  • 拖入目标:可接收并处理拖动数据的组件;
  • 拖拽点:鼠标或手指等与屏幕的接触位置,是否进入组件范围的判定是以接触点是否进入范围进行判断。

拖拽流程

​手势拖拽

​对于手势长按触发拖拽的场景,发起拖拽前框架侧会对当前组件是否可拖拽进行校验,针对默认可拖出的组件(Search、TextInput、TextArea、RichEditor、Text、Image、Hyperlink)需要判断是否设置了draggable属性为true(若系统使能分层参数,则draggable默认为true),其他组件需要额外判断是否设置了onDragStart回调函数,在满足上述可拖拽条件下,长按大于等于500ms可触发拖拽,长按800ms开始做预览图的浮起动效。

手势拖拽(手指/手写笔)触发拖拽流程:

​鼠标拖拽

鼠标拖拽属于即拖即走,只要鼠标左键在可拖拽的组件上按下并移动大于1vp就可触发拖拽。

当前支持应用内和跨应用拖拽,提供了多个回调事件供开发者感知拖拽状态并干预系统默认拖拽行为,具体如下:

回调事件说明
onDragStart

支持拖出的组件产生拖出动作时触发。

该回调可以感知拖拽行为的发起,开发者可通过在 onDragStart 方法中设置拖拽所传递的数据以及自定义拖拽背板图。推荐开发者使用pixelmap的方式返回背板图,不推荐使用customBuilder的方式,会有额外的性能开销。

onDragEnter当拖拽活动的拖拽点进入组件范围内时触发,只有该组件监听了onDrop事件时,此回调才会被触发。
onDragMove

拖拽点在组件范围内移动时触发;只有该组件监听了onDrop事件时,此回调才会被触发。

在此过程中可通过DragEvent中的setResult方法影响系统部分场景下的外观

1. 设置DragResult.DROP_ENABLED;

2. 设置DragResult.DROP_DISABLED。

onDragLeave

拖拽点离开组件范围时触发;只有该组件监听了onDrop事件时,此回调才会被触发。

针对以下两种情况默认不会发送onDragLeave事件:

1. 父组件移动到子组件;

2. 目标组件与当前组件布局有重叠;

API version 12开始可通过UIContext中的setDragEventStrictReportingEnabled方法严格触发onDragLeave事件。

onDrop

当用户在组件范围内释放时触发,需在此回调中通过DragEvent中的setResult方法设置拖拽结果,否则在拖出方组件的onDragEnd方法中通过getResult方法只能拿到默认的处理结果DragResult.DRAG_FAILED。

该回调也是开发者干预系统默认拖入处理行为的地方,系统会优先执行开发者的onDrop回调,通过在回调中执行setResult方法来告知系统该如何处理所拖拽的数据;

1. 设置 DragResult.DRAG_SUCCESSFUL,数据完全由开发者自己处理,系统不进行处理;

2. 设置DragResult.DRAG_FAILED,数据不再由系统继续处理;

3. 设置DragResult.DRAG_CANCELED,系统也不需要进行数据处理;

4. 设置DragResult.DROP_ENABLED或DragResult.DROP_DISABLED会被忽略,同设置DragResult.DRAG_FAILED;

onDragEnd当用户释放拖拽时,拖拽活动结束,发起拖出动作的组件会触发该回调。
onPreDrag

绑定此事件的组件,当触发拖拽发起前的不同阶段时,触发回调。

开发者可以使用该方法监听PreDragStatus中的枚举在发起拖拽前的不同阶段准备数据。

1. ACTION_DETECTING_STATUS:拖拽手势启动阶段。(按下50ms时触发);

2. READY_TO_TRIGGER_DRAG_ACTION:拖拽准备完成,可发起拖拽阶段。(按下500ms时触发);

3. PREVIEW_LIFT_STARTED:拖拽浮起动效发起阶段。(按下800ms时触发);

4. PREVIEW_LIFT_FINISHED:拖拽浮起动效结束阶段。(浮起动效完全结束时触发);

5. PREVIEW_LANDING_STARTED:拖拽落回动效发起阶段。(落回动效发起时触发);

6. PREVIEW_LANDING_FINISHED:拖拽落回动效结束阶段。(落回动效结束时触发);

7. ACTION_CANCELED_BEFORE_DRAG:拖拽浮起落位动效中断。(已满足READY_TO_TRIGGER_DRAG_ACTION状态后,未达到动效阶段,手指抬手时触发)。

拖拽背板图

拖拽移动过程中显示的拖拽背板图,并非是组件本身,其是用户拖动数据的表示,开发者可以将其设置为任意可显示的图像。其中onDragStart 回调返回的customBuilder或pixelmap可以设置拖拽移动过程中的背板图,浮起图默认使用组件本身的截图;dragpreview属性设置的customBuilder或pixelmap可以设置浮起和拖拽过程的背板图;如果开发者没有配置背板图,则系统会默认取组件本身的截图作为浮起及拖拽过程中的背板图。

拖拽背板图当前支持设置透明度、圆角、阴影和模糊,具体用法见:拖拽控制

约束:

  • 对于容器组件,如果内部内容通过position,offset等手段使得绘制区域超出了容器组件范围,则系统截图无法截取到范围之外的内容,此种情况下,如果一定要浮起及拖拽背板能够包含范围之外的内容,则可考虑通过扩大容器范围或自定义方式进行;
  • 不管是使用自定义builder或是系统默认截图方式,截图都暂时无法应用scale、rotate等图形变换效果。

开发步骤

通用拖拽适配

如下以Image组件为例,介绍组件拖拽开发的基本步骤,以及开发中需要注意的事项。

组件使能拖拽

设置draggable属性为true,并设置onDragStart回调,回调中可以通过UDMF设置拖拽的数据,并返回自定义拖拽背板图;

import { unifiedDataChannel, uniformTypeDescriptor } from '@kit.ArkData';Image($r('app.media.app_icon')).width(100).height(100).draggable(true).onDragStart((event) => {let data: unifiedDataChannel.Image = new unifiedDataChannel.Image();data.imageUri = 'common/pic/img.png';let unifiedData = new unifiedDataChannel.UnifiedData(data);event.setData(unifiedData);let dragItemInfo: DragItemInfo = {pixelMap: this.pixmap,extraInfo: "this is extraInfo",};// onDragStart回调函数中返回自定义拖拽背板图return dragItemInfo;})

手势场景触发拖拽抵赖底层绑定的长按手势,若开发者在被拖拽组件上也绑定长按手势,则会与底层的长按手势发生竞争,导致拖拽失败。可以用并行手势解决解决此类问题,如下:

.parallelGesture(LongPressGesture().onAction(() => {promptAction.showToast({ duration: 100, message: 'Long press gesture trigger' });
}))

自定义拖拽背板图

自定义拖拽背板图的pixmap可以通过设置onPreDrag函数在长按50ms时触发的回调中前提准备;

.onPreDrag((status: PreDragStatus) => {if (preDragStatus == PreDragStatus.ACTION_DETECTING_STATUS) {this.getComponentSnapshot();}
})

具体pixmap的生成可以调用componentSnapshot.createFromBuilder函数;

@Builder
pixelMapBuilder() {Column() {Image($r('app.media.startIcon')).width(120).height(120).backgroundColor(Color.Yellow)}}private getComponentSnapshot(): void {componentSnapshot.createFromBuilder(()=>{this.pixelMapBuilder()},(error: Error, pixmap: image.PixelMap) => {if(error){console.log("error: " + JSON.stringify(error))return;}this.pixmap = pixmap;})
}

多选拖拽适配

API version 12开始Grid组件和List组件中的GridItem和ListItem组件支持多选拖拽,当前只支持onDragStart的方式。如下以Grid为例,介绍多选拖拽的基本步骤,以及开发中的注意事项。

组件多选拖拽使能

创建GridItem子组件并绑定onDragStart函数。同时设置GridItem组件的状态是可选中的;

Grid() {ForEach(this.numbers, (idx: number) => {GridItem() {Column().backgroundColor(this.colors[idx % 9]).width(50).height(50).opacity(1.0).id('grid'+idx)}.onDragStart(()=>{}).selectable(true)}, (idx: string) => idx)
}

多选拖拽功能默认为关闭状态,使用多选拖拽需要在dragPreviewOptions接口中的DragInteractionOptions参数中设置isMultiSelectionEnabled为true,表示当前组件是否多选。DragInteractionOptions也有支持组件浮起前默认效果的参数defaultAnimationBeforeLifting,设置该参数为true后组件在浮起前会有一个默认缩小动效。

.dragPreviewOptions({isMultiSelectionEnabled:true,defaultAnimationBeforeLifting:true})

为了保证选中状态,需要设置GridItem子组件selected状态为true。例如,可以通过onClick的调用去设置特定的组件为选中的状态。

.selected(this.isSelectedGrid[idx])
.onClick(()=>{this.isSelectedGrid[idx] = !this.isSelectedGrid[idx]
})

多选拖拽性能优化

多选拖拽情况下,多选会有聚拢的动画效果,聚拢效果触发时,会给当前屏幕内显示的选中组件截图,当选中组件过多,会导致很高的性能开销。多选拖拽支持从dragPreview中获取截图来作为聚拢动效的截图,以节省性能。

.dragPreview({pixelMap:this.pixmap
})

截图的获取可以在选中组件时通过调用componentSnapshot中的get方法获取。如下通过获取组件对应id的方法进行截图。

@State previewData: DragItemInfo[] = []
@State isSelectedGrid: boolean[] = []
.onClick(()=>{this.isSelectedGrid[idx] = !this.isSelectedGrid[idx]if (this.isSelectedGrid[idx]) {let gridItemName = 'grid' + idxcomponentSnapshot.get(gridItemName, (error: Error, pixmap: image.PixelMap)=>{this.pixmap = pixmapthis.previewData[idx] = {pixelMap:this.pixmap}})}
})

数量角标适配

多选拖拽的数量角标当前需要应用使用dragPreviewOptions中的numberBadge参数设置,开发者需要根据当前选中的节点数量来设置数量角标。

@State numberBadge: number = 0;.onClick(()=>{this.isSelectedGrid[idx] = !this.isSelectedGrid[idx]if (this.isSelectedGrid[idx]) {this.numberBadge++;} else {this.numberBadge--;}
})
// 多选场景右上角数量角标需要应用设置numberBadge参数
.dragPreviewOptions({numberBadge: this.numberBadge})

手势事件

通过给各个组件绑定不同的手势事件,并设计事件的响应方式,当手势识别成功时,ArkUI框架将通过事件回调通知组件手势识别的结果。

gesture(常规手势绑定方法)

.gesture(gesture: GestureType, mask?: GestureMask)

gesture为通用的一种手势绑定方法,可以将手势绑定到对应的组件上。

例如,可以将点击手势TapGesture通过gesture手势将方法绑定到Text组件上。

// xxx.ets
@Entry
@Component
struct Index {build() {Column() {Text('Gesture').fontSize(28)// 采用gesture手势绑定方法绑定TapGesture.gesture(TapGesture().onAction(() => {console.info('TapGesture is onAction');}))}.height(200).width(250)}
}

priorityGesture(带优先级的手势绑定方法)

.priorityGesture(gesture: GestureType, mask?: GestureMask)

priorityGesture是带优先级的手势绑定方法,可以在组件上绑定优先识别的手势。

在默认情况下,当父组件和子组件使用gesture绑定同类型的手势时,子组件优先识别通过gesture绑定的手势。当父组件使用priorityGesture绑定与子组件同类型的手势时,父组件优先识别通过priorityGesture绑定的手势。

长按手势时,设置触发长按的最短时间小的组件会优先响应,会忽略priorityGesture设置。

例如,当父组件Column和子组件Text同时绑定TapGesture手势时,父组件以带优先级手势priorityGesture的形式进行绑定时,优先响应父组件绑定的TapGesture。

// xxx.ets
@Entry
@Component
struct Index {build() {Column() {Text('Gesture').fontSize(28).gesture(TapGesture().onAction(() => {console.info('Text TapGesture is onAction');}))}.height(200).width(250)// 设置为priorityGesture时,点击文本区域会忽略Text组件的TapGesture手势事件,优先响应父组件Column的TapGesture手势事件.priorityGesture(TapGesture().onAction(() => {console.info('Column TapGesture is onAction');}), GestureMask.IgnoreInternal)}
}

parallelGesture(并行手势绑定方法)

.parallelGesture(gesture: GestureType, mask?: GestureMask)

parallelGesture是并行的手势绑定方法,可以在父子组件上绑定可以同时响应的相同手势。

在默认情况下,手势事件为非冒泡事件,当父子组件绑定相同的手势时,父子组件绑定的手势事件会发生竞争,最多只有一个组件的手势事件能够获得响应。而当父组件绑定了并行手势parallelGesture时,父子组件相同的手势事件都可以触发,实现类似冒泡效果。

// xxx.ets
@Entry
@Component
struct Index {build() {Column() {Text('Gesture').fontSize(28).gesture(TapGesture().onAction(() => {console.info('Text TapGesture is onAction');}))}.height(200).width(250)// 设置为parallelGesture时,点击文本区域会同时响应父组件Column和子组件Text的TapGesture手势事件.parallelGesture(TapGesture().onAction(() => {console.info('Column TapGesture is onAction');}), GestureMask.Normal)}
}

单一手势

点击手势(TapGesture)

TapGesture(value?:{count?:number, fingers?:number})

点击手势支持单次点击和多次点击,拥有两个可选参数:

  • count:声明该点击手势识别的连续点击次数。默认值为1,若设置小于1的非法值会被转化为默认值。如果配置多次点击,上一次抬起和下一次按下的超时时间为300毫秒。

  • fingers:用于声明触发点击的手指数量,最小值为1,最大值为10,默认值为1。当配置多指时,若第一根手指按下300毫秒内未有足够的手指数按下则手势识别失败。

    以在Text组件上绑定双击手势(count值为2的点击手势)为例:

// xxx.ets
@Entry
@Component
struct Index {@State value: string = "";build() {Column() {Text('Click twice').fontSize(28).gesture(// 绑定count为2的TapGestureTapGesture({ count: 2 }).onAction((event: GestureEvent|undefined) => {if(event){this.value = JSON.stringify(event.fingerList[0]);}}))Text(this.value)}.height(200).width(250).padding(20).border({ width: 3 }).margin(30)}
}

长按手势(LongPressGesture)

LongPressGesture(value?:{fingers?:number, repeat?:boolean, duration?:number})

长按手势用于触发长按手势事件,拥有三个可选参数:

  • fingers:用于声明触发长按手势所需要的最少手指数量,最小值为1,最大值为10,默认值为1。

  • repeat:用于声明是否连续触发事件回调,默认值为false。

  • duration:用于声明触发长按所需的最短时间,单位为毫秒,默认值为500。

以在Text组件上绑定可以重复触发的长按手势为例:

// xxx.ets
@Entry
@Component
struct Index {@State count: number = 0;build() {Column() {Text('LongPress OnAction:' + this.count).fontSize(28).gesture(// 绑定可以重复触发的LongPressGestureLongPressGesture({ repeat: true }).onAction((event: GestureEvent|undefined) => {if(event){if (event.repeat) {this.count++;}}}).onActionEnd(() => {this.count = 0;}))}.height(200).width(250).padding(20).border({ width: 3 }).margin(30)}
}

拖动手势(PanGesture)

PanGesture(value?:{ fingers?:number, direction?:PanDirection, distance?:number})

拖动手势用于触发拖动手势事件,滑动达到最小滑动距离(默认值为5vp)时拖动手势识别成功,拥有三个可选参数:

  • fingers:用于声明触发拖动手势所需要的最少手指数量,最小值为1,最大值为10,默认值为1。

  • direction:用于声明触发拖动的手势方向,此枚举值支持逻辑与(&)和逻辑或(|)运算。默认值为Pandirection.All。

  • distance:用于声明触发拖动的最小拖动识别距离,单位为vp,默认值为5。

以在Text组件上绑定拖动手势为例,可以通过在拖动手势的回调函数中修改组件的布局位置信息来实现组件的拖动

// xxx.ets
@Entry
@Component
struct Index {@State offsetX: number = 0;@State offsetY: number = 0;@State positionX: number = 0;@State positionY: number = 0;build() {Column() {Text('PanGesture Offset:\nX: ' + this.offsetX + '\n' + 'Y: ' + this.offsetY).fontSize(28).height(200).width(300).padding(20).border({ width: 3 })// 在组件上绑定布局位置信息.translate({ x: this.offsetX, y: this.offsetY, z: 0 }).gesture(// 绑定拖动手势PanGesture().onActionStart((event: GestureEvent|undefined) => {console.info('Pan start');})// 当触发拖动手势时,根据回调函数修改组件的布局位置信息.onActionUpdate((event: GestureEvent|undefined) => {if(event){this.offsetX = this.positionX + event.offsetX;this.offsetY = this.positionY + event.offsetY;}}).onActionEnd(() => {this.positionX = this.offsetX;this.positionY = this.offsetY;}))}.height(200).width(250)}
}

说明

大部分可滑动组件,如List、Grid、Scroll、Tab等组件是通过PanGesture实现滑动,在组件内部的子组件绑定拖动手势(PanGesture)或者滑动手势(SwipeGesture)会导致手势竞争。

当在子组件绑定PanGesture时,在子组件区域进行滑动仅触发子组件的PanGesture。如果需要父组件响应,需要通过修改手势绑定方法或者子组件向父组件传递消息进行实现,或者通过修改父子组件的PanGesture参数distance使得拖动更灵敏。当子组件绑定SwipeGesture时,由于PanGesture和SwipeGesture触发条件不同,需要修改PanGesture和SwipeGesture的参数以达到所需效果。

不合理的阈值设置会导致滑动不跟手(响应时延慢)的问题。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

疑似女友通过社交媒体泄露其本人位置数据,导致了杜罗夫的被捕?

以下引用百度百科: 帕维尔杜罗夫(俄文:Павел Дуров,英文:Pavel Durov),男,1984年10月10日出生于俄罗斯列宁格勒州(今圣彼得堡市),毕业…

Guava Cache实现原理及最佳实践

本文内容包括Guava Cache的使用、核心机制的讲解、核心源代码的分析以及最佳实践的说明。 概要 Guava Cache是一款非常优秀本地缓存,使用起来非常灵活,功能也十分强大。Guava Cache说简单点就是一个支持LRU的ConcurrentHashMap,并提供了基于…

4.1 数据分析-excel 基本操作

第四节:数据分析-excel 基本操作 课程目标 学会excel 基本操作 课程内容 数据伪造 产生一份招聘数据 import pandas as pd from faker import Faker import random import numpy as np# 创建一个Faker实例,用于生成假数据,指定中文本地…

不小心删除丢失了所有短信?如何在 iPhone 上查找和恢复误删除的短信

不小心删除了一条短信,或者丢失了所有短信?希望还未破灭,下面介绍如何在 iPhone 上查找和恢复已删除的短信。 短信通常都是非正式和无关紧要的,但短信中可能包含非常重要的信息。因此,如果您删除了一些短信以清理 iPh…

MASt3R:从3D的角度来实现图像匹配(更新中)

Abstract 图像匹配是 3D 视觉中所有性能最佳算法和pipeline的核心组件。 然而,尽管匹配从根本上来说是一个 3D 问题,与相机姿态和场景几何结构有内在联系,但它通常被视为一个 2D 问题。因为匹配的目标是建立 2D 像素字段之间的对应关系&#…

MYSQL:删除指定时间范围内每个电站每天发电数据除最大值以外的记录

有一个需求,需要保留每个电站每一天发电数据的最大值记录,其余删除。 表数据大概长这样: MYSQL 5.7写法:(因为不支持ROW_NUMBER()函数,采用自定义的变量来代替) 首次清理一年内数据&#xff1…

在Postgresql中计算工单的对应的GPS轨迹距离

一、概述 在某个App开发中,要求记录用户的日常轨迹,在用户巡逻设备的时,将记录的轨迹点当做该设备巡逻时候的轨迹。 由于业务逻辑上没有明确的指示人员巡逻工单-GPS位置之间的关系,所以通过时间关系进行轨迹划定。 二、创建测试表…

备受500强企业青睐的安全数据交换系统,到底有什么优势?

网络隔离成为常见的安全手段 网络隔离技术已成为许多企业进行网络安全建设的重要手段之一,党政单位、金融机构、半导体企业、以及能源电力、医疗、生物制药等等行业及领域的企业都会选择方式不一的网络隔离技术来保护自己的网络安全,规避互联网中的网络…

python开发--模板语句

这部分是导航栏部分的代码,由于导航栏在各个页面都需要用,为了提高代码复用率将导航栏部分作为一个模板。 在下面代码图中,红色框部分相当于一个插槽,其他页面,如部门列表、用户列表等将在这个位置展示。 这部分是用户…

全国地市未来产业水平数据集(2008-2023年)

未来产业,作为驱动经济社会高质量发展的核心引擎,是指依托科技创新和模式创新,引领全球新一轮科技革命和产业变革,具有前瞻性、先导性、战略性的新兴产业领域。也是实现生产力大解放,推动生产力质的跃迁并形成新质生产…

路径处理秘籍:Golang path包最佳实践与技巧

路径处理秘籍:Golang path包最佳实践与技巧 引言基本概念和功能path包简介路径的概念:相对路径与绝对路径常见操作函数概览 路径清理和拼接path.Cleanpath.Joinpath.Split 路径提取与处理path.Basepath.Dirpath.Ext处理不同操作系统的路径分隔符 路径匹配…

kubeadm方式升级k8s集群

一、注意事项 升级前最好备份所有组件及数据,例如etcd 不要跨两个大版本进行升级,可能会存在版本bug,如: 1.19.4–>1.20.4 可以 1.19.4–>1.21.4 不可以 跨多个版本的可以逐个版本进行升级。 二、查看当前版本 [rootk8s…

AI时代的程序员:关于创业、应用开发与快速成长的经验分享 | CSDN杭州线下分享

写在前面 上周六参加了一个CSDN组织的线下技术沙龙,做了一个分享,所以本篇内容对当时分享的内容做一个整理,感谢CSDN平台和鲲志大佬的组织,让大家有了一次深入的沟通交流。 先贴照片留念: 本来是想弄个详细点的逐字稿…

【qt】多线程实现倒计时

1.界面设计 设置右边的intvalue从10开始倒计时 2.新建Thread类 新建Thread类,使其继承QThread类,多态重写run函数,相当于线程执行函数 3.重写run函数 重写run函数,让另一个进程每隔1s发出一个信号,主线程使用conne…

大零售时代:开源 AI 智能名片、2+1 链动与 O2O 商城小程序引领融合新趋势

摘要:本文深入探讨了当今零售业态的发展趋势,指出在数据匹配的时代,人依然在零售中发挥着重要作用。通过对大零售理念的阐述,分析了跨行业跨业态融合的必然性,强调了业态融合的指导思想以及实现方式。同时,…

《OpenCV计算机视觉》—— 对图片的各种操作

文章目录 1、安装OpenCV库2、读取、显示、查看图片3、对图片进行切割4、改变图像的大小5、图片打码6、图片组合7、图像运算8、图像加权运算 1、安装OpenCV库 使用pip是最简单、最快捷的安装方式 pip install opencv-python3.4.2还需要安装一个包含了其他一些图像处理算法函数的…

【教程】MySQL数据库学习笔记(六)——数据查询语言DQL(持续更新)

写在前面: 如果文章对你有帮助,记得点赞关注加收藏一波,利于以后需要的时候复习,多谢支持! 【MySQL数据库学习】系列文章 第一章 《认识与环境搭建》 第二章 《数据类型》 第三章 《数据定义语言DDL》 第四章 《数据操…

华为云征文|华为云Flexus X实例docker部署srs6并调优,协议使用webrtc与rtmp

华为云征文|华为云Flexus X实例docker部署srs6并调优,协议使用webrtc与rtmp 什么是华为云Flexus X实例 华为云Flexus X实例云服务是新一代开箱即用、体验跃级、面向中小企业和开发者打造的高品价比云服务产品。Flexus云服务器X实例是新一代面向中小企业…

CRM系统为贷款中介行业插上科技的翅膀

CRM(客户关系管理)系统为贷款中介公司插上了科技的翅膀,极大提升了贷款中介企业的运营效率、客户管理能力和市场竞争力。鑫鹿贷款CRM系统基于互联网、大数据分析、人工智能、云计算等前沿技术,帮助贷款中介公司实现业务流程的自动…

注册安全分析报告:央视网

前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞…