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

查看:92
本文介绍了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

有人可以给我一些建议吗?

Can anyone give me some advice?

代码:

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)
    }
}

还有一个工作示例,其中的更改是赋予 List id ,以及赋予颜色的新的 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天全站免登陆