当前位置: 首页 > news >正文

FairyGUI-Unity侧菜单扩展

目录

缘由:

分析: 

准备:

完整代码:

缘由:

在使用FairyGUI作为项目UI开发时,有时会使用FairyGUI提供的Scripting Define Symbols。当前FairyGUI中的Scripting Define Symbols有:

骨骼动画 Spine:FAIRYGUI_SPINE,龙骨:FAIRYGUI_DRAGONBONES

字体 TextMeshPro:FAIRYGUI_TMPRO

使用ToLua:FAIRYGUI_TOLUA

使用Puerts:FAIRYGUI_PUERTS

显示阿拉伯文本:RTL_TEXT_SUPPORT

UI自动化测试:FAIRYGUI_TEST

 为了方便开发,以上Scripting Define Symbols我将其做成了Unity的菜单,直接看完整代码。

分析: 

在开始制作菜单之前,需要做一些准备工作。比如上述的Scripting Define Symbols是否需要额外的Unity资源包,是否需要熟悉Unity编辑器中的一些方法才能进行?

而且需要注意的是新建的Unity工程中,TextMeshPro组件的必要资源库是需要手动导入或引用的,所以在使用FGUI提供的FAIRYGUI_TMPRO时,需要对TextMeshPro包进行检测。

对于编辑器中的Scripting Define Symbols设置可以通过方法GetScriptingDefineSymbolsForGrouphSetScriptingDefineSymbolsForGroup进行操作。菜单状态则可以通过方法:GetCheckedSetChecked来进行操作。菜单状态的变化Scripting Define Symbols设置有关,所以还要自定义一个同步刷新菜单状态的方法RefreshMenuState

准备:

分析结束,我们在代码中写一下上面的分析结果。新建脚本EditorMenuTool,空间名设置为FairyGUIEditor,添加对UnityEditor的引用。将新建的EditorMenuTool脚本,放到FairyGUI的Editor目录下(也可以根据项目目录结构放置),打开脚本。

#if UNITY_EDITOR
using System;
using UnityEditor;
using UnityEngine;namespace FairyGUIEditor
{public class EditorMenuTool{}
}
#endif

Scripting Define Symbols的操作方法:

        /// <summary>/// 获取Scripting Define Symbols的值/// </summary>/// <returns></returns>private static string GetScriptingDefineSymbolsForGroup(){return PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup);}/// <summary>/// 设置Scripting Define Symbols的值/// </summary>/// <param name="newSymbol">新的宏定义</param>private static void SetScriptingDefineSymbolsForGroup(string newSymbol){PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup,newSymbol);}/// <summary>/// 检测Scripting Define Symbols中是否存在目标值/// </summary>/// <param name="define">目标宏</param>/// <returns></returns>private static bool CheckScriptingDefineSymbolsExist(string define){string symbol = GetScriptingDefineSymbolsForGroup();return symbol.Contains(define);}/// <summary>/// 根据菜单状态修改目标宏/// </summary>/// <param name="define">目标宏定义</param>/// <param name="menuState">当前菜单状态</param>private static void SwitchToTargetState(string define, bool menuState = false){//检测目标宏定义if (define == null)return;//获取当前的宏定义string symbol = GetScriptingDefineSymbolsForGroup();if (menuState) //菜单已选中{//获取目标宏所在的位置int index = symbol.IndexOf(define);if (index < 0)return;//如果不在第一个 则将其前面的分号删掉if (index > 0)index -= 1;int length = define.Length;//如果当前宏长度大于要删除的当前长度,才会有分号if (symbol.Length > length)length += 1;//删除目标宏定义symbol = symbol.Remove(index, length);SetScriptingDefineSymbolsForGroup(symbol);}else //菜单未选中{//如果当前的宏是空的,则直接将目标的宏加入if (symbol.Equals(string.Empty))SetScriptingDefineSymbolsForGroup(define);else{//否则,以分号分割加入目标宏string newSymbol = symbol + ";" + define;SetScriptingDefineSymbolsForGroup(newSymbol);}}}

