前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >SwiftUI 新容器视图 API 深度解析:轻松构建自定义布局

SwiftUI 新容器视图 API 深度解析:轻松构建自定义布局

原创
作者头像
Swift社区
发布于 2024-09-30 03:17:18
发布于 2024-09-30 03:17:18
4030
举报
文章被收录于专栏:Swift社区Swift社区

前言

自 SwiftUI 的第一个版本发布以来,它就拥有了几种容器视图。最常用的有 HStack、VStack、List 等。今年,Apple 引入了新的 API,使我们能够以全新的方式构建自定义容器视图。本周,我们将学习 SwiftUI 新的分解 API 的优势。

容器视图

容器视图就是一个可以包含其他视图的视图。我们可以使用 @ViewBuilder 闭包轻松定义一个容器视图。以下是一个示例:

代码语言:swift
AI代码解释
复制
struct Card<Content: View>: View {
    @ViewBuilder var content: Content
    
    var body: some View {
        VStack {
            content
        }
        .padding()
        .background(Material.regular, in: .rect(cornerRadius: 8))
        .shadow(radius: 4)
    }
}

如上面的例子所示,我们创建了 Card 视图,它是一个用于容纳任何 SwiftUI 视图的容器视图。它使用 @ViewBuilder 闭包包裹了内容,并添加了一个圆角背景和阴影。

代码语言:swift
AI代码解释
复制
struct ContentView: View {
    var body: some View {
        Card {
            Text("Hello, World!")
            Text("My name is Majid Jabrayilov")
        }
    }
}

这个 Card 类型使用起来非常简单。你只需创建一个 Card,并使用闭包提供内容。通过在 Card 容器视图内嵌入不同的视图,你可以在应用的多个屏幕中复用它。

这是使用容器视图的主要优势之一:你可以通过将共享的功能封装在容器视图中,在应用的不同地方重复使用它们。

想了解更多关于 @ViewBuilder 闭包的内容,可以查看我关于 “SwiftUI 中 @ViewBuilder 的强大功能” 的文章。

使用 ViewBuilder

@ViewBuilder 闭包让我们可以轻松地组合多个视图,并将一个视图嵌入到另一个视图中。但是如何从 @ViewBuilder 闭包中提取子视图呢?SwiftUI 引入了新的 API,允许我们重新组合视图。例如,我们可以从通过 @ViewBuilder 闭包构建的内容视图中提取子视图,并根据需要将它们放置。

代码语言:swift
AI代码解释
复制
struct Carousel<Content: View>: View {
    @ViewBuilder var content: Content
    
    var body: some View {
        ScrollView(.horizontal) {
            LazyHStack {
                ForEach(subviews: content) { subview in
                    subview
                        .containerRelativeFrame(.horizontal)
                }
            }
            .scrollTargetLayout()
        }
        .scrollTargetBehavior(.viewAligned)
        .contentMargins(16)
    }
}

如上面的示例所示,我们使用了带有 subviews 参数的 ForEach 视图,这使我们能够提取内容视图的子视图并对它们进行迭代。

代码语言:swift
AI代码解释
复制
struct ContentView: View {
    var body: some View {
        Carousel {
            Color.yellow
            Color.orange
            Color.red
            Color.blue
            Color.green
        }
    }
}

SwiftUI 使用特定的 Subview 类型来公开提取视图的实例。它符合 View 协议,因此我们仍然可以附加额外的 SwiftUI 视图修饰符。它还为我们提供了 id 属性,这是一个唯一标识符,以及与特定视图关联的容器值。我们将在接下来的文章中更多讨论容器值。

访问子视图

另一种新的 API 允许我们通过索引访问子视图,而不是使用 ForEach 视图进行迭代。

代码语言:swift
AI代码解释
复制
struct Magazine<Content: View>: View {
    @ViewBuilder var content: Content
    
    var body: some View {
        ScrollView {
            Group(subviews: content) { subviews in
                if !subviews.isEmpty {
                    subviews[0]
                        .padding(.horizontal)
                        .containerRelativeFrame(.vertical) { length, _ in
                            return length / 3
                        }
                }
                
                if subviews.count > 1 {
                    ScrollView(.horizontal) {
                        LazyHStack {
                            ForEach(subviews[1...], id: \.id) { subview in
                                subview
                                    .containerRelativeFrame([.horizontal, .vertical])
                            }
                        }
                        .scrollTargetLayout()
                    }
                    .scrollTargetBehavior(.viewAligned)
                    .contentMargins(16)
                }
            }
        }
    }
}

