使用@EnvironmentObject和Picker的SwiftUI会导致ScrollView contentOffset绑定警告

时间:2019-12-05 22:23:28

标签: swiftui

我有一个watchOS应用,该应用有两个屏幕。当我导航到第二个屏幕时,在控制台中收到以下警告:

  

ScrollView contentOffset绑定已被读取;每当ScrollView的contentOffset更改时,其内容都会被更新,这将导致视图性能严重低下。避免在绑定的创建者和ScrollView之间没有父视图的视图中读取contentOffset绑定。

这似乎与在第二个屏幕中使用@EnvironmentObject进行选择器选择有关。如果删除@EnvironmentObject并将其替换为@State作为选择器选择,则不会发生该警告。 (但是,更新不会显示在第一个屏幕上)。

为什么会这样?我该怎么做才能停止此警告?

这是我的代码:

第一个屏幕:

import SwiftUI

struct ContentView: View {
  @EnvironmentObject var itemManager: ItemManager

  var body: some View {
    List {
      ForEach(itemManager.items.indices) { index in
        NavigationLink(destination: ItemView(index: index)) {
          VStack(alignment: HorizontalAlignment.leading) {
            HStack {
              Text(self.itemManager.items[index].name)
              Spacer()
              Text("x")
              Text(String(self.itemManager.items[index].quantity))
            }
            Text(self.itemManager.items[index].type.rawValue).font(.footnote)
          }
        }
      }
    }
  }
}

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView().environmentObject(ItemManager())
  }
}

第二个屏幕:

import SwiftUI

struct ItemView: View {

  @EnvironmentObject var itemManager: ItemManager
  var index: Int

  var body: some View {

    VStack {
      Text("Update")
      Form {
        Section {
          Picker(selection: $itemManager.items[index].type, label: Text("Food Type")) {
            ForEach(FoodType.allCases.sorted()) { type in
              Text(type.rawValue).tag(type)
            }
          }
        }
      }
    }.navigationBarTitle(Text("Item"))
  }
}

struct ItemView_Previews: PreviewProvider {
  static var previews: some View {

    return ItemView(index: 0).environmentObject(ItemManager())
  }
}

型号:

import Foundation

enum FoodType: String, CaseIterable, Identifiable, Comparable{
  case fruit
  case vegetable
  case poultry
  case bakery
  var id: FoodType{self}

  static func < (lhs: FoodType, rhs: FoodType) -> Bool {
    lhs.rawValue < rhs.rawValue
  }
}

struct Item {
  var type: FoodType
  var quantity: Int
  var name: String
}

class ItemManager: ObservableObject {

  @Published var items: [Item] =
    [
      Item(type: FoodType.fruit, quantity: 1, name: "apple"),
      Item(type: FoodType.bakery, quantity: 1, name: "french bread"),
      Item(type: FoodType.vegetable, quantity: 6, name: "carrots")
  ]
}

HostingController:

import WatchKit
import Foundation
import SwiftUI

class HostingController: WKHostingController<AnyView> {
    override var body: AnyView {
      return AnyView(ContentView()
      .environmentObject(ItemManager()))
    }
}

1 个答案:

答案 0 :(得分:0)

我最终在第二个屏幕(ItemView)中使用@State,并在视图消失时设置@EnvironmentObject itemManager。

第一个屏幕:

.btn-custom {
border: none;
    outline: none;
}

注意: I got the var itemIndex: Int strategry from the Landmark apple tutorial

第二屏幕:

import SwiftUI

struct ContentView: View {
  @EnvironmentObject var itemManager: ItemManager

  var body: some View {
    List {
      ForEach(itemManager.items, id: \.self) { item in
        NavigationLink(destination: ItemView(selection: item.type, food: item)) {
          VStack(alignment: HorizontalAlignment.leading) {
            HStack {
              Text(item.name)
              Spacer()
              Text("x")
              Text(String(item.quantity))
            }
            Text(item.type.rawValue).font(.footnote)
          }
        }
      }
    }
  }
}

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView().environmentObject(ItemManager())
  }
}