英文:
Detect when user pick same value in Picker to change sort order
问题
我正在尝试在菜单内部使用 Picker 对列表进行排序,如图所示。
选择器正在工作,排序也在工作,缺失的部分是排序顺序。
目标行为:
当用户选择一个排序字段时,排序顺序将为升序,但当他再次选择相同的字段时,排序顺序应为降序。
我如何检测用户是否在选择器中再次选择了相同的字段?或者是否有更好的方法。
谢谢
以下是我的示例代码:
struct Book: Identifiable {
let id = UUID()
let title, author: String
let sales: Int
}
enum SortField: String, CaseIterable {
case title, author, sales
}
struct ContentView: View {
@State private var items: [Book] = [
.init(title: "Da Vinci Code,The", author: "Brown, Dan", sales: 5094805),
.init(title: "Harry Potter and the Deathly Hallows", author: "Rowling, J.K.", sales: 4475152),
.init(title: "Angels and Demons", author: "Brown, Dan", sales: 3193946),
.init(title: "One Day", author: "Nicholls, David", sales: 1616068),
.init(title: "Billy Connolly", author: "Stephenson, Pamela", sales: 1231957),
]
@State private var selectedSortField: SortField = .title
@State private var ascending: Bool = false
var body: some View {
NavigationView {
Form {
ForEach(items) { item in
HStack {
VStack(alignment: .leading) {
Text(item.title)
.font(.headline)
Text(item.author)
}
Spacer()
Text("\(item.sales)")
.font(.caption)
}
}
}
.toolbar {
Menu {
Picker(selection: $selectedSortField, label: Text("Sorting")) {
ForEach(SortField.allCases, id: \.self) { field in
HStack {
Text(field.rawValue)
if selectedSortField == field {
Image(systemName: ascending ? "arrow.up" : "arrow.down")
}
}
}
}
.onChange(of: selectedSortField) { _ in sort() }
} label: {
Label("Menu", systemImage: "ellipsis.circle")
}
}
}
private func sort() {
switch selectedSortField {
case .title: items.sort { ascending ? $0.title < $1.title : $0.title > $1.title }
case .author: items.sort { ascending ? $0.author < $1.author : $0.author > $1.author }
case .sales: items.sort { ascending ? $0.sales < $1.sales : $0.sales > $1.sales }
}
}
}
}
英文:
I'm trying to sort a list using Picker inside a Menu as in the image
the picker is working and sorting is working, the missing part is sorting order
the goal behavior:
when user select a sort field and the sort order will be ASC, but when he select the same field again sort order should be DES.
how can I detect if the user selected the same field again in picker? or is there a better approach.
thank you
here is my example code
struct Book: Identifiable {
let id = UUID()
let title, author: String
let sales: Int
}
enum SortField: String, CaseIterable {
case title, author, sales
}
struct ContentView: View {
@State private var items: [Book] = [
.init(title: "Da Vinci Code,The", author: "Brown, Dan", sales: 5094805),
.init(title: "Harry Potter and the Deathly Hallows", author: "Rowling, J.K.", sales: 4475152),
.init(title: "Angels and Demons", author: "Brown, Dan", sales: 3193946),
.init(title: "One Day", author: "Nicholls, David", sales: 1616068),
.init(title: "Billy Connolly", author: "Stephenson, Pamela", sales: 1231957),
]
@State private var selectedSortField: SortField = .title
@State private var ascending: Bool = false
var body: some View {
NavigationView {
Form {
ForEach(items) { item in
HStack {
VStack(alignment: .leading) {
Text(item.title)
.font(.headline)
Text(item.author)
}
Spacer()
Text("\(item.sales)")
.font(.caption)
}
}
}
.toolbar {
Menu {
Picker(selection: $selectedSortField, label: Text("Sorting")) {
ForEach(SortField.allCases, id: \.self) { field in
HStack {
Text(field.rawValue)
if selectedSortField == field {
Image(systemName: ascending ? "arrow.up" : "arrow.down")
}
}
}
}
.onChange(of: selectedSortField) { _ in sort() }
} label: {
Label("Menu", systemImage: "ellipsis.circle")
}
}
}
}
private func sort() {
switch selectedSortField {
case .title: items.sort { ascending ? $0.title < $1.title : $0.title > $1.title }
case .author: items.sort { ascending ? $0.author < $1.author : $0.author > $1.author }
case .sales: items.sort { ascending ? $0.sales < $1.sales : $0.sales > $1.sales }
}
}
}
答案1
得分: 1
为了实现这个,可以在 `SortField` 的情况中包括 `ascending` 标志。例如:
```swift
struct Book: Identifiable {
let id = UUID()
let title, author: String
let sales: Int
}
enum SortField: Hashable {
case title(asc: Bool), author(asc: Bool), sales(asc: Bool)
var title: String {
switch self {
case .title: return "Title"
case .author: return "Author"
case .sales: return "Sales"
}
}
var isAscending: Bool {
switch self {
case .title(let asc), .author(let asc), .sales(let asc):
return asc
}
}
var inverse: Self {
switch self {
case .title(let asc):
return .title(asc: !asc)
case .author(let asc):
return .author(asc: !asc)
case .sales(let asc):
return .sales(asc: !asc)
}
}
}
struct ContentView: View {
@State private var items: [Book] = [
.init(title: "Da Vinci Code,The", author: "Brown, Dan", sales: 5094805),
.init(title: "Harry Potter and the Deathly Hallows", author: "Rowling, J.K.", sales: 4475152),
.init(title: "Angels and Demons", author: "Brown, Dan", sales: 3193946),
.init(title: "One Day", author: "Nicholls, David", sales: 1616068),
.init(title: "Billy Connolly", author: "Stephenson, Pamela", sales: 1231957),
]
@State private var selectedSortField: SortField = .title(asc: true)
var body: some View {
NavigationView {
Form {
ForEach(items) { item in
HStack {
VStack(alignment: .leading) {
Text(item.title)
.font(.headline)
Text(item.author)
}
Spacer()
Text("\(item.sales)")
.font(.caption)
}
}
}
.toolbar {
Menu {
Picker(selection: $selectedSortField, label: Text("Sorting")) {
ForEach(sortFields, id: \.self) { field in
HStack {
Text(field.title)
if selectedSortField == field || selectedSortField == field.inverse {
Image(systemName: field.isAscending ? "arrow.up" : "arrow.down")
}
}
}
}
.onChange(of: selectedSortField) { _ in sort() }
} label: {
Label("Menu", systemImage: "ellipsis.circle")
}
}
}
}
var sortFields: [SortField] {
var sortFields: [SortField] = []
if case .title(true) = selectedSortField {
sortFields.append(.title(asc: false))
} else {
sortFields.append(.title(asc: true))
}
if case .author(true) = selectedSortField {
sortFields.append(.author(asc: false))
} else {
sortFields.append(.author(asc: true))
}
if case .sales(true) = selectedSortField {
sortFields.append(.sales(asc: false))
} else {
sortFields.append(.sales(asc: true))
}
return sortFields
}
private func sort() {
switch selectedSortField {
case .title(let ascending): items.sort { ascending ? $0.title < $1.title : $0.title > $1.title }
case .author(let ascending): items.sort { ascending ? $0.author < $1.author : $0.author > $1.author }
case .sales(let ascending): items.sort { ascending ? $0.sales < $1.sales : $0.sales > $1.sales }
}
}
}
英文:
A way to achieve this would be to include the ascending
flag in the SortField
cases. e.g.
struct Book: Identifiable {
let id = UUID()
let title, author: String
let sales: Int
}
enum SortField: Hashable {
case title(asc: Bool), author(asc: Bool), sales(asc: Bool)
var title: String {
switch self {
case .title: return "Title"
case .author: return "Author"
case .sales: return "Sales"
}
}
var isAscending: Bool {
switch self {
case .title(let asc), .author(let asc), .sales(let asc):
return asc
}
}
var inverse: Self {
switch self {
case .title(let asc):
return .title(asc: !asc)
case .author(let asc):
return .author(asc: !asc)
case .sales(let asc):
return .sales(asc: !asc)
}
}
}
struct ContentView: View {
@State private var items: [Book] = [
.init(title: "Da Vinci Code,The", author: "Brown, Dan", sales: 5094805),
.init(title: "Harry Potter and the Deathly Hallows", author: "Rowling, J.K.", sales: 4475152),
.init(title: "Angels and Demons", author: "Brown, Dan", sales: 3193946),
.init(title: "One Day", author: "Nicholls, David", sales: 1616068),
.init(title: "Billy Connolly", author: "Stephenson, Pamela", sales: 1231957),
]
@State private var selectedSortField: SortField = .title(asc: true)
var body: some View {
NavigationView {
Form {
ForEach(items) { item in
HStack {
VStack(alignment: .leading) {
Text(item.title)
.font(.headline)
Text(item.author)
}
Spacer()
Text("\(item.sales)")
.font(.caption)
}
}
}
.toolbar {
Menu {
Picker(selection: $selectedSortField, label: Text("Sorting")) {
ForEach(sortFields, id: \.self) { field in
HStack {
Text(field.title)
if selectedSortField == field || selectedSortField == field.inverse {
Image(systemName: field.isAscending ? "arrow.up" : "arrow.down")
}
}
}
}
.onChange(of: selectedSortField) { _ in sort() }
} label: {
Label("Menu", systemImage: "ellipsis.circle")
}
}
}
}
var sortFields: [SortField] {
var sortFields: [SortField] = []
if case .title(true) = selectedSortField {
sortFields.append(.title(asc: false))
} else {
sortFields.append(.title(asc: true))
}
if case .author(true) = selectedSortField {
sortFields.append(.author(asc: false))
} else {
sortFields.append(.author(asc: true))
}
if case .sales(true) = selectedSortField {
sortFields.append(.sales(asc: false))
} else {
sortFields.append(.sales(asc: true))
}
return sortFields
}
private func sort() {
switch selectedSortField {
case .title(let ascending): items.sort { ascending ? $0.title < $1.title : $0.title > $1.title }
case .author(let ascending): items.sort { ascending ? $0.author < $1.author : $0.author > $1.author }
case .sales(let ascending): items.sort { ascending ? $0.sales < $1.sales : $0.sales > $1.sales }
}
}
}
答案2
得分: 1
这是另一种解决这个问题的方法:
struct Book: Identifiable {
let id = UUID()
let title, author: String
let sales: Int
}
enum SortField: String, CaseIterable {
case title, author, sales
}
struct ContentView: View {
@State private var items: [Book] = [
.init(title: "Da Vinci Code,The", author: "Brown, Dan", sales: 5094805),
.init(title: "Harry Potter and the Deathly Hallows", author: "Rowling, J.K.", sales: 4475152),
.init(title: "Angels and Demons", author: "Brown, Dan", sales: 3193946),
.init(title: "One Day", author: "Nicholls, David", sales: 1616068),
.init(title: "Billy Connolly", author: "Stephenson, Pamela", sales: 1231957),
]
@State private var selectedSortField: SortField = .title
@State private var ascending: Bool = false
var body: some View {
NavigationView {
Form {
ForEach(items) { item in
HStack {
VStack(alignment: .leading) {
Text(item.title)
.font(.headline)
Text(item.author)
}
Spacer()
Text("\(item.sales)")
.font(.caption)
}
}
}
.toolbar {
Menu {
ForEach(SortField.allCases, id: \.self) { field in
Toggle(isOn: .init(get: {
return selectedSortField == field
}, set: { value in
if selectedSortField == field {
ascending.toggle()
}
selectedSortField = field
sort()
})) {
Label(field.rawValue, systemImage: selectedSortField == field ? (ascending ? "arrow.up" : "arrow.down") : "")
}
}
} label: {
Label("Menu", systemImage: "ellipsis.circle")
}
}
}
}
private func sort() {
switch selectedSortField {
case .title: items.sort { ascending ? $0.title < $1.title : $0.title > $1.title }
case .author: items.sort { ascending ? $0.author < $1.author : $0.author > $1.author }
case .sales: items.sort { ascending ? $0.sales < $1.sales : $0.sales > $1.sales }
}
}
}
以上是您提供的代码的翻译部分。
英文:
this is another solution to this problem
struct Book: Identifiable {
let id = UUID()
let title, author: String
let sales: Int
}
enum SortField: String, CaseIterable {
case title, author, sales
}
struct ContentView: View {
@State private var items: [Book] = [
.init(title: "Da Vinci Code,The", author: "Brown, Dan", sales: 5094805),
.init(title: "Harry Potter and the Deathly Hallows", author: "Rowling, J.K.", sales: 4475152),
.init(title: "Angels and Demons", author: "Brown, Dan", sales: 3193946),
.init(title: "One Day", author: "Nicholls, David", sales: 1616068),
.init(title: "Billy Connolly", author: "Stephenson, Pamela", sales: 1231957),
]
@State private var selectedSortField: SortField = .title
@State private var ascending: Bool = false
var body: some View {
NavigationView {
Form {
ForEach(items) { item in
HStack {
VStack(alignment: .leading) {
Text(item.title)
.font(.headline)
Text(item.author)
}
Spacer()
Text("\(item.sales)")
.font(.caption)
}
}
}
.toolbar {
Menu {
ForEach(SortField.allCases, id: \.self) { field in
Toggle(isOn: .init(get: {
return selectedSortField == field
}, set: { value in
if selectedSortField == field {
ascending.toggle()
}
selectedSortField = field
sort()
})) {
Label(field.rawValue, systemImage: selectedSortField == field ? (ascending ? "arrow.up" : "arrow.down") : "")
}
}
} label: {
Label("Menu", systemImage: "ellipsis.circle")
}
}
}
}
private func sort() {
switch selectedSortField {
case .title: items.sort { ascending ? $0.title < $1.title : $0.title > $1.title }
case .author: items.sort { ascending ? $0.author < $1.author : $0.author > $1.author }
case .sales: items.sort { ascending ? $0.sales < $1.sales : $0.sales > $1.sales }
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论