包管理(PackageManager)的检测方法:

        /// <summary>/// 检测目标包是否存在/// </summary>/// <param name="packageName">包名</param>/// <param name="callback"></param>private static void CheckTargetPackageExists(string packageName,Action<bool> callback = null){// 创建一个ListRequest请求,用来查询PackageManager中已经安装的packages列表ListRequest request = Client.List();// 发送ListRequest请求,并在每一帧检查请求是否已经完成EditorApplication.CallbackFunction checkUpdateAction = null;checkUpdateAction = () =>{if (request.IsCompleted){bool packageExists = false;EditorUtility.ClearProgressBar();if (request.Status == StatusCode.Success){// 遍历packages列表,查找目标packageName是否存在foreach (var package in request.Result){if (package.name.Contains(packageName) || package.displayName.Contains(packageName)){packageExists = true;break;}}}else if (request.Status >= StatusCode.Failure){Debug.LogError(request.Error.message);}callback?.Invoke(packageExists);// 取消update回调函数EditorApplication.update -= checkUpdateAction;}};EditorApplication.update += checkUpdateAction;EditorUtility.DisplayProgressBar("Check", "Please wait...", 0f);}

同步刷新菜单的方法:

/// <summary>
/// 刷新菜单状态
/// 标签"UnityEditor.Callbacks.DidReloadScripts"可以在脚本编译完成后自动回调这个方法
/// 标签"RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)"在场景加载前执行这个方法
/// </summary>
[UnityEditor.Callbacks.DidReloadScripts,RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
private static void RefreshMenuState()
{//添加需要更新菜单
}

添加UnityEditor.Callbacks.DidReloadScriptsRuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)标签,会在脚本编译完或场景加载前进行状态同步,是个很方便的功能。举例:和小伙伴们一起开发时,只需要自己这边配置好,同步到其他小伙伴那边时,他们的编译器自动就会刷新新配置对应菜单状态。 

完整代码:

