自定义“列表"看法 [英] Custom "list" view

查看:27
本文介绍了自定义“列表"看法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 SwiftUI 中,List 会自动格式化你传递给它的子视图,就像这样:

In SwiftUI, a List will automatically format the sub views you pass it, so something like this:

List {
  Text("A")
  Text("B")
}

将导致两个文本视图都被正确放置,它们之间有分隔符等...

Will result in both text views being correctly placed, with separators between them etc...

此外,还可以混合静态和动态生成的数据,如下所示:

Additionally, it is also possible to mix static and dynamically generated data, like this:

List {
  Text("A")
  ForEach(foo) { fooElement in CustomView(fooElement) }
  Text("B")
  ForEach(bar) { barElement in CustomView(barElement) }
}

我的目标是编写我自己的自定义类型,允许其用户使用这种类型(即:允许用户使用新的函数构建器 DSL 提供视图的视图,而无需他们编写自己的修饰符来放置它们在屏幕上),但我完全不知道在我的自定义视图的初始化程序中放什么.

My goal is to write my own custom type that would allow this kind of use by its users (ie: a view that lets the users provide views using the new function builder DSL, without requiring them to write their own modifiers to place them on the screen), but I don't know at all what to put in the initialiser of my custom view.

原生 SwiftUI 视图正在使用 @ViewBuilder 并接收符合 View 的通用类型,但是它们能够提取元素的方式(例如,从ForEach 视图)很神秘,我很确定它甚至不可能.

The native SwiftUI views are making use of @ViewBuilder and receive a generic type conforming to View, but the way they are able to extract elements (from, say, a ForEach view) is mysterious and I'm pretty sure it's not even possible.

也许我错过了一些东西,所以我很想知道您对此的看法?

Maybe I missed something, so I'm curious to know your opinion about this?

举个例子可能更清楚.你们中的许多人一定在网上看到过使用 ZSack 将卡片排列在一起的好例子,那么如果我想创建一个 CardStack 类型来允许我的用户写这样的代码?

An example might be clearer. Many of you must have seen the nice examples online with cards arranged on top of each other using a ZSack, so what if I want to create a CardStack type that would allow my users to write code like this?

CardStack {
  SomeView()
  AnotherView()
  ForEach(1...10) { i in
    NumberView(i)
  }
}

这将导致 12 张卡片相互堆叠,请注意类型不是同质的,我们使用了 ForEach.

This would result in 12 cards stacked on top of each other, note that the types are not homogenous and that we used ForEach.

推荐答案

挑战的第一部分是找出 ViewBuilder.至于从孩子到祖先的数据流,请继续阅读:

The first part of your challenge is figuring out ViewBuilder. As for the flow of data from children to ancestors, please read on:

通过使用偏好(查看我的文章 https://swiftui-lab.com/communicating-with-the-view-tree-part-1/),你可以让信息从孩子传到祖先.

By using preferences (check my article https://swiftui-lab.com/communicating-with-the-view-tree-part-1/), you can make information flow from children to ancestors.

一旦您完全理解首选项并让它们起作用,您就可以尝试使实现更加清晰和透明,这样堆栈的最终用户甚至不会意识到他正在使用首选项.为此,您可以使用一些视图扩展.最终代码可能如下所示:

Once you fully understand preferences and get them to work, you can try making the implementation more clean and transparent, so that the end user of your Stack doesn't even realize he is using preferences. To do so, you could use some View extensions. The final code could look something like this:

CardStack {
   SomeView().card(title: "", border: .red)
   AnotherView().card(title: "", border: .green)

  ForEach(items) { item in
    NumberView(item).card(item.name, border: .blue)
  }
}

而你的 .card() 实现可能是这样的:

And your .card() implementation may be something like this:

extension View {
   func card(title: String, border: Color) -> CardCustomizer<Self> {
       return CardCustomizer(viewContent: self, title: title, border: border)
   }
}

struct CardCustomizer<Content: View>: View {
    public let viewContent: Content
    public let title: String
    public let border: Color

    var body: some View {
        viewContent.preference(MyCardPref.self, value: ...)
    }
}

我认为最好先尝试在没有 View 扩展的情况下使其工作,这样您就可以做对一件事.然后继续用扩展封装首选项逻辑.否则有太多新的事情要处理.

这篇关于自定义“列表"看法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