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

一发入魂:极简解决 SwiftUI 复杂视图未能正确刷新的问题(上)

在这里插入图片描述

概述

各位似秃非秃小码农们都知道,在 SwiftUI 中视图是状态的函数,这意味着状态的改变会导致界面被刷新。

但是,对于有些复杂布局的 SwiftUI 视图来说,它们的界面并不能直接映射到对应的状态上去。这就会造成一个问题:状态的改变并没有及时的引起 UI 的变化。

在这里插入图片描述

如上图所示:无论英雄挑战关卡的结果是成功还是失败,在视图的显示中都没有体现出来。这该如何是好呢?

在本篇博文中,您将学到如下内容:

  • 概述
  • 1. “固执己见”的 SwiftUI 视图
    • 1.1 关卡视图 StageView
    • 1.2 世界视图 WorldView
  • 总结

相信学完本课后,大家都会掌握只需寥寥几行代码就让 SwiftUI 复杂视图乖乖听话的奥义!

那还等什么呢?Let‘s go!!!😉


1. “固执己见”的 SwiftUI 视图

在上面的示例图中,英雄可以恣意挑战当前关卡,如果挑战成功则进入下一关卡,如果失败则会刷新挑战次数。前者应该在世界视图 WorldView 上有所体现,而后者则必须在关卡视图 StageView 中立即反映出来:

Button {if try! hero.challengeStage() {try! hero.moveToNextStage()}
} label: {Label("挑战关卡!", systemImage: "figure.fencing").foregroundStyle(.white)
}

可惜的是,无论何种情况所有视图都将成为不舞之鹤,无动于衷。这是“肿”么回事呢?

1.1 关卡视图 StageView

我们先到 StageView 中看看与此相关的 UI 布局代码:

let records = stage.queryAllChallengingRecords()if records.isEmpty {ContentUnavailableView("一片寂静,无人在此逗留...", systemImage: "eyes")
} else {ForEach(records) { record inif let hero = record.hero {VStack {heroCell(hero)HStack {Text("失败次数: \(record.challengeFailedCount)")Spacer(minLength: 0)if let timeString = try! hero.getStageStayRelevantTimeString(stage) {Text("已徘徊 \(timeString)")}}.foregroundStyle(.gray)}}}
}

理想的情况是:当英雄挑战关卡失败时,将会递增对应关卡挑战记录中挑战的次数,这会引起界面相关显示的变化。

在这里插入图片描述

但实际运行发现,界面并没有立即刷新。而只有当视图重建后,失败的挑战次数才能得以更新:

在这里插入图片描述

1.2 世界视图 WorldView

WorldView 视图是 StageView 的父视图,它的关键代码如下所示:

Form {let zones = world.zoneSortByNumberAryForEach(zones) { zone inSection {HStack {Image(systemName: "map")Text("\(zone.number). \(zone.name ?? "")")}.font(.title2.bold())if let desc = zone.desc, !desc.isEmpty {Text(desc).foregroundStyle(.gray)}ScrollView {LazyVGrid(columns: [GridItem](repeating: .init(), count: 3)) {ForEach(zone.stageSortByNumberAry) { stage inNavigationLink {StageView(stage: stage)} label: {VStack(alignment: .leading) {HStack {stageLogoImage(stage)Text("\(stage.number)")}.frame(maxWidth: .infinity, alignment: .leading).font(.title3.bold()).foregroundStyle(stageColor(stage))Text("\(stage.name ?? "")").monospaced().minimumScaleFactor(0.8).foregroundStyle(stageColor(stage))Spacer()HStack {let challengingHeros = stage.queryAllChallengingRecords().countlet victoryHeros = stage.queryAllVictoryRecords().countVStack(alignment: .leading) {Image(systemName: "person.3")Text("\(challengingHeros)/\(victoryHeros)")}.minimumScaleFactor(0.5).font(.subheadline).foregroundStyle(.teal)Spacer(minLength: 0)let includeHeros = stageChallengingMyHerosCount(stage)if includeHeros > 0 {HStack(spacing: 0) {Image(systemName: "star.hexagon")Text("\(includeHeros)")}.font(.subheadline).foregroundStyle(.yellow)}}}.padding().frame(maxWidth: .infinity).frame(height: 150).background(.thinMaterial, in: RoundedRectangle(cornerRadius: 11))}}}}.listRowSeparator(.hidden)}}
}
.navigationTitle("世界地图")

在上面的代码中,我们主要做了这样几件事:

  • 获取 World 中的所有区域(Zones),并将结果存入 zones 局部变量中;
  • 获取每个 Zone 中的所有关卡(Stages),并将它们放入 LazyVGrid 容器中以便显示;
  • 如果我们的英雄恰巧正在挑战某一关卡,则在对应关卡 StageCell 里用黄色的五角星表示出来;

WorldView 视图的显示效果如下所示:

在这里插入图片描述

理想情况下,当英雄成功挑战某一关卡并从关卡视图返回世界视图后,世界视图中关卡 StageCell 中的黄色五角星应该自动移动到下一关。但是,从演示图中可以看到,这些都没有发生。这表示 WorldView 视图内容在 Hero 挑战成功后也没有被及时地刷新:

在这里插入图片描述

那么,我们不禁要问:到底是什么导致了 StageView 和 WorldView 视图刷新不及时呢?

在下一篇博文中,我们将继续介绍导致上述问题的根本原因,并先提出几个不那么优雅地解决方案唏嘘一番。不见不散!

总结

在本篇博文中,我们发现了一个 SwiftUI 复杂视图中状态的改变并未正确引起界面刷新的现象,并随后深入代码初步分析了故事的前因后果。

感谢观赏,我们下一篇再见!😎

http://www.xdnf.cn/news/445609.html

相关文章:

  • LabVIEW中样条插值实现及应用
  • Qwen集成clickhouse实现RAG
  • C# 调试技巧——日志记录,NuGet内断点
  • 【HCIA】BFD
  • 化工单元操作实训装置JGSX-205计算机过程控制流体输送操作实训装置
  • 环境配置与MySQL简介
  • 信息安全入门基础知识
  • Python操作MySQL 连接加入缓存层完整方案
  • 【MySQL】(11) 索引
  • 【Java学习笔记】equals方法
  • ElasticSearch重启之后shard未分配问题的解决
  • Rocky Linux 9.5 基于kubeadm部署k8s
  • 3天云南旅游规划
  • Kafka 消费者组进度监控方法解析
  • 【SSL部署与优化​】​​TLS 1.3的核心改进与性能优化​​
  • Java构造器封装继承重写多态
  • Doris
  • Kotlin 中 infix 关键字的原理和使用场景
  • A2DP、HFP、AVRCP分别是什么
  • STL,智能指针和线程安全自选锁读者写者问题
  • 蓝桥杯13届国B 完全日期
  • 【vue】生命周期钩子使用
  • 【行为型之访问者模式】游戏开发实战——Unity灵活数据操作与跨系统交互的架构秘诀
  • 关于Python 实现接口安全防护:限流、熔断降级与认证授权的深度实践
  • 2024年业绩增速大幅回退,泸州老窖未能“重回前三”
  • 使用Rust开发的智能助手系统,支持多模型、知识库和MCP
  • Go 语言 sqlx 库使用:对 MySQL 增删改查
  • Spring Boot requestBody postman
  • 人机环境体系的自主决策与机器系统的自主决策不同
  • 第二章:CSS秘典 · 色彩与布局的力量