#if UNITY_EDITOR
using System;
using UnityEditor;
using UnityEngine;
using UnityEditor.PackageManager;
using UnityEditor.PackageManager.UI;
using UnityEditor.PackageManager.Requests;namespace FairyGUIEditor
{public class EditorMenuTool{#region Define Symbols/// <summary>/// <a href="https://www.fairygui.com/docs/editor/skeleton#%E5%9C%A8unity%E4%B8%AD%E4%BD%BF%E7%94%A8"> 骨骼动画 </a> Spine:FAIRYGUI_SPINE,龙骨:FAIRYGUI_DRAGONBONES/// </summary>private const string DefineSpine = "FAIRYGUI_SPINE", DefineDragonBones = "FAIRYGUI_DRAGONBONES";/// <summary>/// <a href="https://www.fairygui.com/docs/editor/font#textmeshpro%E6%94%AF%E6%8C%81"> 字体 TextMeshPro </a>:FAIRYGUI_TMPRO/// </summary>private const string DefineTMP = "FAIRYGUI_TMPRO";/// <summary>/// <a href="https://www.fairygui.com/docs/unity/lua"> 使用ToLua </a>:FAIRYGUI_TOLUA/// </summary>private const string DefineToLua = "FAIRYGUI_TOLUA";/// <summary>/// <a href="https://www.fairygui.com/docs/unity/puerts"> 使用Puerts </a>:FAIRYGUI_PUERTS/// </summary>private const string DefinePuerts = "FAIRYGUI_PUERTS";/// <summary>/// <a href="https://www.fairygui.com/docs/unity/special#%E9%98%BF%E6%8B%89%E4%BC%AF%E8%AF%AD%E8%A8%80%E6%96%87%E5%AD%97%E6%98%BE%E7%A4%BA"> 阿拉伯语言文字显示 </a>:RTL_TEXT_SUPPORT/// </summary>private const string DefineRTL = "RTL_TEXT_SUPPORT";/// <summary>/// <a href="https://www.fairygui.com/docs/unity/special#ui%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95"> UI自动化测试 </a>:FAIRYGUI_TEST/// </summary>private const string DefineAirTest = "FAIRYGUI_TEST";#endregionprivate const string PackageName = "TextMeshPro";private const string TextMeshProCheckPkg = "FairyGUI/TextMeshPro/Check Package";private const string TextMeshProEssential = "FairyGUI/TextMeshPro/Import TMP Essential Resources";private const string MenuNameTextMeshPro = "FairyGUI/TextMeshPro/Use TextMeshPro";private const string MenuNameSpine = "FairyGUI/Use Spine";private const string MenuNameDragonBones = "FairyGUI/Use DragonBones";private const string MenuNameToLua = "FairyGUI/Use ToLua";private const string MenuNamePuerts = "FairyGUI/Use Puerts";private const string MenuNameRTLTextSupport = "FairyGUI/Use RTLTextSupport";private const string MenuNameAirTest = "FairyGUI/Use AirTest";/// <summary>/// 检测TextMeshPro包是否存在/// </summary>[MenuItem(TextMeshProCheckPkg,false,1000)]private static void CheckTextMeshProPackage(){CheckTargetPackageExists(PackageName, b =>{//不存在则打开包管理面板,并搜索if (!b){//UnityEditor.PackageManager.UIWindow.Open(PackageName);}else{//提示已经安装了EditorUtility.DisplayDialog("Tips", $"{PackageName} package is installed!\n{PackageName}包已存在!","Ok");}});}/// <summary>/// 导入TextMeshPro包必备资源/// </summary>[MenuItem(TextMeshProEssential,false,1015)]private static void ImportTMPEssentialResources(){//做一次安全检查if (UnityEditor.PackageManager.PackageInfo.FindForAssetPath("Packages/com.unity.textmeshpro/Scripts/Runtime/TextMeshPro.cs") == null) {Debug.LogError("TextMeshPro package is not installed.");return;}//执行目标菜单项EditorApplication.ExecuteMenuItem("Window/TextMeshPro/Import TMP Essential Resources");}/// <summary>/// 启用或关闭TextMeshPro支持/// </summary>[MenuItem(MenuNameTextMeshPro,false,1030)]private static void SelectTextMeshPro(){//获取当前状态bool state = Menu.GetChecked(MenuNameTextMeshPro);//切换宏定义状态SwitchToTargetState(DefineTMP,state);//刷新菜单状态RefreshMenuState();//更新AssetDatabase.Refresh();}/// <summary>/// 启用或关闭Spine/// </summary>[MenuItem(MenuNameSpine,false,1015)]private static void SelectSpine(){//获取当前状态bool state = Menu.GetChecked(MenuNameSpine);//切换宏定义状态SwitchToTargetState(DefineSpine,state);//刷新菜单状态RefreshMenuState();//更新AssetDatabase.Refresh();}/// <summary>/// 启用或关闭DragonBones/// </summary>[MenuItem(MenuNameDragonBones,false,1030)]private static void SelectDragonBones(){//获取当前状态bool state = Menu.GetChecked(MenuNameDragonBones);//切换宏定义状态SwitchToTargetState(DefineDragonBones,state);//刷新菜单状态RefreshMenuState();//更新AssetDatabase.Refresh();}/// <summary>/// 启用或关闭ToLua/// </summary>[MenuItem(MenuNameToLua,false,1045)]private static void SelectToLua(){//获取当前状态bool state = Menu.GetChecked(MenuNameToLua);//切换宏定义状态SwitchToTargetState(DefineToLua,state);//刷新菜单状态RefreshMenuState();//更新AssetDatabase.Refresh();}/// <summary>/// 启用或关闭Puerts/// </summary>[MenuItem(MenuNamePuerts,false,1060)]private static void SelectPuerts(){//获取当前状态bool state = Menu.GetChecked(MenuNamePuerts);//切换宏定义状态SwitchToTargetState(DefinePuerts,state);//刷新菜单状态RefreshMenuState();//更新AssetDatabase.Refresh();}/// <summary>/// 启用或关闭阿拉伯语言文字/// </summary>[MenuItem(MenuNameRTLTextSupport,false,1075)]private static void SelectRTLTextSupport(){//获取当前状态bool state = Menu.GetChecked(MenuNameRTLTextSupport);//切换宏定义状态SwitchToTargetState(DefineRTL,state);//刷新菜单状态RefreshMenuState();//更新AssetDatabase.Refresh();}/// <summary>/// 启用或关闭UI自动化测试/// </summary>[MenuItem(MenuNameAirTest,false,1090)]private static void SelectUIAirTest(){//获取当前状态bool state = Menu.GetChecked(MenuNameAirTest);//切换宏定义状态SwitchToTargetState(DefineAirTest,state);//刷新菜单状态RefreshMenuState();//更新AssetDatabase.Refresh();}/// <summary>/// 刷新菜单状态/// 标签"UnityEditor.Callbacks.DidReloadScripts"可以在脚本编译完成后自动回调这个方法/// 标签"RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)"在场景加载前执行这个方法/// </summary>[UnityEditor.Callbacks.DidReloadScripts,RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]private static void RefreshMenuState(){//放置需要更新菜单Menu.SetChecked(MenuNameTextMeshPro, CheckScriptingDefineSymbolsExist(DefineTMP));Menu.SetChecked(MenuNameSpine, CheckScriptingDefineSymbolsExist(DefineSpine));Menu.SetChecked(MenuNameDragonBones, CheckScriptingDefineSymbolsExist(DefineDragonBones));Menu.SetChecked(MenuNameToLua, CheckScriptingDefineSymbolsExist(DefineToLua));Menu.SetChecked(MenuNamePuerts, CheckScriptingDefineSymbolsExist(DefinePuerts));Menu.SetChecked(MenuNameRTLTextSupport, CheckScriptingDefineSymbolsExist(DefineRTL));Menu.SetChecked(MenuNameAirTest, CheckScriptingDefineSymbolsExist(DefineAirTest));}#region Package Check/// <summary>/// 检测目标包是否存在/// </summary>/// <param name="packageName">包名</param>/// <param name="callback"></param>private static void CheckTargetPackageExists(string packageName,Action<bool> callback = null){// 创建一个ListRequest请求,用来查询PackageManager中已经安装的packages列表ListRequest request = Client.List();// 发送ListRequest请求,并在每一帧检查请求是否已经完成EditorApplication.CallbackFunction checkUpdateAction = null;checkUpdateAction = () =>{if (request.IsCompleted){bool packageExists = false;EditorUtility.ClearProgressBar();if (request.Status == StatusCode.Success){// 遍历packages列表,查找目标packageName是否存在foreach (var package in request.Result){if (package.name.Contains(packageName) || package.displayName.Contains(packageName)){packageExists = true;break;}}}else if (request.Status >= StatusCode.Failure){Debug.LogError(request.Error.message);}callback?.Invoke(packageExists);// 取消update回调函数EditorApplication.update -= checkUpdateAction;}};EditorApplication.update += checkUpdateAction;EditorUtility.DisplayProgressBar("Check", "Please wait...", 0f);}#endregion#region Scripting Define Symbols/// <summary>/// 获取Scripting Define Symbols的值/// </summary>/// <returns></returns>private static string GetScriptingDefineSymbolsForGroup(){return PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup);}/// <summary>/// 设置Scripting Define Symbols的值/// </summary>/// <param name="newSymbol">新的宏定义</param>private static void SetScriptingDefineSymbolsForGroup(string newSymbol){PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup,newSymbol);}/// <summary>/// 检测Scripting Define Symbols中是否存在目标值/// </summary>/// <param name="define">目标宏</param>/// <returns></returns>private static bool CheckScriptingDefineSymbolsExist(string define){string symbol = GetScriptingDefineSymbolsForGroup();return symbol.Contains(define);}/// <summary>/// 更新菜单状态修改目标宏/// </summary>/// <param name="define">目标宏定义</param>/// <param name="menuState">当前菜单状态</param>private static void SwitchToTargetState(string define, bool menuState = false){//检测目标宏定义if (define == null)return;//获取当前的宏定义string symbol = GetScriptingDefineSymbolsForGroup();if (menuState) //菜单已选中{//获取目标宏所在的位置int index = symbol.IndexOf(define);if (index < 0)return;//如果不在第一个 则将其前面的分号删掉if (index > 0)index -= 1;int length = define.Length;//如果当前宏长度大于要删除的当前长度,才会有分号if (symbol.Length > length)length += 1;//删除目标宏定义symbol = symbol.Remove(index, length);SetScriptingDefineSymbolsForGroup(symbol);}else //菜单未选中{//如果当前的宏是空的,则直接将目标的宏加入if (symbol.Equals(string.Empty))SetScriptingDefineSymbolsForGroup(define);else{//否则,以分号分割加入目标宏string newSymbol = symbol + ";" + define;SetScriptingDefineSymbolsForGroup(newSymbol);}}}#endregion}
}#endif

相关文章:

FairyGUI-Unity侧菜单扩展

目录 缘由&#xff1a; 分析&#xff1a; 准备&#xff1a; 完整代码&#xff1a; 缘由&#xff1a; 在使用FairyGUI作为项目UI开发时&#xff0c;有时会使用FairyGUI提供的Scripting Define Symbols。当前FairyGUI中的Scripting Define Symbols有&#xff1a; 骨骼动画 …...

学习笔记十八:污点、容忍度

污点、容忍度 污点、容忍度管理节点污点把k8snode2当成是生产环境专用的&#xff0c;其他node是测试的给k8snode1也打上污点 污点、容忍度 给了节点选则的主动权&#xff0c;我们给节点打一个污点&#xff0c;不容忍的pod就运行不上来&#xff0c;污点就是定义在节点上的键值属…...

amis百度前端框架,在js中使用amis写json转页面

amis百度前端框架,在js中使用用amis写的json页面 1.在项目中使用百度 amis 的sdk做开发库。 <script src="./sdk/sdk/sdk.js"></script> 2。加载sdk中的库: amis = amisRequire(amis/embed);amisLib = amisRequire(amis);const match = amisRequire…...

openEuler安装jdk、openEuler离线安装jdk、openEuler设置jdk、openEuler在线安装

记录一下本人使用openEuler安装jdk的过程,希望能帮到看到帖子的你! 方式一:在线安装: 在 openEuler 上安装 JDK(Java Development Kit)的步骤如下: 更新系统: 在安装 JDK 之前,建议先更新系统软件包。打开终端并执行以下命令: sudo dnf update 这将更新系统中的软…...

Photoshop制作漂亮光泽感3D按钮

原文链接(https://img-blog.csdnimg.cn/45472c07f29944458570b59fe1f9a0e0.png)...

【网络爬虫】模拟登录与代理

代理...

无线局域网基础知识与架构

1.1 无线局域网 无线局域网(Wireless Local Area Network&#xff0c;WLAN)是指以无线信道作为传输 媒介的计算机局域网络&#xff0c;是计算机网络与无线通信技术相结合的产物&#xff0c;它以无线多 址信道作为传输媒介&#xff0c;提供传统有线局域网的功能&#xff0c;能…...

uniapp tabbar 浏览器调试显示 真机不显示

解决方案&#xff0c;把tabBar里面的单位全改为px&#xff0c;rpx是不会显示的&#xff01; 注意了&#xff0c;改完一定要重新运行&#xff0c;不然无效&#xff0c;坑爹 "tabBar": {"borderStyle": "black","selectedColor": &quo…...

极智AI | 地平线BPU跑通YOLOv5

欢迎关注我的公众号 [极智视界],获取我的更多经验分享 大家好,我是极智视界,本文来介绍一下 地平线BPU跑通YOLOv5。 邀您加入我的知识星球「极智视界」,星球内有超多好玩的项目实战源码下载,链接:https://t.zsxq.com/0aiNxERDq 硬件设备为地平线旭日x3,开发环境和执行环…...

循环服务器(同时连接多个客户端,为每个客户端创建一个子进程处理其消息)

服务器 客户端 结果...

【从零学习python 】38.Python包的使用及导入方式

文章目录 包的使用1. 导入包的方式总结2. __init__.py文件有什么用3. __all__ 注意事项进阶案例 包的使用 一个模块就是一个 py 文件&#xff0c;在 Python 里为了对模块分类管理&#xff0c;就需要划分不同的文件夹。多个有联系的模块可以将其放到同一个文件夹下&#xff0c;为…...

docker 容器满了常用处理方法

docker 容器满了常用处理方法 1、运行 df -h 查看剩余磁盘占用情况 2、进入到docker目录 cd /var/lib/docker 3、运行du -h --max-depth1 &#xff08;检索文件的最大深度1&#xff0c;即只检索汇总计算当前目录下的文件&#xff09; 4、进入占用最大的 /containers文件夹&am…...

28、springboot的静态模版(前端页面)重加载和 devtools开发者工具

springboot的静态模版重加载和 devtools开发者工具 总结&#xff1a;实现静态模板重加载的两个方法 方法1&#xff1a;在 yml 配置文件&#xff0c;关闭页面模板缓存&#xff0c; 再按 ctrlf9 重新构建 方法2&#xff1a;直接添加 devtools 依赖&#xff0c;再按 ctrlf9 重新构…...

[FPGA IP系列] FPGA常用存储资源大全(RAM、ROM、CAM、SRAM、DRAM、FLASH)

本文主要介绍FPGA中常用的RAM、ROM、CAM、SRAM、DRAM、FLASH等资源。 一、RAM RAM(Random Access Memory)是FPGA中最基本和常用的内部存储块&#xff0c;根据不同架构可以实现不同容量&#xff0c;最大可达几十Mb。 FPGA中的RAM主要包括: 分布式RAM&#xff1a;存在于逻辑块…...

Spark SQL优化:NOT IN子查询优化解决

背景 有如下的数据查询场景。 SELECT a,b,c,d,e,f FROM xxx.BBBB WHERE dt ${zdt.addDay(0).format(yyyy-MM-dd)} AND predict_type not IN ( SELECT distinct a FROM xxx.AAAAAWHERE dt ${zdt.addDay(0).format(yyyy-MM-dd)} ) 分析 通过查看SQL语句的执行计划基本…...

代码审计-java项目-组件漏洞审计

代码审计必备知识点&#xff1a; 1、代码审计开始前准备&#xff1a; 环境搭建使用&#xff0c;工具插件安装使用&#xff0c;掌握各种漏洞原理及利用,代码开发类知识点。 2、代码审计前信息收集&#xff1a; 审计目标的程序名&#xff0c;版本&#xff0c;当前环境(系统,中间件…...

接口测试的测试用例该怎么写呢

接口测试是软件测试中非常重要的一部分&#xff0c;因为接口的稳定性和可靠性对于整个系统的质量和用户体验都有很大的影响。在接口测试中&#xff0c;编写有效的测试用例是非常关键的一步。本文将介绍如何编写接口测试的测试用例&#xff0c;包括测试用例的设计和编写方法&…...

C语言例题讲解(if语句,循环语句,函数)

目录 if语句例题题目分析代码题目总结 循环语句例题题目分析代码题目总结 函数例题题目分析代码题目总结 if语句例题 计算1/1-1/21/3-1/41/5 …… 1/99 - 1/100 的值&#xff0c;打印出结果题目分析 1&#xff1a;首先我们不难看出算式中的加号和减号是交替出现的&#xff0…...

深入探索JavaEE单体架构、微服务架构与云原生架构

课程链接&#xff1a; 链接: https://pan.baidu.com/s/1xSI1ofwYXfqOchfwszCZnA?pwd4s99 提取码: 4s99 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 --来自百度网盘超级会员v4的分享 课程介绍&#xff1a; &#x1f50d;【00】模块零&#xff1a;开营直播&a…...

【STM32】FreeRTOS互斥量学习

互斥量&#xff08;Mutex&#xff09; 互斥量又称互斥信号量&#xff08;本质也是一种信号量&#xff0c;不具备传递数据功能&#xff09;&#xff0c;是一种特殊的二值信号量&#xff0c;它和信号量不同的是&#xff0c;它支持互斥量所有权、递归访问以及防止优先级翻转的特性…...

耦合详解-模块

耦合详解 耦合(Coupling)是衡量软件模块之间相互依赖程度的指标。低耦合是优秀软件设计的核心目标之一,它使系统更易于维护、测试和扩展。 1. 耦合的本质 耦合描述的是两个模块(类、组件、服务)之间的依赖关系强度。当修改一个模块时,需要修改其他模块的程度越高,耦合…...

**Flutter实战进阶:用自定义RenderObject打造高性能图表组件**在Flutter开发中,我们经

Flutter实战进阶&#xff1a;用自定义RenderObject打造高性能图表组件 在Flutter开发中&#xff0c;我们经常需要展示复杂的数据可视化效果&#xff0c;比如折线图、柱状图等。虽然社区已有不少成熟的图表库&#xff08;如charts_flutter&#xff09;&#xff0c;但它们往往无法…...

基于Moondream2的工业质检系统:缺陷检测与分类

基于Moondream2的工业质检系统&#xff1a;缺陷检测与分类 1. 为什么传统质检方式正在被重新思考 产线上的质检员每天要盯着成百上千件产品&#xff0c;眼睛酸涩、注意力下降&#xff0c;漏检率悄悄爬升。一台设备表面划痕只有0.1毫米宽&#xff0c;人眼在连续工作两小时后&a…...

从按键消抖到外部中断:STM32 GPIO输入模式的‘避坑’指南与AFIO的隐藏用法

从按键消抖到外部中断&#xff1a;STM32 GPIO输入模式的‘避坑’指南与AFIO的隐藏用法 在嵌入式开发中&#xff0c;GPIO&#xff08;通用输入输出&#xff09;接口是与外部世界交互的第一道门槛。对于STM32开发者来说&#xff0c;GPIO配置看似简单&#xff0c;却暗藏诸多细节陷…...

Java微服务在Istio中出现“偶发503 no healthy upstream”?7分钟定位Sidecar健康检查盲区与Liveness Probe冲突真相

第一章&#xff1a;Java微服务在Istio中偶发503问题的现象与影响在基于Istio构建的服务网格环境中&#xff0c;Java微服务&#xff08;尤其是采用Spring Cloud Kubernetes或原生Spring Boot Istio Sidecar部署模式&#xff09;频繁出现偶发性HTTP 503 Service Unavailable响应…...

Calypso vs PC-DMIS:三坐标两大软件脱机编程实战对比与选型指南

Calypso vs PC-DMIS&#xff1a;三坐标测量软件脱机编程深度对比与实战选型策略 在精密制造领域&#xff0c;三坐标测量机(CMM)的脱机编程能力直接决定了检测效率与资源利用率。作为行业两大标杆&#xff0c;蔡司Calypso与海克斯康PC-DMIS在用户界面设计、编程逻辑、仿真验证等…...

告别插件!保姆级教程:用Nginx反向代理搞定海康威视Web无插件视频预览

海康威视Web无插件视频预览的Nginx反向代理实战指南 引言 在现代安防监控系统集成中&#xff0c;海康威视设备因其稳定性和广泛兼容性成为行业首选。然而&#xff0c;传统Web集成方案往往依赖浏览器插件&#xff0c;这不仅增加了部署复杂度&#xff0c;也带来了安全风险。随着H…...

Linux I2C设备驱动避坑指南:以MPU6050为例,详解i2c_transfer与数据读取失败

Linux I2C设备驱动深度调试&#xff1a;MPU6050通信稳定性问题全解析 当你在嵌入式系统中集成MPU6050传感器时&#xff0c;是否遇到过这样的场景&#xff1a;设备树配置正确&#xff0c;驱动代码逻辑清晰&#xff0c;但传感器数据读取却间歇性失败&#xff0c;内核日志中频繁出…...

MDXEditor指令系统详解:如何扩展Markdown语法

MDXEditor指令系统详解&#xff1a;如何扩展Markdown语法 【免费下载链接】editor A rich text editor React component for markdown 项目地址: https://gitcode.com/gh_mirrors/editor/editor MDXEditor是一个功能丰富的React组件&#xff0c;专为Markdown编辑设计&am…...

Gemma-3-270m多场景落地:政务热线知识库问答、医疗术语解释系统

Gemma-3-270m多场景落地&#xff1a;政务热线知识库问答、医疗术语解释系统 1. 快速上手&#xff1a;部署你的第一个Gemma-3-270m服务 想要快速体验Gemma-3-270m的强大能力&#xff1f;通过Ollama部署只需几个简单步骤。 1.1 环境准备与模型选择 首先确保你已经安装了Ollam…...