在上面的示例中,我们使用了带有 subviews 参数的 Group 视图,它允许我们将子视图提取到一个名为 SubviewsCollection 的集合类型中。SubviewsCollection 类型符合 RandomAccessCollection 协议,并为我们提供了通过索引访问的功能。

组合子视图

如你所见,我们使用 Group 视图来分解内容视图,然后以另一种方式组合子视图。我们还利用了 id 参数的功能,允许我们使用 ForEach 视图与普通数据一起工作。

代码语言:swift
AI代码解释
复制
struct ContentView: View {
    var body: some View {
        Magazine {
            Color.yellow
            Color.orange
            Color.red
            Color.blue
            Color.green
        }
    }
}

可运行的 Demo

根据文章内容,我将提供一个可以展示如何使用 SwiftUI 新的容器视图 API 构建自定义视图的简单示例,包含 CardCarouselMagazine 容器视图。

代码语言:swift
AI代码解释
复制
import SwiftUI

// 定义 Card 视图,作为一个基本的容器视图
struct Card<Content: View>: View {
    @ViewBuilder var content: Content
    
    var body: some View {
        VStack {
            content
        }
        .padding()
        .background(Material.regular, in: RoundedRectangle(cornerRadius: 8))
        .shadow(radius: 4)
    }
}

// 定义 Carousel 视图,横向滚动的自定义容器视图
struct Carousel<Content: View>: View {
    @ViewBuilder var content: Content
    
    var body: some View {
        ScrollView(.horizontal) {
            LazyHStack {
                ForEach(subviews: content) { subview in
                    subview
                        .containerRelativeFrame(.horizontal)
                }
            }
            .scrollTargetLayout()
        }
        .scrollTargetBehavior(.viewAligned)
        .contentMargins(16)
    }
}

// 定义 Magazine 视图,具有垂直和水平组合布局的自定义容器视图
struct Magazine<Content: View>: View {
    @ViewBuilder var content: Content
    
    var body: some View {
        ScrollView {
            Group(subviews: content) { subviews in
                // 第一个子视图为大图
                if !subviews.isEmpty {
                    subviews[0]
                        .padding(.horizontal)
                        .containerRelativeFrame(.vertical) { length, _ in
                            return length / 3
                        }
                }
                
                // 其余子视图为横向滚动小图
                if subviews.count > 1 {
                    ScrollView(.horizontal) {
                        LazyHStack {
                            ForEach(subviews[1...], id: \.id) { subview in
                                subview
                                    .containerRelativeFrame([.horizontal, .vertical])
                            }
                        }
                        .scrollTargetLayout()
                    }
                    .scrollTargetBehavior(.viewAligned)
                    .contentMargins(16)
                }
            }
        }
    }
}

// 主视图,使用自定义容器视图
struct ContentView: View {
    var body: some View {
        VStack {
            // 使用 Card 视图
            Card {
                Text("SwiftUI 容器视图示例")
                    .font(.headline)
                Text("使用 Card 容器轻松复用视图")
            }
            .padding()
            
            // 使用 Carousel 视图
            Carousel {
                Color.yellow
                Color.orange
                Color.red
                Color.blue
                Color.green
            }
            .frame(height: 100)
            .padding()
            
            // 使用 Magazine 视图
            Magazine {
                Color.pink
                Color.purple
                Color.teal
                Color.mint
            }
            .frame(height: 300)
        }
        .padding()
    }
}

// 主应用入口
@main
struct ContainerViewDemoApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

功能概述

  1. Card:一个简单的容器视图,可以包裹任何内容并添加背景和阴影。你可以在应用中的多个地方使用该容器来保持一致的样式。
  2. Carousel:一个横向滚动的容器视图,可以自动排列并展示内容,适合展示横向滑动的图像或视图。
  3. Magazine:一个自定义的容器视图,允许你将第一个子视图设置为大图,其他子视图横向排列展示。类似于杂志布局。

运行这个Demo

此代码展示了如何在 SwiftUI 中构建自定义的容器视图,灵活地将不同的布局封装在容器中,以便在应用中多次复用这些布局模式。

