You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI:如何让List中的Spacer在编辑模式下不可选中?

解决SwiftUI List编辑模式下末尾Spacer可选中的问题

问题描述

在iOS15.0及以上的SwiftUI应用中,为了让List能滚动到底部(即使最后一行文本是多行内容),我在列表末尾添加了Spacer。但进入编辑模式后,这个Spacer所在的行也会显示复选框,并且会和最后一项一起被选中。尝试给Spacer添加.disabled(true)修饰符没有效果,需要让这个Spacer不可选中且不影响其他列表项。

问题截图说明

  • 进入编辑模式效果:List中所有行(包括末尾Spacer所在行)左侧都显示复选框
  • 选中最后一项或Spacer效果:最后一项和Spacer所在行的复选框均被勾选

原实现代码

struct TestScrollView: View {
    @State private var multiSelection = Set<String>()
    @State private var editMode = EditMode.inactive
    @State var messages: [String] = ["Item 1", "Item 2", "Item 3"]
    var body: some View {
        ScrollViewReader { scrollView in
            Button {
                editMode = EditMode.active
            } label: {
                Text("edit")
            }

            List(messages, id: \.self, selection: $multiSelection) { message in
                Text(message)
                .listRowSeparator(.hidden)
                
                if(message == messages.last) {
                    Spacer()
                        .id("end_text")
                        .disabled(true)
                }
            }.onAppear() {
                scrollView.scrollTo("end_text", anchor: .bottom)
            }.environment(\.editMode, $editMode)
        }
    }
}

解决方案

核心问题是原代码将Spacer嵌套在最后一个列表项的内容中,导致它属于该可选中项的一部分。正确的做法是将Spacer作为独立的列表行,并通过修饰符禁用其选中状态:

struct TestScrollView: View {
    @State private var multiSelection = Set<String>()
    @State private var editMode = EditMode.inactive
    @State var messages: [String] = ["Item 1", "Item 2", "Item 3"]
    
    var body: some View {
        ScrollViewReader { scrollView in
            Button {
                editMode = EditMode.active
            } label: {
                Text("edit")
            }
            
            // 改为显式声明List的selection,分离可选中项和Spacer行
            List(selection: $multiSelection) {
                // 遍历所有可选中的列表项
                ForEach(messages, id: \.self) { message in
                    Text(message)
                        .listRowSeparator(.hidden)
                }
                
                // 独立的Spacer行,不参与选中
                Spacer()
                    .id("end_text")
                    .listRowSeparator(.hidden)
                    .disabled(true) // iOS15下禁用选中,复选框变灰不可点击
                    .listRowSelectable(false) // iOS16+直接隐藏复选框,完全禁用选中
            }
            .onAppear() {
                scrollView.scrollTo("end_text", anchor: .bottom)
            }
            .environment(\.editMode, $editMode)
        }
    }
}

关键修改点

  1. 将原List(messages, id: \.self, selection: $multiSelection)拆分为List(selection: $multiSelection)内部嵌套ForEach,明确区分可选中的列表项和独立的Spacer行。
  2. 将Spacer从最后一个列表项的内容中移出,作为单独的列表行存在,避免和可选中项绑定。
  3. 针对不同iOS版本添加适配:
    • iOS15:使用.disabled(true)让Spacer行的复选框变灰,无法被选中。
    • iOS16+:使用.listRowSelectable(false)直接隐藏复选框,彻底禁用该行的选中功能。

这样修改后,Spacer既可以实现滚动到底部的效果,又不会在编辑模式下被选中,同时不影响其他列表项的正常选中功能。

内容的提问来源于stack exchange,提问作者Zedom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 02:17:38