SwiftUI - 如何在编辑模式下避免列表中的行缩进,但不使用 onDelete? (附代码/视频)

Posted

技术标签:

【中文标题】SwiftUI - 如何在编辑模式下避免列表中的行缩进,但不使用 onDelete? (附代码/视频)【英文标题】:SwiftUI - how to avoid row indenting in List when in Edit Mode, but not using onDelete? (code/video attached) 【发布时间】:2020-04-18 05:42:59 【问题描述】:

在 SwiftUI 中,当我进入编辑模式但不使用 onDelete 时,如何避免行内容在我的列表中缩进?这是目前我的行内容在发生这种情况时缩进,好像“删除”按钮将显示在左侧,但是我没有使用 onDelete 所以那里没有按钮。

动画 GIF

代码摘录在这里:

var body: some View 
    VStack
        List() 
            ForEach(gcTasks)  gcTask in
                HStack 
                    GCTaskRow(withGcTask: gcTask, haha: "")
                
            
            // .onDelete(perform: self.deleteTask)   // NOTE: HAVE REMOVED
            .onMove(perform: self.move)
        
    
    .environment(\.editMode, listInEditMode ? .constant(.active) : .constant(.inactive))

背景 - 实际上希望始终处于 EDIT 模式,即始终可以选择向上/向下拖动行,但是永远不会使用 Delete,因此要查看 onDelete 的所有痕迹,在这种情况下是自动缩进..

更新:另一个不想要的缩进是如何发生的例子(操场):

import SwiftUI
import PlaygroundSupport

let modelData: [String] = ["Eggs", "Milk", "Bread"]

struct ListTestNoDelete: View 
    private func move(from uiStartIndexSet: IndexSet, to uiDestIndex: Int) 
        print("On Move")
    
    var body: some View 
        NavigationView 
            VStack 
                List 
                    ForEach(modelData, id: \.self)  str in
                        Text(str)
                    
                    .onMove(perform: self.move)
                
                .environment(\.editMode, .constant(.active))
                .navigationBarTitle( Text("Test") )
            
        
    



let listTest = ListTestNoDelete()
PlaygroundPage.current.liveView = UIHostingController(rootView: listTest)

【问题讨论】:

【参考方案1】:

也许值得向 Apple 提交请求,但这是默认行为。目前可以使用以下解决方法。使用 Xcode 11.4 / ios 13.4 测试。

struct DemoListEditMode: View 

    @State var items = ["a","b","c","d","e"]

    var body: some View 
        List 
            ForEach(items, id: \.self)  z in
                HStack 
                    Image(systemName: "checkmark.square") // just for demo
                    Text("\(z)")
                
            .onMove(perform: self.move)
            .listRowInsets(EdgeInsets(top: 0, leading: -24, // workaround !!
                bottom: 0, trailing: 0))                    
        
        .environment(\.editMode, .constant(.active)) // persistent edit mode
    

    func move(source: IndexSet, destination: Int) 
        self.items.move(fromOffsets: source, toOffset: destination)
    

【讨论】:

实际上我发现在编辑模式下使用这种方法,当按下复选框时我的 Image onTapGesture 没有拾起? Image(systemName: gcTask.completed ? "checkmark.square" : "square") .onTapGesture print("Check box Tapped") self.gcTask.completed.toggle() GCCoreData.save() 似乎一旦“领先”值变得比大约 -8 更负,然后复选框停止拾取点击手势......有什么想法吗? (非常接近重新工作) @Greg 你有没有找到解决这个问题的方法?我有同样的问题。它看起来像一个隐藏的 UIView 覆盖了那个位置。【参考方案2】:

也许不是一个非常优雅的修复,但您可以将列表扩展到左侧。

List 
    // ...

// .padding(.leading, self.isEditing == .inactive ? 0 : -39)
.padding(.leading, self.isEditing ? -45 : 0)

【讨论】:

谢谢 - 刚刚看到这个 - 这似乎对 Casper 有效(稍作调整) @Greg 我认为每个屏幕尺寸的缩放比例可能不同,在我的测试中,我发现 39 是最接近的。 @CasperZandbergen,这里也是。我发现 44 非常适合 iPhone 11。【参考方案3】:
struct ContentView: View  
    
    /// this is the padding that the list adds in left for delete button when in the edit mode.
    /// I calculated the constant and works fine on iPhone11 but you will need to check for each device separately for accurate offset for every device.
    let listEditModeOffsetX = -UIScreen.main.bounds.width * 0.10647343
    
    @State var modelData: [String] = ["Eggs", "Milk", "Bread","Cake"]
    @State var editingList = false
    
    private func move(from source: IndexSet, to destination: Int) 
        modelData.move(fromOffsets: source, toOffset: destination)
        editingList = false
        print("On Move")
    
    
    var body: some View 
        NavigationView 
            VStack 
                List 
                    ForEach(modelData, id: \.self)  str in
                        Text(str)
                            .offset(x: self.editingList ? listEditModeOffsetX : 0)
                    
                    .onMove(perform: self.move)
                    .onLongPressGesture
                        self.editingList = true
                    
                    
                
                .environment(\.editMode, editingList ? .constant(.active):.constant(.inactive))
                .navigationBarTitle( Text("Test") )
            
        
    

【讨论】:

以上是关于SwiftUI - 如何在编辑模式下避免列表中的行缩进,但不使用 onDelete? (附代码/视频)的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI - 如何在编辑模式下更改列表的背景

从 SwiftUI 中的工作表更新列表视图中的行

SwiftUI:Firebase ForEach 列表执行编辑功能无法编辑选定的行项目

SwiftUI,列表行添加按钮

SwiftUI - 如何在列表中编辑行?

SwiftUI - 列表编辑模式 - 如何更改删除按钮标题?