SwiftUI - 是否可以在显示后更改 ActionSheet 按钮文本?
SwiftUI - Is it possible to change an ActionSheet button text after it is displayed?
我想展示一个 ActionSheet
包含用户可以购买的 InApp 购买对象。
但我希望 sheet 包含此类对象的价格,例如:
Object 1 (.99)
Object 2 (.99)
...
但价格是异步的,因为它必须从商店中检索。
所以,我考虑过这样做:
struct Package {
enum Packtype:String {
typealias RawValue = String
case obj1 = "com.example.object1"
case obj2 = "com.example.object2"
}
var productID:String = ""
@State var namePriceString:String = ""
init(productID:String) {
self.productID = productID
}
}
然后,当我创建操作 sheet 按钮时,我会这样做:
var obj1 = Package(productID: Package.Packtype.obj1.rawValue)
var obj2 = Package(productID: Package.Packtype.obj2.rawValue)
self.getPrices(packages:[obj1, obj2])
let obj1Button = ActionSheet.Button.default(Text(obj1.$namePriceString)) {
// do something with obj1
}
let obj2Button = ActionSheet.Button.default(Text(obj2.$namePriceString)) {
// do something with obj1
}
// build the actionsheet
稍后在代码中:
func getPrices(packages:[Package]) {
let productIDS = Set(packages.map {[=13=].productID})
SwiftyStoreKit.retrieveProductsInfo(productIDS) { (answer) in
if answer.invalidProductIDs.first != nil { return }
let results = answer.retrievedProducts
if results.count == 0 { return }
for result in answer {
if let package = packages.filter({ ([=13=].productID == result.productIdentifier) }).first {
package.namePriceString = result.localizedTitle + "(" + "\(result.localizedPrice!)" + ")"
}
}
}
}
我在按钮创建行上指向 Text
时出错,说
Initializer 'init(_:)' requires that 'Binding' conform to
'StringProtocol'
简而言之,我需要这个:
- 我显示动作sheet。它的按钮不包含价格。
- 我检索价格
- 操作sheet 按钮随价格更新。
一个可能的解决方案是在 completion
处理程序中 return 价格,然后才显示操作 sheet:
struct ContentView: View {
@State var showActionSheet = false
@State var localizedPrices = [Package: String]()
var body: some View {
Button("Get prices") {
getPrices(packages: Package.allCases, completion: {
localizedPrices = [=10=]
showActionSheet = true
})
}
.actionSheet(isPresented: $showActionSheet) {
let buttons = localizedPrices.map { package, localizedPrice in
ActionSheet.Button.default(Text(localizedPrice), action: { buy(package: package) })
}
return ActionSheet(title: Text("Title"), message: Text("Message"), buttons: buttons + [.cancel()])
}
}
}
func getPrices(packages: [Package], completion: @escaping ([Package: String]) -> Void) {
// simulates an asynchronous task, should be replaced with the actual implementation
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
let localizedPrices = Dictionary(uniqueKeysWithValues: packages.map { ([=11=], "\(Int.random(in: 1 ..< 100))") })
completion(localizedPrices)
}
}
func buy(package: Package) {
print("Buying \(package.rawValue)")
}
enum Package: String, CaseIterable {
case obj1 = "com.example.object1"
case obj2 = "com.example.object2"
}
这可以通过加载动画等进一步调整...
我想展示一个 ActionSheet
包含用户可以购买的 InApp 购买对象。
但我希望 sheet 包含此类对象的价格,例如:
Object 1 (.99)
Object 2 (.99)
...
但价格是异步的,因为它必须从商店中检索。
所以,我考虑过这样做:
struct Package {
enum Packtype:String {
typealias RawValue = String
case obj1 = "com.example.object1"
case obj2 = "com.example.object2"
}
var productID:String = ""
@State var namePriceString:String = ""
init(productID:String) {
self.productID = productID
}
}
然后,当我创建操作 sheet 按钮时,我会这样做:
var obj1 = Package(productID: Package.Packtype.obj1.rawValue)
var obj2 = Package(productID: Package.Packtype.obj2.rawValue)
self.getPrices(packages:[obj1, obj2])
let obj1Button = ActionSheet.Button.default(Text(obj1.$namePriceString)) {
// do something with obj1
}
let obj2Button = ActionSheet.Button.default(Text(obj2.$namePriceString)) {
// do something with obj1
}
// build the actionsheet
稍后在代码中:
func getPrices(packages:[Package]) {
let productIDS = Set(packages.map {[=13=].productID})
SwiftyStoreKit.retrieveProductsInfo(productIDS) { (answer) in
if answer.invalidProductIDs.first != nil { return }
let results = answer.retrievedProducts
if results.count == 0 { return }
for result in answer {
if let package = packages.filter({ ([=13=].productID == result.productIdentifier) }).first {
package.namePriceString = result.localizedTitle + "(" + "\(result.localizedPrice!)" + ")"
}
}
}
}
我在按钮创建行上指向 Text
时出错,说
Initializer 'init(_:)' requires that 'Binding' conform to 'StringProtocol'
简而言之,我需要这个:
- 我显示动作sheet。它的按钮不包含价格。
- 我检索价格
- 操作sheet 按钮随价格更新。
一个可能的解决方案是在 completion
处理程序中 return 价格,然后才显示操作 sheet:
struct ContentView: View {
@State var showActionSheet = false
@State var localizedPrices = [Package: String]()
var body: some View {
Button("Get prices") {
getPrices(packages: Package.allCases, completion: {
localizedPrices = [=10=]
showActionSheet = true
})
}
.actionSheet(isPresented: $showActionSheet) {
let buttons = localizedPrices.map { package, localizedPrice in
ActionSheet.Button.default(Text(localizedPrice), action: { buy(package: package) })
}
return ActionSheet(title: Text("Title"), message: Text("Message"), buttons: buttons + [.cancel()])
}
}
}
func getPrices(packages: [Package], completion: @escaping ([Package: String]) -> Void) {
// simulates an asynchronous task, should be replaced with the actual implementation
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
let localizedPrices = Dictionary(uniqueKeysWithValues: packages.map { ([=11=], "\(Int.random(in: 1 ..< 100))") })
completion(localizedPrices)
}
}
func buy(package: Package) {
print("Buying \(package.rawValue)")
}
enum Package: String, CaseIterable {
case obj1 = "com.example.object1"
case obj2 = "com.example.object2"
}
这可以通过加载动画等进一步调整...