gpt4 book ai didi

SwiftUI 使用 INFO 按钮列出行

转载 作者:行者123 更新时间:2023-12-05 04:52:28 25 4
gpt4 key购买 nike

UIKit 过去支持启用蓝色信息/披露按钮的 TableView Cell。以下是在 SwiftUI 中生成的,但是让底层功能正常工作对 SwiftUI 初学者来说是一个挑战。

Visually everything is fine as demonstrated below:

由以下代码生成:

struct Session: Identifiable {
let date: Date
let dir: String
let instrument: String
let description: String
var id: Date { date }
}

final class SessionsData: ObservableObject {
@Published var sessions: [Session]

init() {
sessions = [Session(date: SessionsData.dateFromString(stringDate: "2016-04-14T10:44:00+0000"),dir:"Rhubarb", instrument:"LCproT", description: "brief Description"),
Session(date: SessionsData.dateFromString(stringDate: "2017-04-14T10:44:00+0001"),dir:"Custard", instrument:"LCproU", description: "briefer Description"),
Session(date: SessionsData.dateFromString(stringDate: "2018-04-14T10:44:00+0002"),dir:"Jelly", instrument:"LCproV", description: " Description")
]
}
static func dateFromString(stringDate: String) -> Date {
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX") // set locale to reliable US_POSIX
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
return dateFormatter.date(from:stringDate)!
}
}

struct SessionList: View {
@EnvironmentObject private var sessionData: SessionsData

var body: some View {
NavigationView {
List {
ForEach(sessionData.sessions) { session in
SessionRow(session: session )
}
}
.navigationTitle("Session data")
}
// without this style modification we get all sorts of UIKit warnings
.navigationViewStyle(StackNavigationViewStyle())
}
}

struct SessionRow: View {
var session: Session

@State private var presentDescription = false

var body: some View {
HStack(alignment: .center){
VStack(alignment: .leading) {
Text(session.dir)
.font(.headline)
.truncationMode(.tail)
.frame(minWidth: 20)

Text(session.instrument)
.font(.caption)
.opacity(0.625)
.truncationMode(.middle)
}
Spacer()
// SessionGraph is a place holder for the Graph data.
NavigationLink(destination: SessionGraph()) {
// if this isn't an EmptyView then we get a disclosure indicator
EmptyView()
}
// Note: without setting the NavigationLink hidden
// width to 0 the List width is split 50/50 between the
// SessionRow and the NavigationLink. Making the NavigationLink
// width 0 means that SessionRow gets all the space. Howeveer
// NavigationLink still works
.hidden().frame(width: 0)

Button(action: { presentDescription = true
print("\(session.dir):\(presentDescription)")
}) {
Image(systemName: "info.circle")
}
.buttonStyle(BorderlessButtonStyle())

NavigationLink(destination: SessionDescription(),
isActive: $presentDescription) {
EmptyView()
}
.hidden().frame(width: 0)
}
.padding(.vertical, 4)
}
}

struct SessionGraph: View {
var body: some View {
Text("SessionGraph")
}
}

struct SessionDescription: View {
var body: some View {
Text("SessionDescription")
}
}

问题出在 SessionGraph 的 NavigationLinks 的行为中。选择作为行主体的 SessionGraph,传播到 SessionDescription!因此 Views 开始在不受控制的庄园中飞来飞去。

我已经看到了针对这个问题的几个明确的解决方案,但是没有一个适用于 XCode 12.3 和 iOS 14.3

有什么想法吗?

最佳答案

当您将 NavigationLink 放在列表行的背景中时,NavigationLink 仍然可以在点击时激活。即使使用 .buttonStyle(BorderlessButtonStyle())(对我来说这看起来像个错误)。

一个可能的解决方案是将所有 NavigationLinks 移到 List 之外,然后从 List 行内激活它们。为此,我们需要保存激活状态的@State 变量。然后,我们需要将它们作为 @Binding 传递给 subview ,并在点击按钮时激活它们。

这是一个可能的例子:

struct SessionList: View {
@EnvironmentObject private var sessionData: SessionsData

// create state variables for activating NavigationLinks
@State private var presentGraph: Session?
@State private var presentDescription: Session?

var body: some View {
NavigationView {
List {
ForEach(sessionData.sessions) { session in
SessionRow(
session: session,
presentGraph: $presentGraph,
presentDescription: $presentDescription
)
}
}
.navigationTitle("Session data")
// put NavigationLinks outside the List
.background(
VStack {
presentGraphLink
presentDescriptionLink
}
)
}
.navigationViewStyle(StackNavigationViewStyle())
}

@ViewBuilder
var presentGraphLink: some View {
// custom binding to activate a NavigationLink - basically when `presentGraph` is set
let binding = Binding<Bool>(
get: { presentGraph != nil },
set: { if !$0 { presentGraph = nil } }
)
// activate the `NavigationLink` when the `binding` is `true`
NavigationLink("", destination: SessionGraph(), isActive: binding)
}

@ViewBuilder
var presentDescriptionLink: some View {
let binding = Binding<Bool>(
get: { presentDescription != nil },
set: { if !$0 { presentDescription = nil } }
)
NavigationLink("", destination: SessionDescription(), isActive: binding)
}
}
struct SessionRow: View {
var session: Session

// pass variables as `@Binding`...
@Binding var presentGraph: Session?
@Binding var presentDescription: Session?

var body: some View {
HStack {
Button {
presentGraph = session // ...and activate them manually
} label: {
VStack(alignment: .leading) {
Text(session.dir)
.font(.headline)
.truncationMode(.tail)
.frame(minWidth: 20)

Text(session.instrument)
.font(.caption)
.opacity(0.625)
.truncationMode(.middle)
}
}
.buttonStyle(PlainButtonStyle())
Spacer()
Button {
presentDescription = session
print("\(session.dir):\(presentDescription)")
} label: {
Image(systemName: "info.circle")
}
.buttonStyle(PlainButtonStyle())
}
.padding(.vertical, 4)
}
}

关于SwiftUI 使用 INFO 按钮列出行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66493944/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com