检测用户选择相同的值在选择器中以更改排序顺序。

huangapple go评论56阅读模式
英文:

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: &quot;Da Vinci Code,The&quot;, author: &quot;Brown, Dan&quot;, sales: 5094805),
.init(title: &quot;Harry Potter and the Deathly Hallows&quot;, author: &quot;Rowling, J.K.&quot;, sales: 4475152),
.init(title: &quot;Angels and Demons&quot;, author: &quot;Brown, Dan&quot;, sales: 3193946),
.init(title: &quot;One Day&quot;, author: &quot;Nicholls, David&quot;, sales: 1616068),
.init(title: &quot;Billy Connolly&quot;, author: &quot;Stephenson, Pamela&quot;, 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(&quot;\(item.sales)&quot;)
.font(.caption)
}
}
}
.toolbar {
Menu {
Picker(selection: $selectedSortField, label: Text(&quot;Sorting&quot;)) {
ForEach(SortField.allCases, id: \.self) { field in
HStack {
Text(field.rawValue)
if selectedSortField == field {
Image(systemName: ascending ? &quot;arrow.up&quot; : &quot;arrow.down&quot;)
}
}
}
}
.onChange(of: selectedSortField) { _ in sort() }
} label: {
Label(&quot;Menu&quot;, systemImage: &quot;ellipsis.circle&quot;)
}
}
}
}
private func sort() {
switch selectedSortField {
case .title: items.sort { ascending ? $0.title &lt; $1.title : $0.title &gt; $1.title }
case .author: items.sort { ascending ? $0.author &lt; $1.author : $0.author &gt; $1.author }
case .sales: items.sort { ascending ? $0.sales &lt; $1.sales : $0.sales &gt; $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 &quot;Title&quot;
case .author: return &quot;Author&quot;
case .sales: return &quot;Sales&quot;
}
}
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: &quot;Da Vinci Code,The&quot;, author: &quot;Brown, Dan&quot;, sales: 5094805),
.init(title: &quot;Harry Potter and the Deathly Hallows&quot;, author: &quot;Rowling, J.K.&quot;, sales: 4475152),
.init(title: &quot;Angels and Demons&quot;, author: &quot;Brown, Dan&quot;, sales: 3193946),
.init(title: &quot;One Day&quot;, author: &quot;Nicholls, David&quot;, sales: 1616068),
.init(title: &quot;Billy Connolly&quot;, author: &quot;Stephenson, Pamela&quot;, 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(&quot;\(item.sales)&quot;)
.font(.caption)
}
}
}
.toolbar {
Menu {
Picker(selection: $selectedSortField, label: Text(&quot;Sorting&quot;)) {
ForEach(sortFields, id: \.self) { field in
HStack {
Text(field.title)
if selectedSortField == field || selectedSortField == field.inverse {
Image(systemName: field.isAscending ? &quot;arrow.up&quot; : &quot;arrow.down&quot;)
}
}
}
}
.onChange(of: selectedSortField) { _ in sort() }
} label: {
Label(&quot;Menu&quot;, systemImage: &quot;ellipsis.circle&quot;)
}
}
}
}
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 &lt; $1.title : $0.title &gt; $1.title }
case .author(let ascending): items.sort { ascending ? $0.author &lt; $1.author : $0.author &gt; $1.author }
case .sales(let ascending): items.sort { ascending ? $0.sales &lt; $1.sales : $0.sales &gt; $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: &quot;Da Vinci Code,The&quot;, author: &quot;Brown, Dan&quot;, sales: 5094805),
.init(title: &quot;Harry Potter and the Deathly Hallows&quot;, author: &quot;Rowling, J.K.&quot;, sales: 4475152),
.init(title: &quot;Angels and Demons&quot;, author: &quot;Brown, Dan&quot;, sales: 3193946),
.init(title: &quot;One Day&quot;, author: &quot;Nicholls, David&quot;, sales: 1616068),
.init(title: &quot;Billy Connolly&quot;, author: &quot;Stephenson, Pamela&quot;, 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(&quot;\(item.sales)&quot;)
.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 ? &quot;arrow.up&quot; : &quot;arrow.down&quot;) : &quot;&quot;)
}
}
} label: {
Label(&quot;Menu&quot;, systemImage: &quot;ellipsis.circle&quot;)
}
}
}
}
private func sort() {
switch selectedSortField {
case .title: items.sort { ascending ? $0.title &lt; $1.title : $0.title &gt; $1.title }
case .author: items.sort { ascending ? $0.author &lt; $1.author : $0.author &gt; $1.author }
case .sales: items.sort { ascending ? $0.sales &lt; $1.sales : $0.sales &gt; $1.sales }
}
}
}

huangapple
  • 本文由 发表于 2023年2月16日 18:35:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/75471008.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定