SwiftUI-显示后可以更改ActionSheet按钮文本吗?

时间:2020-11-09 16:34:24

标签: swift swiftui observable

我想展示一个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. 操作表按钮随价格更新。

1 个答案:

答案 0 :(得分:1)

一种可能的解决方案是在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"
}

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