使用 SwiftUI 和 Combine 根据授权状态有条件地显示视图?
Using SwiftUI and Combine to conditionally display a view based on authorization status?
我正在构建一个 UI,我想在视图中根据 HealthKit 是否已获得授权来显示“启用”按钮或绿色复选标记。我还希望视图是反应式的,以便一旦您授权 HealthKit,视图就会从按钮动态更改为复选标记,但我无法弄清楚如何正确地进行这两种方式的通信以及 属性要使用的包装器:
struct SetUpWatchView: View {
let healthKitAuthManager = HealthKitAuthManager()
@ViewBuilder
var body: some View {
VStack(alignment: .leading) {
HStack {
Image(systemName: "heart.circle.fill")
.foregroundColor(.red)
.font(.system(size: 56.0, weight: .bold))
.frame(width: 65, height: 65)
VStack(alignment: .leading) {
Text("Health Integration")
.fontWeight(.bold)
Text("Enable in Order to Track your Speed, Distance, and Heart Rate.")
}
Spacer()
if healthKitAuthManager.healthKitIsAuthorized {
Image(systemName: "checkmark.circle.fill")
.foregroundColor(.green)
.font(.system(size: 30.0, weight: .bold))
.padding(.horizontal)
} else {
Button(action: {
healthKitAuthManager.authorizeHealthKit()
}) {
Text("ENABLE")
.fontWeight(.bold)
.foregroundColor(Color.black)
}
.padding(.horizontal)
}
}
.padding([.leading, .bottom])
}.onAppear {
healthKitAuthManager.checkWhetherHealthKitDatAvailableAndIfAuthorized()
}
}
}
}
class HealthKitAuthManager: ObservableObject {
let healthStore = HKHealthStore()
@Published var healthKitIsAuthorized = false
public func checkWhetherHealthKitDatAvailableAndIfAuthorized() {
if HKHealthStore.isHealthDataAvailable() {
let authorizationStatus = healthStore.authorizationStatus(for: HKSampleType.workoutType())
switch authorizationStatus {
case .sharingAuthorized:
healthKitIsAuthorized = true
case .sharingDenied: ()
healthKitIsAuthorized = false
default:()
healthKitIsAuthorized = false
}
}
else {
healthKitIsAuthorized = false
}
}
public func authorizeHealthKit() {
let healthKitTypesToWrite: Set<HKSampleType> = [
HKObjectType.workoutType(),
HKSeriesType.workoutRoute(),
HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!,
HKObjectType.quantityType(forIdentifier: .heartRate)!,
HKObjectType.quantityType(forIdentifier: .restingHeartRate)!,
HKObjectType.quantityType(forIdentifier: .bodyMass)!,
HKObjectType.quantityType(forIdentifier: .vo2Max)!,
HKObjectType.quantityType(forIdentifier: .stepCount)!,
HKObjectType.quantityType(forIdentifier: .distanceWalkingRunning)!]
let healthKitTypesToRead: Set<HKObjectType> = [
HKObjectType.workoutType(),
HKSeriesType.workoutRoute(),
HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!,
HKObjectType.quantityType(forIdentifier: .heartRate)!,
HKObjectType.quantityType(forIdentifier: .restingHeartRate)!,
HKObjectType.characteristicType(forIdentifier: .dateOfBirth)!,
HKObjectType.quantityType(forIdentifier: .bodyMass)!,
HKObjectType.quantityType(forIdentifier: .vo2Max)!,
HKObjectType.quantityType(forIdentifier: .stepCount)!,
HKObjectType.quantityType(forIdentifier: .distanceWalkingRunning)!]
let authorizationStatus = HKHealthStore().authorizationStatus(for: HKSampleType.workoutType())
switch authorizationStatus {
case .sharingAuthorized:
print("Sharing Authorized")
healthKitIsAuthorized = true
case .sharingDenied: print("sharing denied")
//Success does NOT necessarily mean we are authorized, only that the request was successfully delivered. Also if a user chooses not to authorize, if you call .requestAuthorization again you won't get the action sheet
HKHealthStore().requestAuthorization(toShare: healthKitTypesToWrite, read: healthKitTypesToRead) { (success, error) in
if !success {
print("failed HealthKit Authorization from iPhone SetUpWatchVC \(String(describing: error?.localizedDescription))")
}
print("Successful HealthKit Authorization from iPhone")
}
default: print("not determined")
HKHealthStore().requestAuthorization(toShare: healthKitTypesToWrite, read: healthKitTypesToRead) { (success, error) in
if !success {
print("failed HealthKit Authorization from iPhone SetUpWatchVC \(String(describing: error?.localizedDescription))")
}
print("Successful HealthKit Authorization from iPhone SetUpWatchVC")
}
}
}
}
尝试添加 @ObservedObject var healthKitAuthManager = HealthKitAuthManager()
而不是 let healthKitAuthManager = HealthKitAuthManager()
。这样 @Published
变量将触发新的视图渲染。
我正在构建一个 UI,我想在视图中根据 HealthKit 是否已获得授权来显示“启用”按钮或绿色复选标记。我还希望视图是反应式的,以便一旦您授权 HealthKit,视图就会从按钮动态更改为复选标记,但我无法弄清楚如何正确地进行这两种方式的通信以及 属性要使用的包装器:
struct SetUpWatchView: View {
let healthKitAuthManager = HealthKitAuthManager()
@ViewBuilder
var body: some View {
VStack(alignment: .leading) {
HStack {
Image(systemName: "heart.circle.fill")
.foregroundColor(.red)
.font(.system(size: 56.0, weight: .bold))
.frame(width: 65, height: 65)
VStack(alignment: .leading) {
Text("Health Integration")
.fontWeight(.bold)
Text("Enable in Order to Track your Speed, Distance, and Heart Rate.")
}
Spacer()
if healthKitAuthManager.healthKitIsAuthorized {
Image(systemName: "checkmark.circle.fill")
.foregroundColor(.green)
.font(.system(size: 30.0, weight: .bold))
.padding(.horizontal)
} else {
Button(action: {
healthKitAuthManager.authorizeHealthKit()
}) {
Text("ENABLE")
.fontWeight(.bold)
.foregroundColor(Color.black)
}
.padding(.horizontal)
}
}
.padding([.leading, .bottom])
}.onAppear {
healthKitAuthManager.checkWhetherHealthKitDatAvailableAndIfAuthorized()
}
}
}
}
class HealthKitAuthManager: ObservableObject {
let healthStore = HKHealthStore()
@Published var healthKitIsAuthorized = false
public func checkWhetherHealthKitDatAvailableAndIfAuthorized() {
if HKHealthStore.isHealthDataAvailable() {
let authorizationStatus = healthStore.authorizationStatus(for: HKSampleType.workoutType())
switch authorizationStatus {
case .sharingAuthorized:
healthKitIsAuthorized = true
case .sharingDenied: ()
healthKitIsAuthorized = false
default:()
healthKitIsAuthorized = false
}
}
else {
healthKitIsAuthorized = false
}
}
public func authorizeHealthKit() {
let healthKitTypesToWrite: Set<HKSampleType> = [
HKObjectType.workoutType(),
HKSeriesType.workoutRoute(),
HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!,
HKObjectType.quantityType(forIdentifier: .heartRate)!,
HKObjectType.quantityType(forIdentifier: .restingHeartRate)!,
HKObjectType.quantityType(forIdentifier: .bodyMass)!,
HKObjectType.quantityType(forIdentifier: .vo2Max)!,
HKObjectType.quantityType(forIdentifier: .stepCount)!,
HKObjectType.quantityType(forIdentifier: .distanceWalkingRunning)!]
let healthKitTypesToRead: Set<HKObjectType> = [
HKObjectType.workoutType(),
HKSeriesType.workoutRoute(),
HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!,
HKObjectType.quantityType(forIdentifier: .heartRate)!,
HKObjectType.quantityType(forIdentifier: .restingHeartRate)!,
HKObjectType.characteristicType(forIdentifier: .dateOfBirth)!,
HKObjectType.quantityType(forIdentifier: .bodyMass)!,
HKObjectType.quantityType(forIdentifier: .vo2Max)!,
HKObjectType.quantityType(forIdentifier: .stepCount)!,
HKObjectType.quantityType(forIdentifier: .distanceWalkingRunning)!]
let authorizationStatus = HKHealthStore().authorizationStatus(for: HKSampleType.workoutType())
switch authorizationStatus {
case .sharingAuthorized:
print("Sharing Authorized")
healthKitIsAuthorized = true
case .sharingDenied: print("sharing denied")
//Success does NOT necessarily mean we are authorized, only that the request was successfully delivered. Also if a user chooses not to authorize, if you call .requestAuthorization again you won't get the action sheet
HKHealthStore().requestAuthorization(toShare: healthKitTypesToWrite, read: healthKitTypesToRead) { (success, error) in
if !success {
print("failed HealthKit Authorization from iPhone SetUpWatchVC \(String(describing: error?.localizedDescription))")
}
print("Successful HealthKit Authorization from iPhone")
}
default: print("not determined")
HKHealthStore().requestAuthorization(toShare: healthKitTypesToWrite, read: healthKitTypesToRead) { (success, error) in
if !success {
print("failed HealthKit Authorization from iPhone SetUpWatchVC \(String(describing: error?.localizedDescription))")
}
print("Successful HealthKit Authorization from iPhone SetUpWatchVC")
}
}
}
}
尝试添加 @ObservedObject var healthKitAuthManager = HealthKitAuthManager()
而不是 let healthKitAuthManager = HealthKitAuthManager()
。这样 @Published
变量将触发新的视图渲染。