我想根据分配给项目的内容显示不同类型的视图。每个相关视图都遵循此协议:
public protocol ItemDisplayer {
init(item: ItemObject)
}
该结构体存储Item对象及其关联的外观视图对象。
public struct ItemWithDisplay {
private let item: ItemObject
private let itemDisplayer : ItemDisplayer
public init(item : ItemObject, displayer : ItemDisplayer) {
self.item = item
self.itemDisplayer = displayer
}
public func getDisplayer() -> TimeCounterDisplayer {
return itemDisplayer
}
public func getItem() -> ItemObject {
return item
}
}
有一些类型的视图显示数据的某种方式,取决于什么被分配给ItemObject。
import SwiftUI
struct OtherItemView: View, ItemDisplayer {
private var item: ItemObject
init(item: ItemObject) { self.item = item }
var body: some View { ... }
}
struct DefaultItemView: View, ItemDisplayer {
private var item: ItemObject
init(item: ItemObject) { self.item = item }
var body: some View { ... }
}
// other ItemViews ...
我想在modelView类中与视图分开项目,像这样:
switch displayerType {
case .other:
self.itemWithDisplayArray.append(ItemWithDisplay(item: item, displayer: OtherItemView(itemToDisplay: item)))
case .another:
self.itemWithDisplayArray.append(ItemWithDisplay(item: item, displayer: AnotherItemView(itemToDisplay: item)))
default:
self.itemWithDisplayArray.append(ItemWithDisplay(item: item, displayer: DefaultItemView(itemToDisplay: item)))
}
这是下面问题所需的信息。我的问题涉及以下部分:
ScrollView {
ForEach(viewModel.itemWithDisplayArray, id: .itemId) { item in
VStack {
//item.getDisplayer() as! DefaultItemView // It works
item.getDisplayer() as! AnyView // Cast from 'ItemDisplayer' to unrelated type 'AnyView' always fails // how could I fix this?
}
}
}
如果itemdisplay直接强制转换为DefaultTimerView或OtherItemView,则强制转换工作。但是我想转换为任意视图类型
编辑:我在UIKit中做了这样的:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let itemViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "ItemViewCell", for: indexPath) as! ItemViewCell
let itemWithDisplay = itemWithDisplayArray[indexPath.row]
itemViewCell.containerView = UIView(frame: itemViewCell.contentView.frame)
itemViewCell.containerView!.addSubview(itemWithDisplay.getDisplayer() as! UIView) // <--the POINT is here: "as! UIView"
itemViewCell.contentView.addSubview(itemViewCell.containerView!)
itemWithDisplay.display()
return itemViewCell
}
或者在Cocoa中:
class ItemGridNSView : NSView {
private let itemWithDisplay : ItemWithDisplay
init(frame frameRect: NSRect, itemWithDisplay: ItemWithDisplay) {
self.itemWithDisplay = itemWithDisplay
super.init(frame:frameRect);
self.addSubview(itemWithDisplay.getDisplayer() as! NSView) // <-- Here too
itemWithDisplay.display()
}
...
我正在寻找相同的解决方案在SwiftUI。
我想保持域层与视图逻辑的独立性,即任何视图特定的信息(导入SwiftUI)。我想在视图层中避免这种排序逻辑。
你能帮我一下吗?提前感谢您提供的任何帮助!
使ItemDisplayer
符合View
。这样你就可以像使用普通的View
一样使用它。
public protocol ItemDisplayer: View {
init(item: ItemObject)
}
然后更改ItemWithDisplay
,以便您可以使用ItemDisplayer
(因为它现在具有相关的类型要求):
public struct ItemWithDisplay<Displayer: ItemDisplayer> {
private let item: ItemObject
private let itemDisplayer : Displayer
public init(item : ItemObject, displayer : Displayer) {
self.item = item
self.itemDisplayer = displayer
}
public func getDisplayer() -> Displayer {
return itemDisplayer
}
public func getItem() -> ItemObject {
return item
}
}
最后,您现在可以使用getDisplayer()
来获取视图,甚至不需要将其转换为AnyView
:
VStack {
item.getDisplayer()
}
然而,要使某些内容成为AnyView
,您将执行以下操作:
VStack {
AnyView(item.getDisplayer())
}