Средство выбора SwiftUI разделяет тексты для выбранного элемента и представления выбора - PullRequest
2 голосов
/ 18 июня 2020

У меня Picker встроено в Form внутри NavigationView. Я хотел бы иметь отдельный текст для выбранного элемента в основном View и более подробные описания при выборе элементов в сборщике View.

Это то, что я пробовал до сих пор:

struct Item {
    let abbr: String
    let desc: String
}
struct ContentView: View {
    @State private var selectedIndex = 0
    let items: [Item] = [
        Item(abbr: "AA", desc: "aaaaa"),
        Item(abbr: "BB", desc: "bbbbb"),
        Item(abbr: "CC", desc: "ccccc"),
    ]

    var body: some View {
        NavigationView {
            Form {
                picker
            }
        }
    }

    var picker: some View {
        Picker(selection: $selectedIndex, label: Text("Chosen item")) {
            ForEach(0..<items.count) { index in
                Group {
                    if self.selectedIndex == index {
                        Text(self.items[index].abbr)
                    } else {
                        Text(self.items[index].desc)
                    }
                }
                .tag(index)
            }
            .id(UUID())
        }
    }
}

Текущее решение

Это средство выбора на главном экране:

Chosen item

And this is the selection view:

Picker selection

The problem is that with this solution in the selection view there is "BB" instead of "bbbbb".

This occurs because the "BB" text in both screens is produced by the very same Text view.

Expected result

The picker in the main view:

Chosen item

And in the selection view:

Ожидаемый результат

Возможно ли в SwiftUI иметь отдельные тексты (представления) для обоих экранов?

Ответы [ 2 ]

1 голос
/ 25 июня 2020

Расширение на Ответ Йонаса Дайхельмана Я создал свой собственный сборщик:

struct CustomPicker<Item>: View where Item: Hashable {
    @State var isLinkActive = false
    @Binding var selection: Int
    let title: String
    let items: [Item]
    let shortText: KeyPath<Item, String>
    let longText: KeyPath<Item, String>

    var body: some View {
        NavigationLink(destination: selectionView, isActive: $isLinkActive, label: {
            HStack {
                Text(title)
                Spacer()
                Text(items[selection][keyPath: shortText])
                    .foregroundColor(Color.gray)
            }
        })
    }

    var selectionView: some View {
        Form {
            ForEach(0 ..< items.count) { index in
                Button(action: {
                    self.selection = index
                    self.isLinkActive = false
                }) {
                    HStack {
                        Text(self.items[index][keyPath: self.longText])
                        Spacer()
                        if self.selection == index {
                            Image(systemName: "checkmark")
                                .foregroundColor(Color.blue)
                        }
                    }
                    .contentShape(Rectangle())
                    .foregroundColor(.primary)
                }
            }
        }
    }
}

Затем мы должны сделать Item соответствовать Hashable:

struct Item: Hashable { ... }

И мы можем использовать его так:

struct ContentView: View {
    @State private var selectedIndex = 0
    let items: [Item] = [
        Item(abbr: "AA", desc: "aaaaa"),
        Item(abbr: "BB", desc: "bbbbb"),
        Item(abbr: "CC", desc: "ccccc"),
    ]

    var body: some View {
        NavigationView {
            Form {
                CustomPicker(selection: $selectedIndex, title: "Item", items: items,
                             shortText: \Item.abbr, longText: \Item.desc)
            }
        }
    }
}

Примечание: В настоящее время макет средства выбора нельзя изменить. При необходимости его можно сделать более универсальным c, например, используя. @ViewBuilder.

1 голос
/ 24 июня 2020

Возможное решение без средства выбора

Как упоминалось в моем комментарии , пока нет решения для собственной реализации с помощью средства выбора SwiftUI. Вместо этого вы можете сделать это с помощью элементов SwiftUI, особенно с помощью NavigationLink. Вот пример кода:

struct Item {
    let abbr: String
    let desc: String
}

struct ContentView: View {
    
    @State private var selectedIndex = 0
    let items: [Item] = [
        Item(abbr: "AA", desc: "aaaaa"),
        Item(abbr: "BB", desc: "bbbbb"),
        Item(abbr: "CC", desc: "ccccc"),
    ]
    
    var body: some View {
        NavigationView {
            Form {
                NavigationLink(destination: (
                    DetailSelectionView(items: items, selectedItem: $selectedIndex)
                    ), label: {
                        HStack {
                            Text("Chosen item")
                            Spacer()
                            Text(self.items[selectedIndex].abbr).foregroundColor(Color.gray)
                        }
                })
            }
        }
    }
}

struct DetailSelectionView: View {
    var items: [Item]
    @Binding var selectedItem: Int
    
    var body: some View {
        Form {
            ForEach(0..<items.count) { index in
                HStack {
                    Text(self.items[index].desc)
                    Spacer()
                    if self.selectedItem == index {
                        Image(systemName: "checkmark").foregroundColor(Color.blue)
                    }
                }
                .onTapGesture {
                    self.selectedItem = index
                }
            }
        }
    }
}

Если есть какие-либо улучшения, не стесняйтесь редактировать фрагмент кода.

...