HarmonyOS 6学习:Canvas实现圆角矩形进度条

news2026/4/3 17:31:13
在HarmonyOS应用开发中进度条是展示任务进度、加载状态和数据可视化的重要组件。虽然系统提供了Progress组件但在需要高度定制化、复杂视觉效果或特殊交互的场景下开发者常常面临以下困境样式限制Progress组件难以实现圆角矩形、渐变填充、分段显示等复杂效果交互单一无法灵活添加点击事件、拖拽交互或动态效果性能瓶颈复杂动画场景下系统组件可能无法满足高性能要求适配困难不同设备分辨率下进度条显示效果不一致扩展性差难以与图标、文字、动画等其他元素深度集成本文将深入分析这些常见问题并提供基于HarmonyOS Canvas的完整解决方案。一、常见问题深度分析1.1 样式定制化难题问题表现Progress组件仅支持基础的线性、环形进度条样式无法实现圆角矩形、胶囊形等特殊形状渐变填充、阴影效果等高级视觉效果难以实现分段显示不同颜色进度时边界处理不自然根本原因系统组件封装度高暴露的样式属性有限底层渲染引擎对自定义形状支持不足样式配置接口设计较为基础扩展性差1.2 交互体验不足问题表现无法实现点击跳转到指定进度拖拽调整进度时反馈不流畅进度变化动画生硬缺乏过渡效果多状态切换如暂停、继续、重置实现复杂根本原因组件事件系统设计简单缺少丰富的手势支持动画系统与进度逻辑耦合度低状态管理机制不够灵活1.3 性能与兼容性问题问题表现高频更新进度时出现卡顿内存占用随进度条复杂度增加而上升不同设备上渲染效果不一致复杂动画在低端设备上帧率下降明显根本原因渲染管线优化不足硬件加速支持不完善资源管理策略不够智能二、Canvas解决方案架构2.1 核心组件选择组件作用优势Canvas自定义绘制画布完全控制绘制过程支持任意形状和效果CanvasRenderingContext2D绘图上下文提供丰富的绘图API支持路径、渐变、变换等ArkUI声明式语法界面构建响应式数据绑定自动更新视图动画系统进度动画平滑过渡效果支持多种缓动函数手势系统交互处理支持点击、拖拽、长按等多种手势2.2 圆角矩形绘制原理圆角矩形进度条的绘制基于Canvas的路径绘制能力核心原理如下// 圆角矩形绘制配置 export class RoundedRectConfig { // 矩形位置和尺寸 public x: number 0; public y: number 0; public width: number 300; public height: number 20; // 圆角半径 public borderRadius: number 10; // 进度相关 public progress: number 0; // 0-100 public maxProgress: number 100; // 样式配置 public backgroundColor: string #E0E0E0; public progressColor: string #4CAF50; public borderColor: string #CCCCCC; public borderWidth: number 1; // 渐变配置 public useGradient: boolean false; public gradientColors: string[] [#4CAF50, #8BC34A, #CDDC39]; }2.3 两阶段绘制流程第一阶段基础绘制绘制背景轨道绘制完整的圆角矩形作为进度条背景计算进度宽度根据当前进度值计算填充部分的宽度绘制进度填充绘制圆角矩形的进度填充部分添加边框为进度条添加边框效果第二阶段增强效果渐变处理如果启用渐变创建线性渐变填充阴影效果为进度条添加投影增强立体感动画过渡应用平滑动画效果交互反馈添加点击、拖拽等交互效果三、代码实现详解3.1 Canvas基础配置// Canvas进度条基础组件 Entry Component struct RoundedRectProgressBar { // Canvas绘图上下文 private settings: RenderingContextSettings new RenderingContextSettings(true); private context: CanvasRenderingContext2D new CanvasRenderingContext2D(this.settings); // 进度状态 State progressValue: number 0; State isAnimating: boolean false; // 组件配置 private config: RoundedRectConfig new RoundedRectConfig(); build() { Column() { // 进度显示文本 Text(${this.progressValue}%) .fontSize(20) .fontColor(#333333) .margin({ bottom: 10 }) // Canvas画布 Canvas(this.context) .width(100%) .height(this.config.height 20) .backgroundColor(#FFFFFF) .onReady(() { // 画布准备就绪后开始绘制 this.drawProgressBar(); }) .onClick((event: ClickEvent) { // 点击跳转到对应进度 this.handleCanvasClick(event); }) // 控制按钮 Row({ space: 10 }) { Button(开始) .onClick(() this.startProgress()) Button(暂停) .onClick(() this.pauseProgress()) Button(重置) .onClick(() this.resetProgress()) } .margin({ top: 20 }) } .padding(20) .width(100%) .height(100%) } }3.2 圆角矩形绘制实现// 圆角矩形绘制工具类 export class RoundedRectDrawer { private context: CanvasRenderingContext2D; constructor(context: CanvasRenderingContext2D) { this.context context; } /** * 绘制圆角矩形 */ drawRoundedRect( x: number, y: number, width: number, height: number, radius: number, fillColor?: string, strokeColor?: string, lineWidth: number 1 ): void { if (width 2 * radius) radius width / 2; if (height 2 * radius) radius height / 2; this.context.beginPath(); // 从左上角开始顺时针绘制 this.context.moveTo(x radius, y); // 上边 this.context.lineTo(x width - radius, y); // 右上角圆弧 this.context.arc(x width - radius, y radius, radius, Math.PI * 1.5, Math.PI * 2); // 右边 this.context.lineTo(x width, y height - radius); // 右下角圆弧 this.context.arc(x width - radius, y height - radius, radius, 0, Math.PI * 0.5); // 下边 this.context.lineTo(x radius, y height); // 左下角圆弧 this.context.arc(x radius, y height - radius, radius, Math.PI * 0.5, Math.PI); // 左边 this.context.lineTo(x, y radius); // 左上角圆弧 this.context.arc(x radius, y radius, radius, Math.PI, Math.PI * 1.5); this.context.closePath(); // 填充 if (fillColor) { this.context.fillStyle fillColor; this.context.fill(); } // 描边 if (strokeColor) { this.context.strokeStyle strokeColor; this.context.lineWidth lineWidth; this.context.stroke(); } } /** * 绘制圆角矩形进度条 */ drawProgressBar( config: RoundedRectConfig, progress: number ): void { const { x, y, width, height, borderRadius } config; // 1. 绘制背景轨道 this.drawRoundedRect( x, y, width, height, borderRadius, config.backgroundColor, config.borderColor, config.borderWidth ); // 2. 计算进度宽度 const progressWidth (progress / config.maxProgress) * width; // 3. 绘制进度填充 if (progressWidth 0) { // 创建渐变如果启用 let fillStyle: string | CanvasGradient config.progressColor; if (config.useGradient config.gradientColors.length 0) { const gradient this.context.createLinearGradient( x, y, x progressWidth, y ); config.gradientColors.forEach((color, index) { const stop index / (config.gradientColors.length - 1); gradient.addColorStop(stop, color); }); fillStyle gradient; } // 绘制进度填充需要考虑圆角 this.drawProgressFill(x, y, progressWidth, height, borderRadius, fillStyle); } // 4. 添加内阴影效果可选 this.addInnerShadow(x, y, width, height, borderRadius); } /** * 绘制进度填充处理圆角 */ private drawProgressFill( x: number, y: number, width: number, height: number, radius: number, fillStyle: string | CanvasGradient ): void { this.context.save(); // 创建裁剪区域 this.context.beginPath(); this.drawRoundedRectPath(x, y, width, height, radius); this.context.clip(); // 填充进度 this.context.fillStyle fillStyle; this.context.fillRect(x, y, width, height); this.context.restore(); } /** * 绘制圆角矩形路径不填充不描边 */ private drawRoundedRectPath( x: number, y: number, width: number, height: number, radius: number ): void { if (width 2 * radius) radius width / 2; if (height 2 * radius) radius height / 2; this.context.beginPath(); this.context.moveTo(x radius, y); this.context.arcTo(x width, y, x width, y height, radius); this.context.arcTo(x width, y height, x, y height, radius); this.context.arcTo(x, y height, x, y, radius); this.context.arcTo(x, y, x width, y, radius); this.context.closePath(); } /** * 添加内阴影效果 */ private addInnerShadow( x: number, y: number, width: number, height: number, radius: number ): void { this.context.save(); // 创建内阴影路径 this.context.beginPath(); this.drawRoundedRectPath(x, y, width, height, radius); this.context.clip(); // 绘制阴影 this.context.shadowColor rgba(0, 0, 0, 0.1); this.context.shadowBlur 5; this.context.shadowOffsetX 0; this.context.shadowOffsetY 2; this.context.strokeStyle transparent; this.context.lineWidth 1; this.context.stroke(); this.context.restore(); } }3.3 动画与交互实现// 进度条动画管理器 export class ProgressAnimator { private animationId: number -1; private startTime: number 0; private duration: number 1000; // 动画时长毫秒 private easingFunction: (t: number) number; constructor(easing: string easeOutCubic) { this.easingFunction this.getEasingFunction(easing); } /** * 开始进度动画 */ animate( fromValue: number, toValue: number, duration: number, onUpdate: (value: number) void, onComplete?: () void ): void { this.startTime Date.now(); this.duration duration; const animateFrame () { const currentTime Date.now(); const elapsed currentTime - this.startTime; const progress Math.min(elapsed / this.duration, 1); // 应用缓动函数 const easedProgress this.easingFunction(progress); // 计算当前值 const currentValue fromValue (toValue - fromValue) * easedProgress; // 更新回调 onUpdate(currentValue); if (progress 1) { this.animationId requestAnimationFrame(animateFrame); } else { if (onComplete) { onComplete(); } } }; // 取消之前的动画 if (this.animationId ! -1) { cancelAnimationFrame(this.animationId); } this.animationId requestAnimationFrame(animateFrame); } /** * 停止动画 */ stop(): void { if (this.animationId ! -1) { cancelAnimationFrame(this.animationId); this.animationId -1; } } /** * 获取缓动函数 */ private getEasingFunction(type: string): (t: number) number { switch (type) { case linear: return (t: number) t; case easeInQuad: return (t: number) t * t; case easeOutQuad: return (t: number) t * (2 - t); case easeInOutQuad: return (t: number) t 0.5 ? 2 * t * t : -1 (4 - 2 * t) * t; case easeInCubic: return (t: number) t * t * t; case easeOutCubic: return (t: number) (--t) * t * t 1; case easeInOutCubic: return (t: number) t 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) 1; default: return (t: number) t; } } } // 交互处理器 export class ProgressInteractionHandler { private config: RoundedRectConfig; private onProgressChange: (progress: number) void; constructor( config: RoundedRectConfig, onProgressChange: (progress: number) void ) { this.config config; this.onProgressChange onProgressChange; } /** * 处理Canvas点击事件 */ handleClick(event: ClickEvent): void { const canvasX event.offsetX; const progress this.calculateProgressFromX(canvasX); // 限制进度范围 const clampedProgress Math.max(0, Math.min(this.config.maxProgress, progress)); // 触发回调 this.onProgressChange(clampedProgress); } /** * 处理拖拽事件 */ handleDrag(event: DragEvent): void { if (event.type DragAction.Move) { const canvasX event.offsetX; const progress this.calculateProgressFromX(canvasX); // 限制进度范围 const clampedProgress Math.max(0, Math.min(this.config.maxProgress, progress)); // 触发回调 this.onProgressChange(clampedProgress); } } /** * 根据X坐标计算进度值 */ private calculateProgressFromX(x: number): number { const { x: rectX, width } this.config; // 计算相对位置 const relativeX x - rectX; const percentage relativeX / width; return percentage * this.config.maxProgress; } }四、常见问题解决方案4.1 性能优化方案问题高频更新时出现卡顿解决方案// 性能优化配置 export class CanvasPerformanceOptimizer { // 启用离屏Canvas private offscreenCanvas: OffscreenCanvas | null null; private offscreenContext: CanvasRenderingContext2D | null null; // 初始化离屏Canvas initializeOffscreenCanvas(width: number, height: number): void { this.offscreenCanvas new OffscreenCanvas(width, height); const settings new RenderingContextSettings(true); this.offscreenContext this.offscreenCanvas.getContext(2d, settings); } // 批量绘制优化 batchDrawOperations( operations: Array() void, context: CanvasRenderingContext2D ): void { // 使用离屏Canvas预渲染 if (this.offscreenContext this.offscreenCanvas) { // 清空离屏Canvas this.offscreenContext.clearRect( 0, 0, this.offscreenCanvas.width, this.offscreenCanvas.height ); // 在离屏Canvas上执行所有绘制操作 operations.forEach(operation { // 临时替换上下文 const originalContext this.offscreenContext; operation.call({ context: this.offscreenContext }); }); // 一次性绘制到主Canvas const image this.offscreenCanvas.transferToImageBitmap(); context.transferFromImageBitmap(image); } else { // 降级方案直接在主Canvas上绘制 operations.forEach(operation { operation.call({ context }); }); } } // 防抖绘制 debouncedDraw( drawFunction: () void, delay: number 16 ): () void { let timeoutId: number -1; return () { if (timeoutId ! -1) { clearTimeout(timeoutId); } timeoutId setTimeout(() { drawFunction(); timeoutId -1; }, delay); }; } // 内存优化 optimizeMemoryUsage(): void { // 定期清理不需要的缓存 if (this.offscreenCanvas) { // 重置离屏Canvas尺寸以释放内存 this.offscreenCanvas.width 0; this.offscreenCanvas.height 0; } // 触发垃圾回收提示 if (globalThis.gc) { globalThis.gc(); } } }4.2 兼容性处理方案问题不同设备显示效果不一致解决方案// 设备适配器 export class DeviceAdapter { private dpr: number 1; private deviceType: string phone; constructor() { this.detectDevice(); } // 检测设备信息 private detectDevice(): void { // 获取设备像素比 this.dpr window.devicePixelRatio || 1; // 检测设备类型 const screenWidth window.screen.width; if (screenWidth 768) { this.deviceType phone; } else if (screenWidth 1024) { this.deviceType tablet; } else { this.deviceType desktop; } } // 适配Canvas尺寸 adaptCanvasSize( canvas: HTMLCanvasElement, logicalWidth: number, logicalHeight: number ): void { // 设置逻辑尺寸 canvas.style.width ${logicalWidth}px; canvas.style.height ${logicalHeight}px; // 设置实际渲染尺寸 canvas.width logicalWidth * this.dpr; canvas.height logicalHeight * this.dpr; // 缩放绘图上下文 const context canvas.getContext(2d); if (context) { context.scale(this.dpr, this.dpr); } } // 适配圆角半径 adaptBorderRadius(baseRadius: number): number { switch (this.deviceType) { case phone: return baseRadius; case tablet: return baseRadius * 1.2; case desktop: return baseRadius * 1.5; default: return baseRadius; } } // 适配进度条高度 adaptProgressHeight(baseHeight: number): number { switch (this.deviceType) { case phone: return baseHeight; case tablet: return baseHeight * 1.5; case desktop: return baseHeight * 2; default: return baseHeight; } } }4.3 错误处理与降级策略问题Canvas API不支持或渲染异常解决方案// 健壮的Canvas渲染器 export class RobustCanvasRenderer { private fallbackEnabled: boolean false; private errorCount: number 0; private maxErrors: number 3; /** * 安全绘制方法 */ safeDraw( drawFunction: () void, context: CanvasRenderingContext2D, fallbackDraw?: () void ): boolean { try { // 检查Canvas上下文是否有效 if (!this.isContextValid(context)) { throw new Error(Canvas context is not valid); } // 尝试绘制 drawFunction(); this.errorCount 0; // 重置错误计数 return true; } catch (error) { console.error(Canvas绘制失败:, error); this.errorCount; // 如果错误次数过多启用降级方案 if (this.errorCount this.maxErrors) { this.fallbackEnabled true; } // 执行降级绘制 if (this.fallbackEnabled fallbackDraw) { try { fallbackDraw(); return true; } catch (fallbackError) { console.error(降级绘制也失败:, fallbackError); return false; } } return false; } } /** * 检查Canvas上下文有效性 */ private isContextValid(context: CanvasRenderingContext2D): boolean { return ( context ! null context ! undefined typeof context.fillRect function ); } /** * 降级绘制方案使用div模拟进度条 */ createFallbackProgressBar( config: RoundedRectConfig, progress: number ): HTMLElement { const container document.createElement(div); container.style.position relative; container.style.width ${config.width}px; container.style.height ${config.height}px; container.style.borderRadius ${config.borderRadius}px; container.style.backgroundColor config.backgroundColor; container.style.border ${config.borderWidth}px solid ${config.borderColor}; container.style.overflow hidden; const progressBar document.createElement(div); progressBar.style.position absolute; progressBar.style.top 0; progressBar.style.left 0; progressBar.style.height 100%; progressBar.style.width ${(progress / config.maxProgress) * 100}%; progressBar.style.backgroundColor config.progressColor; progressBar.style.borderRadius ${config.borderRadius}px; container.appendChild(progressBar); return container; } }五、最佳实践与优化建议5.1 性能优化最佳实践// 根据设备性能选择渲染策略 export function selectRenderingStrategy(deviceScore: number): RenderingStrategy { if (deviceScore 80) { // 高性能设备 return { useOffscreenCanvas: true, enableShadows: true, enableGradients: true, animationFPS: 60, batchDraw: true }; } else if (deviceScore 50) { // 中等性能设备 return { useOffscreenCanvas: true, enableShadows: false, enableGradients: true, animationFPS: 30, batchDraw: true }; } else { // 低性能设备 return { useOffscreenCanvas: false, enableShadows: false, enableGradients: false, animationFPS: 15, batchDraw: false }; } } // 智能缓存管理 export class SmartCanvasCache { private cache: Mapstring, ImageBitmap new Map(); private maxCacheSize: number 10; // 最大缓存数量 private accessCount: Mapstring, number new Map(); // 获取缓存的绘制结果 getCachedDraw(key: string): ImageBitmap | null { if (this.cache.has(key)) { // 更新访问计数 const count this.accessCount.get(key) || 0; this.accessCount.set(key, count 1); return this.cache.get(key)!; } return null; } // 缓存绘制结果 cacheDraw(key: string, bitmap: ImageBitmap): void { // 检查缓存是否已满 if (this.cache.size this.maxCacheSize) { this.cleanupCache(); } this.cache.set(key, bitmap); this.accessCount.set(key, 1); } // 清理缓存LRU策略 private cleanupCache(): void { // 找到访问次数最少的项 let minKey: string | null null; let minCount Infinity; for (const [key, count] of this.accessCount.entries()) { if (count minCount) { minCount count; minKey key; } } // 移除最少使用的项 if (minKey) { this.cache.delete(minKey); this.accessCount.delete(minKey); } } }5.2 代码组织最佳实践// 模块化进度条组件 Component export struct ModularProgressBar { // 配置参数 Prop config: ProgressBarConfig; Prop progress: number; Prop onProgressChange?: (progress: number) void; // 内部状态 State private isDragging: boolean false; State private displayProgress: number 0; // 工具实例 private drawer: RoundedRectDrawer; private animator: ProgressAnimator; private interactionHandler: ProgressInteractionHandler; aboutToAppear(): void { // 初始化工具实例 const context new CanvasRenderingContext2D(new RenderingContextSettings(true)); this.drawer new RoundedRectDrawer(context); this.animator new ProgressAnimator(easeOutCubic); this.interactionHandler new ProgressInteractionHandler( this.config, (progress: number) { if (this.onProgressChange) { this.onProgressChange(progress); } } ); // 初始化显示进度 this.displayProgress this.progress; } aboutToDisappear(): void { // 清理资源 this.animator.stop(); } // 进度动画 animateToProgress(targetProgress: number, duration: number 500): void { this.animator.animate( this.displayProgress, targetProgress, duration, (value: number) { this.displayProgress value; }, () { console.log(进度动画完成); } ); } // 构建UI build() { Column() { // 进度条标签 if (this.config.showLabel) { this.buildLabel(); } // 进度条主体 this.buildProgressBar(); // 控制按钮如果启用 if (this.config.showControls) { this.buildControls(); } } } Builder buildLabel() { Row({ space: 8 }) { Text(this.config.label || 进度) .fontSize(this.config.labelFontSize || 14) .fontColor(this.config.labelColor || #333333) Text(${Math.round(this.displayProgress)}%) .fontSize(this.config.valueFontSize || 16) .fontColor(this.config.valueColor || #4CAF50) .fontWeight(FontWeight.Bold) } .width(100%) .justifyContent(FlexAlign.SpaceBetween) .margin({ bottom: 8 }) } Builder buildProgressBar() { Canvas(this.drawer.context) .width(100%) .height(this.config.height 4) .onReady(() { this.drawer.drawProgressBar(this.config, this.displayProgress); }) .onClick((event: ClickEvent) { this.interactionHandler.handleClick(event); }) .onTouch((event: TouchEvent) { if (event.type TouchType.Down) { this.isDragging true; } else if (event.type TouchType.Up || event.type TouchType.Cancel) { this.isDragging false; } else if (event.type TouchType.Move this.isDragging) { // 处理拖拽 const touch event.touches[0]; if (touch) { // 这里需要将touch事件转换为点击事件坐标 // 实际实现中需要更精确的坐标转换 } } }) } Builder buildControls() { Row({ space: 12 }) { Button(-10%) .onClick(() { const newProgress Math.max(0, this.progress - 10); this.animateToProgress(newProgress); }) Button(10%) .onClick(() { const newProgress Math.min(100, this.progress 10); this.animateToProgress(newProgress); }) Button(重置) .onClick(() { this.animateToProgress(0); }) } .width(100%) .justifyContent(FlexAlign.Center) .margin({ top: 16 }) } }六、总结与展望6.1 技术总结通过本文的分析和实现我们解决了HarmonyOS Canvas进度条开发中的几个核心问题样式定制化通过Canvas的路径绘制能力实现了完全自定义的圆角矩形进度条支持渐变填充、阴影效果等高级样式交互体验结合手势系统实现了点击跳转、拖拽调整等丰富的交互功能性能优化采用离屏Canvas、批量绘制、智能缓存等策略确保高频更新下的流畅性兼容性处理通过设备检测和降级策略保证了在不同设备上的一致体验代码可维护性采用模块化设计将绘制逻辑、动画控制、交互处理分离提高了代码的可读性和可维护性6.2 未来优化方向WebGL集成对于需要大量图形计算的场景可以考虑集成WebGL进行硬件加速渲染矢量图形支持探索使用SVG或自定义矢量图形格式实现无限缩放而不失真物理动画引擎引入物理引擎实现更自然的进度变化动画效果AI智能推荐基于用户使用习惯智能推荐进度条样式和动画效果跨平台适配进一步优化代码结构支持一次开发多端部署6.3 给开发者的建议性能优先在实现复杂效果前先评估设备性能和用户体验影响渐进增强先实现基础功能再逐步添加高级特性确保基础体验测试全面在不同设备、不同分辨率、不同系统版本上进行充分测试代码复用将通用功能封装成组件提高开发效率和代码质量关注官方更新及时关注HarmonyOS官方文档和API更新利用最新特性优化实现Canvas自定义进度条开发是一个既充满挑战又极具创造性的领域。随着HarmonyOS生态的不断完善和硬件性能的持续提升我们有理由相信未来的UI组件将更加精美、交互更加自然、性能更加卓越。希望本文能为您的HarmonyOS开发之路提供有价值的参考和启发。

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

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

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…