ios - SwiftUI:可以管理各种形状协议(protocol)的单个结构吗?

标签 ios swift swiftui

目标: 使用单个结构来管理自定义View的外观和行为。

状态: 我有一个简单的 View 模型,它维护表示 View 的数据数组。在运行时,我按如下方式绘制这些 View :

struct MyView: View {
    @ObservedObject var viewModel = MyViewModel()
    
    var body: some View {
        Vstack() {
            ForEach(viewModel.data, id: \.id) { data in 
                switch data.shape {
                    case .circle:
                        MyViewCircle(isHighlighted: data.willHighlight)
                    case .ellipses:
                        MyViewEllipses(isHighlighted: data.willHighlight)
                }
            }
        }
    }
}

struct MyViewCircle: View {
    var isHighlighted: Bool

    var body: some View {
        Circle()
            /// a bunch of modifiers
    }
}

struct MyViewEllipses: View {
    var isHighlighted: Bool

    var body: some View {
        Ellipses()
            ///A bunch of modifiers that mirror exactly MyViewCircle
    }
}

这工作正常,我可以更新我的 viewModel,这将相应地更新我的 View 。

My Shapes drawing, I can even tap on the view and update my view model and highlight the corresponding shapes (code not shown for brevity

但是,就我而言,MyViewCircleMyViewEllipses 将具有完全相同的外观和行为,唯一不同的是它的形状,我还计划添加一个许多其他形状,甚至自定义绘制的形状。

我想做什么 我希望能够在 ForEach 循环中传递 enumprotocol 或其他内容,以绘制我想要的形状并进行简化,而不需要很长的 switch 语句。像这样的事情:

struct MyView: View {
    @ObservedObject var viewModel = MyViewModel()

    var body: some View {
        VStack() {
            ForEach(viewModel.data, id: \.id) { data in 
                MyViewProtocol(shape: data.shape, isHighlighted: data.IsHighlighted)
            }
        }
    }
}

还有父类、父类(super class)、协议(protocol),无论 MyViewProtocol 的正确名称是什么,都类似于:

struct MyViewProtocol: View {
    var shape: ShapeEnum
    var isHighlighted: Bool

    var body: some View {
        switch shape:
        case .circle:
            Circle()
        case .ellipses:
            Ellipses()
        case .triangle:
            MyTrinagle()
        // etc.....
    }
}

我一直在搜索任何/所有 WWDC 演讲、YouTube 教程、媒体文章,我能找到的最接近的内容就在这里:Creating BaseView class in SwiftUI这对于创建一组 View 修饰符很有用,但是如果我希望能够使用由一个父结构 View 管理的大量形状,我仍然陷入困境。

我也可能遇到问题,因为对于像 SwiftUI 这样的声明性语言来说,这可能是一个危险的错误设计模式!

如果有任何提示或想法,我将非常感激!

最佳答案

我认为您无法避免使用 switch 语句,因为您需要 ShapeEnum 案例和实际 View 之间的映射,但您可以将其集中在一个地方:

enum ShapeEnum {
   case circle, ellipse, square // etc...
}
extension ShapeEnum: View {
   var body: AnyView {
      switch self {
      case circle:   return AnyView(Circle())
      case ellipse:  return AnyView(Ellipse())
      // ...
      default:       return AnyView(EmptyView())
      }
   }
}

用法可能是:

@State var shapes: [ShapeEnum] = [.circle, .circle, .ellipse]

var body: some View {
   ForEach(shapes, id: \.self) { shape in
      shape
         .padding()
         .background(Color.red)
   }
}

关于ios - SwiftUI:可以管理各种形状协议(protocol)的单个结构吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63093327/

相关文章:

ios - 绘制不同线宽的曲线

ios - Mac 催化剂 : multi-window without supporting multi-window in iPad app?

swift - switch 语句中的常量绑定(bind)实际上有什么作用?

ios - SwiftUI - 如何模糊 View 的默认背景颜色?

ios - 如何将测试数据添加到PreviewProvider

ios - 当我在没有 sudo 的情况下安装 cocoapods 时,我会失去哪些权限?

iOS Simulator 8.1 和 8.2 的 UITabBar 半透明错误?

ios - 发现信标的最佳测距方式?

objective-c - 为设备编译,未找到 swift 头文件

ios - iOS 14.0 Beta 中反复调用 DispatchQueue.main.asyncAfter