首页 > 解决方案 > SwiftUI - 是否可以在显示后更改 ActionSheet 按钮文本?

问题描述

我想展示一个ActionSheet包含用户可以购买的 InApp 购买对象。

但我希望该表包含此类对象的价格,例如:

Object 1 ($1.99)
Object 2 ($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
  }
}

然后,当我创建操作表按钮时,我会这样做:

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 {$0.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({ ($0.productID == result.productIdentifier) }).first {
          package.namePriceString = result.localizedTitle + "(" + "\(result.localizedPrice!)" + ")"
        }
      }
    }
  }

我有一个错误指向Text按钮创建行说

初始化程序 'init(_:)' 要求 'Binding' 符合 'StringProtocol'

简而言之,我需要这个:

  1. 我显示操作表。它的按钮不包含价格。
  2. 我检索价格
  3. 操作表按钮随价格更新。

标签: swiftswiftuiobservable

解决方案


一种可能的解决方案是在处理程序中返回价格,completion然后才显示操作表:

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 = $0
                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 { ($0, "\(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"
}

这可以通过加载动画等进一步调整......


推荐阅读