别让错误藏在屏幕外:用 AI + ScrollViewReader 把 iOS 表单定位到首个问题

别让错误藏在屏幕外:用 AI + ScrollViewReader 把 iOS 表单定位到首个问题

这一技教你让 AI 用 SwiftUI ScrollViewReader 把提交失败后的第一个表单错误滚到可见位置,并用稳定字段 ID和 Xcode 场景清单独立验收。

提交失败时,先把第一个问题送到眼前

一个很常见的表单缺陷是:用户点了提交,页面没有明显变化,真正的错误信息却藏在屏幕下方。用户只看到按钮没反应,又点一遍,甚至直接退出。
今天这招解决的是「错误已经出现,但用户看不见」:让 AI 给表单内容加上稳定的字段 ID,提交失败后找到页面顺序里的第一个错误,再用 SwiftUI ScrollViewReader 把它滚到可见位置。ScrollView 本身就是用于承载可滚动内容的视图;ScrollViewReader 则提供一个代理,让代码可以滚到指定的子视图。12
这不是把所有错误都弹出来,也不是自动替用户修改输入,而是提交失败后先回答一个产品问题:用户下一步应该看哪里?

先写一张表单错误表

打开 AI 编码工具前,先把表单字段按用户填写顺序列出来。不要只说「帮我加表单校验」,那会让 AI 自己猜错误优先级。
顺序字段什么时候算错错误出现在哪里
1姓名为空姓名输入框下方
2手机号格式不对手机号输入框下方
3公司为空公司输入框下方
4邮箱格式不对邮箱输入框下方
5备注超过长度限制备注输入框下方
然后定一条规则:一次提交可以展示多个错误,但只自动滚到最靠前的那个。这样用户不会被连续跳转打断,也不会在错误顺序上迷路。
如果页面本来就按这个顺序显示字段,firstError 可以直接取校验结果里第一个字段;如果校验结果来自字典或异步接口,就让 AI 先按页面字段顺序重新排序,再决定第一个错误。

让 AI 只改滚动和错误反馈

把下面这段缺陷单交给 AI,再附上你的表单字段表和相关 View 文件:
请修复「资料编辑页」的表单反馈问题:用户点击提交后,如果有多个字段不合法,页面要保留所有错误提示,但自动滚动到页面顺序里的第一个错误字段。
请使用 SwiftUI ScrollViewReader 包住现有的表单滚动内容,并给每个可定位的字段行加稳定的 .id。错误 ID 必须和字段 ID 一一对应,不要使用会随着数组排序变化的下标作为唯一标识。
请把校验结果整理成按页面显示顺序排列的错误列表,得到 firstError 后,在它发生变化时调用 scrollTo,让错误行落在可见区域。保留现有输入、接口请求、提交按钮样式和业务规则,不要重写整个页面。
请按照项目的最低 iOS 部署版本选择正确的 onChange 写法,并解释你修改了哪些文件、为什么在这个时机滚动。
如果当前页面使用的是 Form,请先说明它是否适合当前的精确定位需求;未经确认不要直接把整页改成另一种容器。
scrollTo 会在代理包含的滚动视图中查找带有指定 identifier 的子视图,再滚动到它。3 所以这次改动里最容易漏掉的不是滚动调用,而是字段行没有稳定 ID,或者 ID 加在了错误的容器上。

看懂 AI 应该改成什么

你不需要逐行审 SwiftUI,只要顺着下面这条关系检查:
提交按钮
  -> 校验全部字段
  -> 按页面顺序得到 firstError
  -> firstError 变化
  -> ScrollViewReader.scrollTo(firstError)
  -> 首个错误行进入视口
代码结构可以接近下面这样,字段和业务名称按你的项目替换:
ScrollViewReader { proxy in
    ScrollView {
        VStack {
            NameField()
                .id(FieldID.name)

VStack(alignment: .leading, spacing: 8) {
                PhoneField()

if let error = errors[FieldID.phone] {
                    ErrorText(error)
                }
            }
            .id(FieldID.phone)

CompanyField()
                .id(FieldID.company)
        }
    }
    .onChange(of: firstError) { _, fieldID in
        guard let fieldID else { return }
        withAnimation {
            proxy.scrollTo(fieldID, anchor: .center)
        }
    }
}
这里有四个检查点:
  1. .id 要挂在包含输入框和错误文案的整行上,否则滚动到了输入框,错误文案仍可能在屏幕边缘。
  2. firstError 应该是字段 ID,而不是错误文字。文字会改,ID 才适合定位。
  3. 校验失败后先更新 errorsfirstError,再滚动。这样目标行已经带着错误文案进入视图层级。
  4. withAnimation 只负责让滚动过程容易看懂,不要用动画掩盖错误状态没有更新的问题。