总结

通过使用 SwiftUI 新引入的 API 以及容器视图,你可以轻松构建具有良好复用性的自定义布局,提升应用的开发效率和代码可维护性。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
【prometheus】-02 一张图彻底搞懂Prometheus服务发现机制
Prometheus是基于Pull模式抓取监控数据,首先要能够发现需要监控的目标对象target,特别Prometheus最开始设计是一个面向云原生应用程序的,云原生、容器场景下按需的资源使用方式对于监控系统而言就意味着没有了一个固定的监控目标,所有的监控对象(基础设施、应用、服务)都在动态的变化。而对于Prometheus而言其解决方案就是引入一个中间的代理人(服务注册中心),这个代理人掌握着当前所有监控目标的访问信息,Prometheus只需要向这个代理人询问有哪些监控目标控即可, 这种模式被称为服务发现(service discovery)。
Reactor2020
2023/03/22
8960
【prometheus】-02 一张图彻底搞懂Prometheus服务发现机制
【云原生 • Prometheus】图解Prometheus数据抓取原理
discovery模块利用各种服务发现协议发现目标采集点,并通过channel管道将最新发现的目标采集点信息实时同步给scrape模块,scrape模块负责使用http协议从目标采集点上抓取监控指标数据。
Reactor2020
2023/04/20
1.4K0
【云原生 • Prometheus】图解Prometheus数据抓取原理
prometheus 服务发现原理
如上图,Prometheus核心功能包括服务发现、数据采集和数据存储。服务发现模块专门负责发现需要监控的目标采集点(target)信息,数据采集模块从服务发现模块订阅该信息,获取到target信息后,其中就包含协议(scheme)、主机地址:端口(instance)、请求路径(metrics_path)、请求参数(params)等;然后数据采集模块就可以基于这些信息构建出一个完整的Http Request请求,定时通过pull http协议不断的去目标采集点(target)拉取监控样本数据(sample);最后,将采集到监控样本数据交由TSDB模块进行数据存储。
Reactor2020
2023/03/22
5620
prometheus 服务发现原理
构建企业级监控平台系列(十三):Prometheus Server 配置详解
更多关于企业级监控平台系列的学习文章,请参阅:构建企业级监控平台,本系列持续更新中。
民工哥
2023/10/23
1.7K0
构建企业级监控平台系列(十三):Prometheus Server 配置详解
​修改prometheus实现数据库存储报警规则和收集目标
prometheus本身报警规则及服务发现策略基于文件配置很不方便,对于非K8S服务监控经常需要操作配置文件,不利于管理系统平台化建设。实现思路:将相关配置信息存储在MySQL里,加入新的逻辑,实现保留文件加载配置的同时,加载MySQL中的信息, 动态生成 static_config及 alert_rule从而实现报警及监控目标的配置UI化.
有点技术
2020/07/14
1.3K0
prometheus内核
这篇文章会着重分析 其中的 discovery => scrap => storage 的流程
王磊-字节跳动
2019/12/29
2.5K0
初试 Prometheus + Grafana 监控系统搭建并监控 Mysql
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/aixiaoyang168/article/details/81354059
哎_小羊
2019/05/25
2.1K0
Prometheus +VictoriaMetrics+Granafa安装部署
https://github.com/prometheus/prometheus/releases/download/v2.54.1/prometheus-2.54.1.linux-amd64.tar.gz
授客
2025/01/19
1960
Prometheus +VictoriaMetrics+Granafa安装部署
运维实战来了!如何构建适用于YashanDB的Prometheus Exporter
小崖又收到用户投稿啦。今天分享的是构建YashanDB Exporter的核心设计理念和关键方法,希望也能为你的运维实战加分!
qiaoyikefu
2025/01/09
830
运维实战来了!如何构建适用于YashanDB的Prometheus Exporter
新功能:Prometheus Agent 模式上手体验
Prometheus 几乎已经成为了云原生时代下监控选型的事实标准,它也是第二个从 CNCF 毕业的项目。
Jintao Zhang
2021/12/01
1.4K0
新功能:Prometheus Agent 模式上手体验
【prometheus】-08 图解云原生服务发现机制
分析过云原生监控接入方案,下面开始看下云原生服务发现机制。Prometheus本身就是作为云原生监控出现的,所以对云原生服务发现支持具有天然优势。Kubernetes 服务发现协议允许使用Kubernetes Rest API检索出Prometheus需要监控的targets,并且跟着集群状态进行同步变更。
Reactor2020
2023/03/22
3960
【prometheus】-08 图解云原生服务发现机制
《Prometheus监控实战》第3章 安装和启动Prometheus
第3章 安装和启动Prometheus ---- 3.1 安装Prometheus 如果要将Prometheus部署到生产环境或进行扩展,则应该始终选择配置管理工具作为安装方法 下载地址:https://prometheus.io/download/ 3.1.4 在Mac OS X上安装Prometheus $ brew install prometheus 3.1.5 通过监控套件安装Prometheus 使用Docker Compose安装Prometheus、Node Exporter和Grafan
yeedomliu
2019/12/19
1.3K0
打造云原生大型分布式监控系统(三): Thanos 部署与实践
上一篇 Thanos 架构详解 我们深入理解了 thanos 的架构设计与实现原理,现在我们来聊聊实战,分享一下如何部署和使用 Thanos。
imroc
2020/04/20
6.3K5
在 Kubernetes 上手动部署 Prometheus
我们知道监控是保证系统运行必不可少的功能,特别是对于 Kubernetes 这种比较庞大的系统来说,监控报警更是不可或缺,我们需要时刻了解系统的各种运行指标,也需要时刻了解我们的 Pod 的各种指标,更需要在出现问题的时候有报警信息通知到我们。
CNCF
2021/02/23
8440
在 Kubernetes 上手动部署 Prometheus
Prometheus监控学习笔记之Prometheus如何热加载更新配置
当 Prometheus 有配置文件修改,我们可以采用 Prometheus 提供的热更新方法实现在不停服务的情况下实现配置文件的重新加载。
Jetpropelledsnake21
2019/10/10
7K0
Prometheus监控学习笔记之Prometheus如何热加载更新配置
prometheus告警规则管理
Prometheus支持用户自定义Rule规则。Rule分为两类,一类是Recording Rule,另一类是Alerting Rule。Recording Rule的主要目的是通过PromQL可以实时对Prometheus中采集到的样本数据进行查询,聚合以及其它各种运算操作。而在某些PromQL较为复杂且计算量较大时,直接使用PromQL可能会导致Prometheus响应超时的情况。这时需要一种能够类似于后台批处理的机制能够在后台完成这些复杂运算的计算,对于使用者而言只需要查询这些运算结果即可。Prometheus通过Recoding Rule规则支持这种后台计算的方式,可以实现对复杂查询的性能优化,提高查询效率。
没有故事的陈师傅
2021/09/09
1.9K0
初玩prometheus
因为Prometheus是基于GoLang编写,编译后的软件包,不依赖于任何的第三方依赖。用户只需要下载对应平台的二进制包,并解压添加基本配置即可正常启动Prometheus server。
张琳兮
2019/11/04
8970
初玩prometheus
运维实战来了!如何构建适用于 YashanDB 的 Prometheus Exporter
小崖又收到用户投稿啦。今天分享的是构建 YashanDB Exporter 的核心设计理念和关键方法,希望也能为你的运维实战加分!
用户10349277
2025/02/21
1320
如何使用Prometheus配置自定义告警规则
Prometheus是一个用于监控和告警的开源系统。一开始由Soundcloud开发,后来在2016年,它迁移到CNCF并且称为Kubernetes之后最流行的项目之一。从整个Linux服务器到stand-alone web服务器、数据库服务或一个单独的进程,它都能监控。在Prometheus术语中,它所监控的事物称为目标(Target)。每个目标单元被称为指标(metric)。它以设置好的时间间隔通过http抓取目标,以收集指标并将数据放置在其时序数据库(Time Series Database)中。你可以使用PromQL查询语言查询相关target的指标。
CNCF
2020/03/25
6.1K0
如何使用Prometheus配置自定义告警规则
prometheus使用总结(2)
建议使用第五步启动方式,找到配置文件加上--web.enable-lifecycle,此参数的意义在于我们修改了prometheus.yml后直接远程热加载即可,不用重启服务,使用下面的命令即可。
Bob hadoop
2021/04/01
1.5K0
推荐阅读
相关推荐
【prometheus】-02 一张图彻底搞懂Prometheus服务发现机制
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档