SwiftUI NavigationView实战:导航栈、NavigationLink与迁移NavigationStack指南
接手老项目的时候第一眼看到几十个NavigationView躺在代码里我心里咯噔一下iOS 16 之后苹果不是已经推荐NavigationStack了吗怎么还在用老的容器后来真动手改了一遍才发现这些NavigationView并不是偷懒而是一套完整的导航体系。标题里的“SwiftUI 8”我更愿意理解成内部工程代号可能对应的是 iOS 17 SDK 前后的那一代 SwiftUI 版本核心 API 依然是 NavigationView 这一套。这篇文章就把我在实际项目中用 NavigationView 做导航的经验、踩过的坑、以及迁移到 NavigationStack 的思路整个拆开讲一遍适合正在维护老项目、或者刚接触 SwiftUI 导航的新手参考。1. 先搞懂 NavigationView 的导航栈后面才不踩坑1.1 导航栈是什么页面之间的“前进后退”从哪里来NavigationView 本质上是一个容器视图它本身不显示任何业务内容而是管理一组“页面”之间的关系。这套关系就是一个栈栈底是根页面每一次通过 NavigationLink 跳转就往栈顶压入一个新页面点击返回按钮或手势右滑就把栈顶页面弹出。这个机制和 UIKit 里的 UINavigationController 几乎一致SwiftUI 只是把它声明式地包装了一层。我遇到不少刚接触 SwiftUI 的开发者会误以为 NavigationView 是个“页面容器”只要把子页面放进去就能跳转。实际上单纯写NavigationView { Text(Hello) }只是显示一个文本并不会产生任何导航能力。真正触发跳转的是NavigationLink它才是往导航栈里压入页面的入口。理解了这一点后面很多看似诡异的问题就都能解释通了。另一点容易忽略的是NavigationView 会根据运行环境自动决定展示样式。在 iPhone 上默认是单栏 push 风格在 iPad 上则可能变成 split view 那种主从双栏布局。如果你希望 iPad 上也保持传统的单栏导航可以在 NavigationView 上显式加上.navigationViewStyle(.stack)这是我在项目里几乎必写的一行修饰符。1.2 NavigationView 和 UINavigationController 的关系SwiftUI 的 NavigationView 底层并不是重新实现了一套导航机制而是桥接到了 UIKit 的 UINavigationController。所以在 NavigationView 中设置导航栏标题、返回按钮、工具栏按钮最终都会落到 UINavigationBar 和 UIToolbar 上。这就带来一个非常重要的实践结论很多 UIKit 时代针对 UINavigationBar 的定制经验在 SwiftUI 里依然有效。比如修改导航栏背景色或标题字体可以借助UINavigationBarAppearance在视图初始化时配置一次NavigationView 里的所有页面都会生效。我在一个老项目中需要做全局导航栏白色背景、黑色标题就是用了这种混合方案完全不需要在 SwiftUI 层面对每个页面单独设置。连接关系用代码看更清楚struct RootView: View { var body: some View { NavigationView { VStack { NavigationLink(进入二级页面) { Text(这是二级页面) } } .navigationTitle(首页) } } }运行之后你看到的导航栏、返回按钮、右滑手势其实都是 UIKit 在底层提供的。这也是为什么 NavigationView 里的页面返回手势一直都很稳定因为系统自动为这个导航栈配置了交互式 pop 手势。还有一点值得说NavigationView 是视图值类型每次重绘时它都可能被重新创建但底层对应的 UINavigationController 实例会由 SwiftUI 维护不会因为父视图刷新而丢失导航栈。换言之你不需要担心State一变导致当前页面被弹出这一点在实际项目中给过我很多信心。2. NavigationLink 跳转与 isActive 触发的完整写法2.1 destination 式 NavigationLink最直接的 pushNavigationLink 最基础的用法是直接指定目标视图点击后就 push 到下一页NavigationLink(查看详情) { DetailView() }这段代码看起来简单但背后有几个细节值得注意。首先destination参数用的是ViewBuilder也就是说你可以在里面写一个完整的视图结构不只是一个单独的视图。其次SwiftUI 对destination的构造是惰性的只有在用户真正点击跳转时才会创建目标视图的内容所以不用担心一个列表里放几百个 NavigationLink 会一次性创建几百个详情页对象。不过这里也有一个常见的困惑很多人在 List 里使用 NavigationLink 时发现整行都可以点击而且行尾会自动出现一个灰色箭头。这是系统默认行为如果你不想要箭头可以把.environment(\.navigationBarBackButtonHidden, ...)之类的东西放在目标视图里箭头样式本身由系统的列表样式控制想隐藏需要自定义列表行。如果你的列表数据量很大比如超过几千条我更推荐用 value 式 NavigationLink它不是绑定目标视图而是绑定一个可哈希的值再配合navigationDestination统一映射到目标页面NavigationLink(value: item) { Text(item.name) } .navigationDestination(for: Item.self) { item in DetailView(item: item) }这种写法最大的好处是解耦列表行只负责提供“跳转数据”页面构造逻辑集中在navigationDestination里后续如果要把跳转改为路由管理改动会非常小。不过需要说明value 式 NavigationLink 这套能力在 NavigationStack 里表现最好NavigationView 里虽然也能用但要确认系统版本避免在低版本上出现无法跳转的问题。2.2 isActive 触发式跳转适合表单提交后自动进入下一页实际项目中并不是所有跳转都来自用户点击列表更多时候需要“在某个条件满足后自动跳转”。比如登录成功后自动进入主页、表单校验通过后自动跳到下一步。这种场景用NavigationLink(destination:isActive:)最合适struct ParentView: View { State private var shouldShowDetail false var body: some View { NavigationView { VStack { Button(校验并进入下一页) { // 做一些校验逻辑 shouldShowDetail true } } .background( NavigationLink(destination: DetailView(), isActive: $shouldShowDetail) { EmptyView() } ) .navigationTitle(首页) } } }仔细看这段代码我并没有把 NavigationLink 放在 Button 里而是把它放在background中并让内容为EmptyView()。这样页面里就看不到任何跳转入口唯一的触发源是shouldShowDetail这个状态。为什么要塞进background而不是用hidden因为 SwiftUI 对不可见视图有一套自己的处理方式EmptyView()在布局上不占空间后台导航链接也不会影响当前页面的点击事件。如果你把一个 NavigationLink 的label设为空字符串在某些系统版本上还是会留下一条空白行很影响界面。这里要强调一个关键点isActive的 Binding 状态应该从父视图传入而不是在目标视图内部创建。原因很简单当 NavigationLink 把目标视图 push 上去之后父视图仍然持有这个状态当用户点击返回按钮时系统需要把isActive改回false这样才能保证下次点击还能继续跳转。如果状态定义在目标视图里返回后目标视图就被销毁了父视图怎么拿到这个值呢所以在写这种触发式跳转时一定要把State提升到父视图或者放到一个 ViewModel 里。2.3 返回上一页的几种写法在 NavigationView 的子页面里返回有两种常用方式。第一种是让用户点击系统返回按钮什么都不用写第二种是在业务逻辑里主动返回比如保存成功后自动 pop。主动返回最简洁的写法是用环境值dismissstruct DetailView: View { Environment(\.dismiss) private var dismiss var body: some View { VStack { Button(保存并返回) { // 保存逻辑 dismiss() } } .navigationTitle(详情) } }需要注意dismiss是一个多用途环境值它在导航 push、sheet 弹窗、fullScreenCover 里的表现不同。在 NavigationView 的 push 页面里调用它相当于 pop在一个 sheet 里调用它相当于关闭弹窗。SwiftUI 会根据视图所处的容器自动选择合适的行为这点设计得很巧妙。如果你需要返回多级比如从第三层直接回到根页面单个dismiss就不够用了。旧版 NavigationView 里没有直接提供 popToRoot 的 API常见做法是向上传递一个回调或者在根页面控制一个全局导航状态。比较粗暴但有效的另一个方案是替换整个导航栈比如用NavigationLink(isActive:)在根页面做一些状态联动但那样代码会很难维护。更推荐的做法是直接考虑迁移到 NavigationStack它用路径数组管理导航栈popToRoot 只是清除数组这么简单。3. 列表导航、多级页面与导航栏定制的实际案例3.1 List NavigationLink 的经典主从界面在 SwiftUI 里最经典的一套导航场景就是左侧列表点击后进入详情页。拆开其实就是两个部分外层 NavigationView 管理导航栈内层 List 通过 NavigationLink 生成每一行。struct Item: Identifiable { let id UUID() let name: String } struct RootListView: View { let items [ Item(name: 项目A), Item(name: 项目B), Item(name: 项目C) ] var body: some View { NavigationView { List(items) { item in NavigationLink { DetailView(item: item) } label: { Text(item.name) } } .navigationTitle(列表) } .navigationViewStyle(.stack) } }这个示例里我特别加了.navigationViewStyle(.stack)因为默认样式在 iPad 上会变成主从分栏列表会一直停留在左侧详情显示在右侧第一次看到的人会以为页面跳转失效了。强制改成 stack 后所有设备上的行为一致都是 push 样式。另外List 中的 NavigationLink 如果只放 Text整行点击区域会自动扩展。如果你在 label 里放了多个组件需要确保组件本身能响应点击。一个常见的坑是在 Text 上设置.onTapGesture这会把 NavigationLink 的内置点击覆盖掉导致行可点但跳转不执行。遇到这种需求优先用 Button 或者重写整个行而不是在 label 内部加手势。3.2 多级页面和嵌套 NavigationView 的坑多级页面也是常规需求列表页 - 详情页 - 详情中的某个附属页面。在 NavigationView 体系中每一级页面都通过 NavigationLink push 到同一个导航栈中所以不需要在子页面里嵌套 NavigationView。但我在实际项目里见过不少新人的代码每个子页面都习惯性地包一层NavigationView { ... }结果一运行就出现“双导航栏”而且返回手势时灵时不灵。原因很简单每个 NavigationView 都往视图树里插入一个独立的导航容器系统被搞糊涂了不知道该让哪一层容器响应返回。正确的做法是整个导航流程只有一个 NavigationView子页面里的跳转继续使用 NavigationLink目标页面不需要再包容器。NavigationView { VStack { NavigationLink(二级页面) { VStack { NavigationLink(三级页面) { Text(这里是三级页面) } } .navigationTitle(二级页面) } } .navigationTitle(一级页面) }只要保证最外层只有一个 NavigationView多级跳转的返回栈会自动维护。如果你确实遇到某个子页面需要独立导航栏那就应该用sheet或fullScreenCover弹出另一条导航链而不是在同一个链路上嵌套。3.3 导航栏按钮、标题模式与背景样式调整NavigationView 的导航栏左侧和右侧可以放自定义按钮用的是toolbar修饰符.navigationTitle(首页) .toolbar { ToolbarItem(placement: .navigationBarLeading) { Button(左侧) { } } ToolbarItem(placement: .navigationBarTrailing) { Button(右侧) { } } }这里要注意这些修饰符要写在“当前页面内容的视图”上而不是写在 NavigationView 容器上。如果写在容器上某些系统版本会出现按钮不显示的问题。我在排查过几个类似 case 后养成了习惯所有导航相关修饰符都紧随内容视图。标题模式方面navigationTitle默认在 iOS 14 上会根据滚动状态自动切换大标题与内联标题。如果你想固定大标题可以在目标页面加.navigationBarTitleDisplayMode(.large)如果固定成内联标题用.inline。这个修饰符的作用域是当前页面返回上一页时会自动恢复上一页的标题模式。背景颜色和字体这类更深入的定制需要用到 UIKit 的UINavigationBarAppearance。一个常见做法是写一个扩展或者 init 方法在视图创建时配置init() { let appearance UINavigationBarAppearance() appearance.configureWithOpaqueBackground() appearance.backgroundColor .white appearance.titleTextAttributes [.foregroundColor: UIColor.black] appearance.largeTitleTextAttributes [.foregroundColor: UIColor.black] UINavigationBar.appearance().standardAppearance appearance UINavigationBar.appearance().scrollEdgeAppearance appearance }这样设置一次整个 app 的 NavigationView 导航栏都会生效。需要注意的是scrollEdgeAppearance影响的是滚动到边缘时的导航栏外观很多项目忘了配置这一项导致列表滚到顶部时导航栏又变回半透明很影响视觉效果。4. 高频翻车现场NavigationView 的 5 类问题与排查实录4.1 点击列表跳转后导航栏消失有一次线上反馈说某个列表页点进去之后导航栏突然不见了返回按钮也没有只能依靠边缘滑动返回体验很差。我第一反应是目标页面里写了.navigationBarHidden(true)检查后发现果然是之前某个版本为了做沉浸式头图加的。SwiftUI 的navigationBarHidden是单向隐藏不会因为页面 pop 回来而自动恢复如果页面复用了同一个视图实例可能把隐藏状态也带到下一次显示。处理办法很简单去掉.navigationBarHidden改用更精确的.toolbar(.hidden, for: .navigationBar)并且确保在onDisappear中恢复.onAppear { // 隐藏导航栏 toolbarVisible false } .onDisappear { toolbarVisible true }更稳的做法是不要轻易隐藏导航栏除非你确认不会影响返回手势和标题展示。4.2 isActive 状态不更新跳转后无法返回编程式跳转最常见的 bug 是第一次点击能正常进入下一页返回后再次点击页面没有任何反应。症结基本都在 isActive 的 Binding 来源上。举一个错误示例struct DetailView: View { State private var isActive false // 永远不能用自己视图里的状态去控制是否进入自己 }如果你在父视图里把isActive传给 NavigationLink但返回时系统需要把状态设回false。如果这个状态定义在了某个不会因页面 pop 而重置的 ViewModel 中也要注意在返回回调里手动处理。总之状态必须是被父视图稳定持有的才能伴随整个 push/pop 生命周期。我还遇到过一种情况isActive状态在主线程外被修改导致界面响应异常。SwiftUI 的状态更新必须回到主线程推荐在异步逻辑里用DispatchQueue.main.async包裹状态赋值。4.3 页面返回到根部不生效在 NavigationView 里从多层页面直接返回根页面没有官方 API。我见过有人连续调用两次dismiss()结果直接把整个页面关闭了体验非常奇怪。比较好的临时方案是在根页面放一个State var refreshTrigger通过环境对象或者回调通知子页面去修改根页面的 isActive 状态但这套逻辑很绕长期维护成本高。真正一劳永逸的做法还是迁移到 NavigationStack。用路径数组管理栈的时候popToRoot 就是一行path.removeAll()逻辑直白且稳定。如果你的项目短期没法迁移建议尽量减少三层以上的导航用 fullScreenCover 替代深层 push。4.4 导航状态被 TabView 切换清空有人在 TabView 里放了一个 NavigationView然后发现切换到其他 Tab 再切回来导航栈被重置了。这种情况多半是因为 TabView 的每个 tab 在切换时都被重新渲染如果导航状态存在子视图的临时 State 里就会丢失。解决方案是把导航栈状态上移到能被稳定持有的地方。每个 tab 保持独立的 NavigationView 容器并且把关键的页面栈数据放到对应 tab 的 ViewModel 中。换 Tab 时不要用重建视图的方式刷新 tab 内容保持容器稳定即可。4.5 大量数据列表跳转卡顿列表数据超过几千条时如果每行都写NavigationLink(destination:)即使 destination 是惰性构造也可能在快速滑动时频繁计算行视图出现卡顿。我的经验是先用List而不是ScrollView VStackList 自身有复用机制。其次把跳转改成NavigationLink(value:)配合navigationDestination让页面构造集中到容器级别减少每行的负担。4.6 问题排查速查表现象可能原因排查与处理建议导航栏消失或双导航栏嵌套 NavigationView 或错误隐藏只保留一个容器检查 navigationBarHiddenisActive 跳转后无法再次跳转状态定义位置不对将状态提升到父视图或 ViewModel返回手势失效隐藏返回按钮或自定义导航栏尽量保留系统返回按钮或推迟隐藏时机Tab 切换后导航栈被清空状态绑定在临时视图上将导航状态放入 Tab 内稳定的 ViewModel列表跳转卡顿大量 NavigationLink 目标构造过重改用 value 式跳转并集中 destination5. 迁移到 NavigationStack统一路径数组与 Route 枚举5.1 为什么要迁移以及两者能力差异苹果在 iOS 16 中推出了 NavigationStackNavigationView 进入到废弃状态。这里说的“废弃”不是“立刻不能用”而是不再推荐在新代码中使用后续系统版本会在新特性上优先支持 NavigationStack。NavigationView 没有原生 path 路径数组的概念所有导航状态分散在多个isActive或NavigationLink里逐个状态跟踪非常痛苦。NavigationStack 把整个导航栈收敛到一个[Route]数组或NavigationPath类型中跳转、返回、popToRoot 都变成对数组的增删操作。两者的差异可以整理成一张表能力NavigationViewNavigationStack路径数组无原生 pathNavigationPath 或 [Route]编程式跳转NavigationLink isActivenavigationDestination path.append多目标管理需要分散多个 isActive统一注册 destination(for:)popToRoot无法直接操作path.removeAll()最低系统版本iOS 13iOS 16从实际体验看NavigationStack 的最大优势不只是 API 更干净而是“导航状态可序列化”。路径数组可以被持久化到文件或 UserDefaults冷启动后能恢复到上次浏览的位置这在 NavigationView 时代做起来非常费劲。5.2 用统一 Route 枚举管理跳转目标NavigationStack 配合一个 Route 枚举基本就是一个小型路由系统。下面是我在项目里经常用的模式enum Route: Hashable { case detail(id: UUID) case settings case profile(userID: UUID) } struct AppNavigationView: View { State private var path: [Route] [] var body: some View { NavigationStack(path: $path) { HomeView() .navigationDestination(for: Route.self) { route in switch route { case .detail(let id): DetailView(id: id) case .settings: SettingsView() case .profile(let userID): ProfileView(userID: userID) } } } } }跳转时不再写NavigationLink而是修改pathButton(打开详情) { path.append(.detail(id: item.id)) }返回时可以用path.removeLast()回到根页面用path.removeAll()。这套模式的好处是目标页面完全由 Route 决定页面间传参限制在枚举关联值里新增页面只需要加一个 case 和对应映射可读性非常好。如果你要支持多种不同类型的参数NavigationPath也能做到但我个人更喜欢[Route]因为它是强类型的编译器会帮我检查错误。NavigationPath 虽然灵活但里面装的东西只能靠运行时判断对大型项目不友好。5.3 迁移时最容易踩的兼容性差异迁移 NavigationView 到 NavigationStack 不是简单替换类名有不少细节差异。首先是环境值dismiss的行为变化。在 NavigationView 中dismiss在 push 页面和 sheet 中都能用在 NavigationStack 中dismiss的语义更加明确它会 pop 到上一级或关闭弹窗但如果你同时用了path数组推荐直接操作path.removeLast()避免两边状态不同步。第二点是navigationTitle的作用位置。以前在 NavigationView 里有人习惯把标题写在子页面内容上NavigationStack 中这种写法依然有效但如果你用navigationDestination统一注册页面也要在每个目标页面上单独设置标题不能在容器层直接设置所有子页面的标题。第三点是navigationBarTitleDisplayMode和toolbar的生效时机NavigationStack 中这些修饰符的推荐作用范围是“当前视图到最近的一个可识别导航容器”如果视图被复用可能会出现预期外的状态残留。迁移时建议先回归所有页面标题和按钮不要只验证跳转逻辑。6. 导航架构的最终建议什么时候该用 Router6.1 模块化路由到底值不值得做很多人一看到 NavigationStack 能管理路径数组就立刻开始写 Router 类把所有页面都塞进一个枚举。这种思路在小项目里可能有一点收益但项目复杂后全局路由表会变得非常臃肿每加一个页面都要改 Router 和 destination 映射反而拖慢开发速度。我的判断标准是如果项目只有两层或者三层导航直接用 NavigationLink 就好path 数组都不需要。当页面前置条件复杂比如登录后才能进入、特定角色才能看到某些页面或者多个模块需要互相跳转时再上 Router。Router 的核心价值不是“统一跳转”而是把“允许跳转”这个决策逻辑集中起来。一个实用的折中方案是每个模块内部维护自己的 Route 枚举和 destination 映射模块间跳转通过一个轻量的 AppRouter 协调。这样既不会出现全局路由表爆炸又能保持跨模块跳转的可控性。6.2 与 TabView、Modal 组合使用的场景选择NavigationView 和 NavigationStack 都经常与 TabView 一起出现。我自己的经验是每个 Tab 都保留独立的导航容器不要让 TabView 去包裹一个全局 NavigationView。这样每个 Tab 的导航状态互不干扰用户切换 Tab 后还能回到之前浏览的页面。TabView { NavigationStack { HomeView() } .tabItem { Label(首页, systemImage: house) } NavigationStack { SettingsView() } .tabItem { Label(设置, systemImage: gear) } }至于 Modal 和 push 的选择我的习惯是凡是需要用户完整执行“取消或完成”这种独立流程的场景用 fullScreenCover 或 sheet凡是上下级内容关系的场景用 push。比如编辑用户信息适合 sheet查看一条订单详情则适合 push。两者不要混着用否则用户在返回时的心理预期会被打乱。6.3 一点个人经验从 NavigationView 迁移到 NavigationStack 这件事我不建议搞一刀切。老项目里 NavigationView 写了几十个页面全部迁移需要测试所有跳转路径风险很大。更实际的做法是新页面一律用 NavigationStack 和 Route 枚举老页面保留 NavigationView但当某个页面因为新增需求需要大改时顺手把它迁移到 NavigationStack。我就是用这个节奏分批推进的每次改动范围可控回归成本也低。最后分享一个小技巧在 iOS 16 以上的 NavigationStack 中如果某个页面需要从外部传值并自动返回可以用一个Published var path放到共享的 ViewModel 里但在修改 path 之前先判断当前是不是在目标页面避免重复 push。类似这样的边界情况往往是真实项目里最容易出 bug 的地方多打日志、多复现比背 API 更有用。

相关新闻

银行卡号识别之图像预处理:从灰度化到字符分割的完整管线

银行卡号识别之图像预处理:从灰度化到字符分割的完整管线

这个系列前两篇我们把整个银行卡号识别系统的主流程、相机采集和卡面区域定位讲完了,这篇进入真正决定识别率下限的一段,也就是输入图像的处理。这一步我是这么理解的,模板匹配或OCR算法再强,喂进去的图像如果没做过几何校正、光照…

2026/10/18 22:08:28 阅读更多 →
COMSOL电树枝相场模型:从击穿图到参数扫描的完整实现

COMSOL电树枝相场模型:从击穿图到参数扫描的完整实现

简介:这份资源面向材料科学、高压绝缘与电气工程方向的研究者及研究生,提供基于COMSOL的相场模拟电树枝与二维电介质介电击穿建模素材,帮助理解电树枝在二维空间内的萌生与扩展机制,并为实验提供理论对照。压缩包共9个文件&#x…

2026/10/18 22:08:28 阅读更多 →
Cocos2d-x Lua脚本保护:LuaJIT字节码加密完整实践

Cocos2d-x Lua脚本保护:LuaJIT字节码加密完整实践

做游戏客户端的人,对“Lua脚本裸奔”这件事应该都不陌生。只要是Cocos2d-x配Lua的项目,发布到渠道包之后,scripts目录下面那些.lua文件几乎是明文躺在包里的,谁拿到包谁就能把代码直接复制走。这也意味着你的新手引导逻辑、付费判…

2026/10/18 22:08:28 阅读更多 →

最新新闻

78B多模态大模型如何落地?InternVL2_5-78B-MPO多卡部署与省显存量化完整攻略

78B多模态大模型如何落地?InternVL2_5-78B-MPO多卡部署与省显存量化完整攻略

【免费下载链接】InternVL2_5-78B-MPO 项目地址: https://ai.gitcode.com/OpenGVLab/InternVL2_5-78B-MPO 点击查看 免费下载 InternVL2_5-78B-MPO 是一款基于 ViT-MLP-LLM 架构的开源多模态大模型,融合了 6B 视觉编码器 InternViT 与 72B 语言模型 Qwe…

2026/10/18 23:08:17 阅读更多 →
定长140字节上报协议n值解析:字段偏移、熵值定位与纯算还原

定长140字节上报协议n值解析:字段偏移、熵值定位与纯算还原

简介:这是一份阿里140-n值纯算生成逻辑的代码解析包,面向反爬虫工程师、前端加密研究者与算法学习者。包内完整呈现n值生成全链路:从自定义base64加密算法入手,逐步拆解Ye、ke、B、u四个核心数组的来源与组装规则,涵盖…

2026/10/18 23:08:17 阅读更多 →
无监督深度单应性估计:PyTorch实战与几何建模原理

无监督深度单应性估计:PyTorch实战与几何建模原理

1. 项目概述:为什么“无监督深度单应性估计”值得你花30分钟认真读完“Unsupervised Deep Homography - Pytorch实现”——这个标题里藏着计算机视觉领域一个非常典型的“理想与现实撕扯点”。单应性(Homography)是什么?简单说&am…

2026/10/18 23:08:17 阅读更多 →
AUBO i5与D435i抓取实践:手眼标定、点云分割与避坑指南

AUBO i5与D435i抓取实践:手眼标定、点云分割与避坑指南

简介:面向机械臂视觉抓取开发者的可运行源码包,整合aubo i5机械臂与Intel RealSense D435i深度相机的识别抓取实践。压缩包仅6KB,内含3个文件,以html说明与inscode工程配置为主,附带gitignore版本管理配置,…

2026/10/18 23:08:17 阅读更多 →
Agent Skill 完全指南:让 AI 智能体“一次学会,处处复用“

Agent Skill 完全指南:让 AI 智能体“一次学会,处处复用“

目录 一、 Agent Skill入门 1.1 Agent Skill 到底是什么? 1.2 Agent Skill长什么样? 1.2.1 文件架构 1.2.2 SKILL.md文件格式 (1) Frontmatter字段 (2) Body content 1.2.3 Skill Demo 二、怎么用Agent Skill? 2.1 安装Agent 2.2 …

2026/10/18 23:08:17 阅读更多 →
推荐一个适合学习AI Agent开发的AI智能体开源项目:用TaoToken统一Key跑通DeepAgent实战

推荐一个适合学习AI Agent开发的AI智能体开源项目:用TaoToken统一Key跑通DeepAgent实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 23:07:17 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →