SwiftUI 从列表中删除行 [英] SwiftUI delete rows from a list

查看:22
本文介绍了SwiftUI 从列表中删除行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

正如您从图片中看到的,我有一个颜色列表,我希望还可以提供从 array 中删除颜色的可能性.

As you can see from the image I have a list of colors, I would like to be able to also give the possibility to delete a color from the array.

我尝试添加一个列表,然后在 ForEach 上调用 onDelete 调用,但效果不佳,给我带来了问题.

I tried to add a list and then call the onDelete call on ForEach, but it's not working well it gives me problems.

然后除此之外,我希望列表是包含元素的大小.

Then in addition to this I would like the list to be the size of the contained elements.

错误:

Fatal error: Index out of range: file Swift/ContiguousArrayBuffer.swift, line 444

谁能给我一些建议?

代码:

import SwiftUI

struct ContentView: View {
    var cornerRadius: CGFloat = 16
    
    @State public var select = 2
    @State public var bgColors: [Color] =
        [
            Color(red: 21.0/255.0, green: 101.0/255.0, blue: 192.0/255.0),
            Color(red: 255.0/255.0, green: 193.0/255.0, blue: 7.0/255.0),
            Color(red: 76.0/255.0, green: 175.0/255.0, blue: 80.0/255.0)
        ]
    @Environment(.colorScheme) var colorScheme
    
    @State var isShowPicker: Bool = false
    @State var image: Image? = Image("placeholder")
    
    @State private var url: String = "https://a.wattpad.com/useravatar/climaxmite.256.718018.jpg"
    
    init() {
        // Segmented control colors
        UISegmentedControl.appearance().backgroundColor = .systemGray6
        UISegmentedControl.appearance().selectedSegmentTintColor = UIColor(Color.blue)
        UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor.systemBackground], for: .selected)
        UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor.label], for: .normal)
    }
    
    var body: some View {
        VStack{
            
            ZStack {
                RoundedRectangle(cornerRadius: cornerRadius)
                    .frame(width: UIScreen.main.bounds.width-40, height: 100, alignment: .center)
                    .foregroundColor(colorScheme == .dark ? .black : .white)
                VStack(spacing: 12) {
                    ZStack {
                        Rectangle()
                            .frame(width: UIScreen.main.bounds.width-47, height: 35, alignment: .center)
                            .foregroundColor(Color(UIColor.systemGray6))
                            .cornerRadius(cornerRadius, corners: [.topLeft, .topRight])
                        Text("Select Background")
                            .foregroundColor(Color(UIColor.label))
                            .font(.subheadline)
                            .bold()
                    }
                    Picker(selection: $select, label: Text("Select Background")) {
                        Text("Url").tag(0)
                        Text("Select Image").tag(1)
                        Text("Gradient").tag(2)
                    }.pickerStyle(SegmentedPickerStyle())
                    .padding(EdgeInsets(top: 0, leading: 30, bottom: 0, trailing: 30))
                    Spacer()
                        .frame(height: 3)
                }
            }
            
            if self.select == 0 {
                VStack{
                    ZStack {
                        RoundedRectangle(cornerRadius: cornerRadius)
                            .frame(width: UIScreen.main.bounds.width-40, height: 42, alignment: .center)
                            .foregroundColor(Color(UIColor.systemBackground))
                        TextField("http://", text: $url)
                            .padding(10)
                            .frame(width: UIScreen.main.bounds.width-40)
                            .foregroundColor(Color(UIColor.label))
                            .cornerRadius(cornerRadius)
                            .padding(EdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 10))
                    }
                    
                    Button(action: {
                        
                    }, label: {
                        Text("Submit")
                            .foregroundColor(Color(UIColor.systemBackground))
                            .bold()
                    })
                    .padding(EdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 20))
                    .foregroundColor(.white)
                    .font(.subheadline)
                    .background(Color.blue)
                    .cornerRadius(cornerRadius)
                }
            }
            
            if self.select == 1 {
                VStack {
                    Button(action: {
                        withAnimation {
                            self.isShowPicker.toggle()
                        }
                    }) {
                        Image(systemName: "photo")
                            .font(.headline)
                            .foregroundColor(colorScheme == .dark ? .white : .black)
                        Text("Import")
                            .font(.headline)
                            .foregroundColor(colorScheme == .dark ? .white : .black)
                        
                    }
                    .foregroundColor(.black)
                }
                .sheet(isPresented: $isShowPicker) {
                    ImagePicker(image: self.$image)
                }
            }
            
            if self.select == 2 {
                VStack(alignment: .trailing){
                    Button(action: {
                        bgColors.append(Color.clear)
                    }) {
                        Image(systemName: "plus")
                            .font(.headline)
                            .foregroundColor(colorScheme == .dark ? .white : .black)
                            .padding(EdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 15))
                    }
                    
                    List {
                        
                        ForEach(Array(bgColors.enumerated()), id: .offset) { index, element in
                            ZStack {
                                ColorPicker("Set the background color", selection: $bgColors[index])
                            }
                            .padding(EdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 10))
                        }                .onDelete(perform: delete)
                    }.background(Color.blue)
                    
                }
            }
            
            Spacer()
        }
        .padding(.top, 25)
        .ignoresSafeArea(.keyboard)
        .background(Color(UIColor.systemGray6))
        .edgesIgnoringSafeArea(.all)
    }
    
    func delete(at offsets: IndexSet) {
        bgColors.remove(atOffsets: offsets)
    }
}

struct RoundedCorner: Shape {
    var radius: CGFloat = .infinity
    var corners: UIRectCorner = .allCorners
    
    func path(in rect: CGRect) -> Path {
        let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
        return Path(path.cgPath)
    }
}

extension View {
    func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View {
        clipShape( RoundedCorner(radius: radius, corners: corners) )
    }
}

// extension for keyboard to dismiss
extension UIApplication {
    func endEditing() {
        sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
    }
}

struct ImagePicker: UIViewControllerRepresentable {
    
    @Environment(.presentationMode)
    var presentationMode
    
    @Binding var image: Image?
    
    class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
        
        @Binding var presentationMode: PresentationMode
        @Binding var image: Image?
        
        init(presentationMode: Binding<PresentationMode>, image: Binding<Image?>) {
            _presentationMode = presentationMode
            _image = image
        }
        
        func imagePickerController(_ picker: UIImagePickerController,
                                   didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            let uiImage = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
            image = Image(uiImage: uiImage)
            presentationMode.dismiss()
            
        }
        
        func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
            presentationMode.dismiss()
        }
        
    }
    
    func makeCoordinator() -> Coordinator {
        return Coordinator(presentationMode: presentationMode, image: $image)
    }
    
    func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
        let picker = UIImagePickerController()
        picker.delegate = context.coordinator
        return picker
    }
    
    func updateUIViewController(_ uiViewController: UIImagePickerController,
                                context: UIViewControllerRepresentableContext<ImagePicker>) {
        
    }
    
}

推荐答案

问题是在你的 List 中,你给它的 id.偏移.但是,由于您正在从 bgColors 中删除数据,因此该数据可能会发生变化.相反,您应该将 id 设置为 .element 因为它对于每种颜色都是恒定的.

The problem is that in your List, the id you give it is .offset. However, since you are removing data from bgColors, so this data can change. Instead, you should set the id as .element because it will be constant for each color.

考虑这个简化的例子,当你从列表中删除一个 Color 时它会崩溃:

Consider this simplified example, which crashes when you remove a Color from the list:

struct ContentView: View {
    
    @State private var arr: [Color] = [.red, .green, .blue]

    var body: some View {
        List {
            ForEach(Array(arr.enumerated()), id: .offset) { (index, _) in
                ColorPicker("Color", selection: $arr[index])
            }
            .onDelete(perform: delete)
        }
    }
    
    private func delete(at offsets: IndexSet) {
        arr.remove(atOffsets: offsets)
    }
}

和工作示例,其中更改是给 Listid 和新的 Binding 给颜色:

And the working example, where the changes are the id given to the List, and the new Binding to the color:

struct ContentView: View {

    @State private var arr: [Color] = [.red, .green, .blue]

    var body: some View {
        List {
            ForEach(Array(arr.enumerated()), id: .element) { (index, _) in
                ColorPicker(
                    "Color",
                    selection: Binding<Color>(
                        get: { arr[index] },
                        set: { arr[index] = $0 }
                    )
                )
            }
            .onDelete(perform: delete)
        }
    }

    private func delete(at offsets: IndexSet) {
        arr.remove(atOffsets: offsets)
    }
}

这篇关于SwiftUI 从列表中删除行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