onChange 的用途就是在指定值发生变化时触发动作。4 让 AI 按项目最低 iOS 版本选择闭包签名,避免为了套用网上旧代码而引入编译错误。

先审一遍改动,再运行

让 AI 生成代码后,先用这组问题做人工检查:
  • 每个需要定位的字段是否都有稳定 ID?
  • ID 是否来自字段枚举或明确的字段名,而不是数组下标?
  • firstError 是否按用户看到的页面顺序计算?
  • 错误文案是否和输入框在同一个可定位的行里?
  • 提交成功时是否不会触发滚动?
  • 用户修正第一个错误后再次提交,是否会滚到下一个错误?
  • AI 有没有顺手改掉原来的请求参数、按钮行为或提交防重复逻辑?
  • 页面如果使用 Form,AI 是否说明了容器限制,而不是未经确认直接重写布局?
有一个细节值得单独盯住:不要让 AI 把「第一个错误」写成 errors.first,除非它已经证明错误集合的顺序和页面顺序一致。字典、异步返回结果和服务端字段顺序都可能让这个假设失效。

用 Xcode 验收四个场景

不要只在字段都填错时点一次提交。用能稳定复现的假数据,按下面顺序检查:
  1. 只让最下面的字段出错,点击提交,确认页面自动滚到这个字段,错误文案完整可见。
  2. 让第 2、4、5 个字段同时出错,确认页面只自动滚到第 2 个字段,但其它错误仍保留。
  3. 修正第 2 个字段后再次提交,确认页面滚到第 4 个字段,而不是继续停在旧位置。
  4. 全部输入正确后提交,确认不会出现无意义的跳动,成功状态和原来的提交流程不变。
再补三种压力场景:小屏 iPhone、键盘打开、大字号文字。键盘可能遮住滚动后的输入框,大字号可能把错误文案撑成多行,.center 未必适合所有页面。让 AI 根据实际截图调整 anchor,但每次只改一个变量并重新验收。
如果页面支持 VoiceOver,再检查辅助功能焦点是否也能让用户找到错误。自动滚动只改变视觉位置,不等于自动把读屏焦点移动到了错误控件;这部分需要单独验收,不能把「页面滚到了」当成「所有用户都收到了反馈」。

这招的边界

ScrollViewReader 适合「目标字段已经在当前页面滚动内容里」的情况。它不能替你完成服务端校验,也不能自动猜出错误字段在分页、折叠区或导航栈的哪一层。
如果错误字段在折叠面板里,先展开面板再滚动;如果字段在另一个页面,先把导航路径处理好;如果错误来自服务端,先把服务端字段映射成页面字段 ID。让 AI 把这些前置动作写进缺陷单,别只追加一个 scrollTo 就宣布完成。
这次改动也不要求你把所有输入框都变成复杂组件。先挑一个提交后经常让用户「不知道哪里错了」的长表单,验证错误 ID、滚动时机和四个验收场景,确认有效后再扩展到其它页面。

PM 今天可以独立完成的清单

  • 找一个提交失败后错误信息经常在屏幕外的 iOS 表单。
  • 按页面顺序列出字段、校验条件和错误文案位置。
  • 把缺陷单交给 AI,要求保留所有错误,只滚到第一个问题。
  • 检查字段 ID 是否稳定,firstError 是否按页面顺序计算。
  • 检查 AI 有没有改动接口、业务规则和原提交行为。
  • 用小屏、大字号、键盘打开和多个错误同时出现的场景验收。
  • 单独验证 VoiceOver 用户能否找到错误,不把自动滚动当成无障碍焦点移动。
先拿一个真实的资料编辑页做这次改动。你要验收的结果很具体:点提交后,用户能立刻看到第一个需要修正的地方,而且页面不会因为自动滚动而丢掉其它错误。

관련 콘텐츠

  • 로그인하면 댓글을 작성할 수 있습니다.
More from this channel