越秀手机建网站/产品策划推广方案

越秀手机建网站,产品策划推广方案,自己创建一个网页,mini主机做网站服务器概览 在 SwiftUI 的世界里,我们无数次都梦想着视图可以自动根据布局上下文“因势而变”‌。大多数情况下,SwiftUI 会将每个视图尺寸处理的井井有条,不过在某些时候我们还是得亲力亲为。 如上图所示,无论顶部 TabView 容器里子视图…

在这里插入图片描述

概览

在 SwiftUI 的世界里,我们无数次都梦想着视图可以自动根据布局上下文“因势而变”‌。大多数情况下,SwiftUI 会将每个视图尺寸处理的井井有条,不过在某些时候我们还是得亲力亲为。

在这里插入图片描述

如上图所示,无论顶部 TabView 容器里子视图高度如何变化,TabView 本身的高度都能“随遇而安”。如何用最简单、最现代化、最有趣且最切中要害的方法让容器尺寸与子视图的高度“如影随形”呢?

在本篇博文中,您将学到如下内容:

  • 概览
  • 9. 最“相得益彰”的实现:自定义布局 Layout
    • 9.1 重装上阵 Layout
    • 9.2 “奇怪的” TabView
    • 9.3 MaxHeightLayout 的实现
  • 总结

相信学完本课后,小伙伴们必能脑洞大开、格局打开,用“千姿百态”的方法让问题的解决一发入魂、九转功成!

那还等什么呢?Let‘s go!!!😉


9. 最“相得益彰”的实现:自定义布局 Layout

在一口气介绍完上面 5 种“五花八门”的实现之后,我们完全可以“鸣金收兵”。但是为了面面俱到,我们最后还是决定用自定义布局 Layout 来为整个系列博文画一个圆满的句号。

9.1 重装上阵 Layout

所谓自定义布局 Layout,其实就是创建一款遵守 Layout 协议的“容器”(严格说应该是视图集合 Collection of views),然后“恣意”为内部的子视图“排兵布阵”:

在这里插入图片描述

为什么说用 Layout 这种方法更加“鞭辟入里”呢?因为这是处理多个同一层级子视图布局最自然的方式。

大家回忆一下:我们是将所有喜爱的成语用 ForEach 挨个放在 TabView 容器里的,在父容器中对它们的布局“运筹帷幄”是理所当然的事。


关于自定义布局的进一步介绍,请小伙伴们移步如下链接观赏精彩的文章:

  • SwiftUI 打造一款收缩自如的 HStack(四):Layout 自定义布局

9.2 “奇怪的” TabView

我们的目标是创建一个通用自定义布局 MaxHeightLayout,然后实时计算出所有子视图中最高的 Height。由于 MaxHeightLayout 是作为一个“容器”放在 TabView 中的,我们必须显式设置 TabView 的高度,而不能通过设置 MaxHeightLayout 的高度来间接影响 Tabview。

为什么会这样呢?这是由于 TabView 自身的特殊性质造成的。

比如在下面的代码中,我们在 TabView 里放置了一个高度为 200 的圆形:

TabView {Circle().foregroundStyle(.green.gradient).frame(height: 200)
}
.tabViewStyle(.page)

尽管我们将内部圆形的高度设置为 200,明确“暗示” TabView 把自己的高度也做出相应调整 ,但 TabView 还是会无动于衷:

在这里插入图片描述

要想 TabView 能够充分容纳高度为 200 的圆形,我们必须将 TabView 的高度显式设置为 200:

TabView {Circle().foregroundStyle(.green.gradient)
}
.tabViewStyle(.page)
.frame(height: 200)

在这里插入图片描述

换句话说,TabView 不会站在子视图的角度考虑问题,它会完全忽略子视图尺寸的提议,“一意孤行”。

9.3 MaxHeightLayout 的实现

上面讨论的结果迫使我们必须让自定义布局 MaxHeightLayout 想办法将计算产生的最大高度传递向外给 TabView 才行。

有很多种方法可以达到目的,这里我们采用最简单的一种:绑定(Binding)。

struct MaxHeightLayout: Layout {var spacing: CGFloat?@Binding var maxHeight: CGFloatfunc sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {let proposalWidth = proposal.width!let idealViewSizes = subviews.map { $0.sizeThatFits(.init(width: proposalWidth / CGFloat(subviews.count), height: nil)) }let totalHeight = idealViewSizes.map {$0.height}.max() ?? 0.0// 防止反复赋值造成渲染循环if totalHeight > maxHeight {maxHeight = totalHeight}return CGSize(width: proposalWidth, height: totalHeight)}private func calcSpaces(subviews: Subviews) -> [CGFloat] {if let spacing {[CGFloat](repeating: spacing, count: subviews.count - 1)} else {subviews.indices.map { idx inguard idx < subviews.count - 1 else { return 0 }return subviews[idx].spacing.distance(to: subviews[idx+1].spacing, along: .horizontal)}}}func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {let spaces = calcSpaces(subviews: subviews)var point = CGPoint(x: bounds.minX, y: bounds.minY)let subviewWidth = bounds.width / CGFloat(subviews.count)for idx in subviews.indices {subviews[idx].place(at: point, proposal: .init(width: subviewWidth - spaces[idx], height: maxHeight))if idx < subviews.count - 1 {point.x += subviewWidth - spaces[idx]}}}    
}

在上面的代码中,我们主要做了这么几件事:

  • 让 MaxHeightLayout “容器”中每个子视图的宽都平分容器的宽度;
  • 用 calcSpaces 方法计算子视图间的空隙,并确保 placeSubviews 方法在布局子视图时应用它们;
  • 只在必要时更新 maxHeight 绑定的值(totalHeight > maxHeight 时),这是避免“递归渲染”的重要手段;

最后,只要将 TabView 中原来内层的 ForEach 循环以及相关逻辑放在 MaxHeightLayout 里就可以啦:

Section("喜爱的成语") {TabView {ForEach(likeIdioms.chunked(into: 2), id: \.self) { idiomChunk inVStack {MaxHeightLayout(maxHeight: $maxHeight) {                    ForEach(idiomChunk) { idiom inlikeIdiomCard(idiom)}if idiomChunk.count < 2 {Rectangle().foregroundStyle(.clear)}}Spacer()}}}.tabViewStyle(.page).frame(height: maxHeight).padding(.bottom, 8)
}

运行代码可以发现结果和其它的实现毫无二致!

在这里插入图片描述

借助自定义布局 Layout 的灵活性,我们可以非常轻松的改变 TabView 中成语显示的数量,比如改为 3 列也不在话下:

在这里插入图片描述

至此,我们圆满完成了本系列博文中的所有任务。秃头小伙伴们还不赶紧给自己一个大大的赞吧!爱你们哦!❤


想要进一步系统地学习 Swift 开发的小伙伴们,可以来我的《Swift 语言开发精讲》专栏逛一逛哦:

在这里插入图片描述

  • 《Swift 语言开发精讲》

总结

在本篇博文中,我们介绍了如何使用自定义布局 Layout 来实现 SwiftUI 视图高度的“遥相呼应”,精彩的大结局小伙伴们不容错过哦!

感谢观赏,再会啦!😎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/73087.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小程序SSL证书过期怎么办?

SSL证书就像小程序的“安全锁”&#xff0c;一旦过期&#xff0c;用户访问时会被提示“不安全”&#xff0c;轻则流失客户&#xff0c;重则数据泄露&#xff01;作为企业负责人&#xff0c;如何快速解决证书过期问题&#xff1f;又该如何避免再次踩坑&#xff1f;这篇指南给你答…

DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加列宽调整功能,示例Table14_02带边框和斑马纹的固定表头表格

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…

基础算法——顺序表

一、询问学号 题⽬来源&#xff1a;洛⾕ 题⽬链接&#xff1a;P3156 【深基15.例1】询问学号 - 洛谷 难度系数&#xff1a;★ 1. 题目描述 2. 算法原理 直接⽤ vector 或者数组模拟即可。 3. 参考代码 #include <iostream> #include <vector>using namespace st…

Ubuntu用户安装cpolar内网穿透

前言 Cpolar作为一款体积小巧却功能强大的内网穿透软件&#xff0c;不仅能够在多种环境和应用场景中发挥巨大作用&#xff0c;还能适应多种操作系统&#xff0c;应用最为广泛的Windows、Mac OS系统自不必多说&#xff0c;稍显小众的Linux、树莓派、群辉等也在起支持之列&#…

Oracle比较好的几本书籍

1.《Oracle专家高级编程》 2.《Oracle高效设计》 3.《Oracle9i&10g&11g编程艺术深入数据库体系结构》 4.《让Oracle跑的更快》(1/2) ....... n.《Oracle官方文档的阅读》下面包括这几个部分&#xff0c;可以跟进研读一下&#xff1a; &#xff08;1&#xff09;《…

Android : Camera之CHI API

来自&#xff1a; https://www.cnblogs.com/szsky/articles/10861918.html 一、CAM CHI API功能介绍&#xff1a; CHI API建立在Google HAL3的灵活性基础之上&#xff0c;目的是将Camera2/HAL3接口分离出来用于使用相机功能&#xff0c;它是一个灵活的图像处理驱动程序&#…

Netty基础—2.网络编程基础四

大纲 1.网络编程简介 2.BIO网络编程 3.AIO网络编程 4.NIO网络编程之Buffer 5.NIO网络编程之实战 6.NIO网络编程之Reactor模式 5.NIO网络编程之Buffer (1)Buffer的作用 Buffer的作用是方便读写通道(Channel)中的数据。首先数据是从通道(Channel)读入缓冲区&#xff0c;从…

调试正常 ≠ 运行正常:Keil5中MicroLIB的“量子态BUG”破解实录

调试正常 ≠ 运行正常&#xff1a;Keil5中MicroLIB的“量子态BUG”破解实录——从勾选一个选项到理解半主机模式&#xff0c;嵌入式开发的认知升级 &#x1f4cc; 现象描述&#xff1a;调试与烧录的诡异差异 在线调试时 程序正常运行 - 独立运行时 设备无响应 ! 编译过程 0 Err…

算法每日一练 (9)

&#x1f4a2;欢迎来到张胤尘的技术站 &#x1f4a5;技术如江河&#xff0c;汇聚众志成。代码似星辰&#xff0c;照亮行征程。开源精神长&#xff0c;传承永不忘。携手共前行&#xff0c;未来更辉煌&#x1f4a5; 文章目录 算法每日一练 (9)最小路径和题目描述解题思路解题代码…

【高项】信息系统项目管理师(四)项目整合管理【4分】

一、管理基础 项目整合管理的责任不能被授权或转移&#xff0c;项目经理必须对整个项目承担最终责任。 执行项目整合时项目经理承担双重角色&#xff1a; 1、组织层面上&#xff0c;项目经理扮演重要角色&#xff0c;与项目发起人携手合作&#xff0c;了解战略目标并确保项目目…

初次体验Tauri和Sycamore(3)通道实现

​ 原创作者&#xff1a;庄晓立&#xff08;LIIGO&#xff09; 原创时间&#xff1a;2025年03月10日&#xff08;发布时间&#xff09; 原创链接&#xff1a;https://blog.csdn.net/liigo/article/details/146159327 版权所有&#xff0c;转载请注明出处。 20250310 LIIGO备注&…

蓝耘赋能通义万相 2.1:用 C++ 构建高效 AI 视频生成生态

目录 开篇&#xff1a;AI 视频生成新时代的号角 通义万相 2.1&#xff1a;AI 视频生成的领军者 核心技术揭秘 功能特点展示 与其他模型的全面对比 C&#xff1a;高效编程的基石 C 的发展历程与特性 C 在 AI 领域的广泛应用 通义万相 2.1 与 C 的完美融合 融合的意义与…

自然语言处理文本分析:从词袋模型到认知智能的进化之旅

清晨&#xff0c;当智能音箱准确识别出"播放周杰伦最新专辑"的模糊语音指令时&#xff1b;午间&#xff0c;企业舆情系统自动标记出十万条评论中的负面情绪&#xff1b;深夜&#xff0c;科研人员用GPT-4解析百万篇论文发现新材料线索——这些场景背后&#xff0c;是自…

uniapp+Vue3 组件之间的传值方法

一、父子传值&#xff08;props / $emit 、ref / $refs&#xff09; 1、props / $emit 父组件通过 props 向子组件传递数据&#xff0c;子组件通过 $emit 触发事件向父组件传递数据。 父组件&#xff1a; // 父组件中<template><view class"container">…

【MySQL篇】MySQL基本查询详解

目录 前言&#xff1a; 1&#xff0c;Create 1.1&#xff0c;单行数据全列插入 1.2&#xff0c;单行数据指定列插入 1.3&#xff0c;多行数据全列插入 1.4&#xff0c;多行数据指定列插入 1.5&#xff0c;插入否则更新 1.6&#xff0c;替换 2&#xff0c;Retrieve …

【Python入门】一篇掌握Python中的字典(创建、访问、修改、字典方法)【详细版】

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;《Python/PyTorch极简课》_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目…

每日一题——两数相加

两数相加 问题描述问题分析解题思路代码实现代码解析注意事项示例运行总结 问题描述 给定两个非空链表&#xff0c;表示两个非负整数。链表中的每个节点存储一个数字&#xff0c;数字的存储顺序为逆序&#xff08;即个位在链表头部&#xff09;。要求将这两个数字相加&#xff…

C++20 模块:告别头文件,迎接现代化的模块系统

文章目录 引言一、C20模块简介1.1 传统头文件的局限性1.2 模块的出现 二、模块的基本概念2.1 模块声明2.2 模块接口单元2.3 模块实现单元 三、模块的优势3.1 编译时间大幅减少3.2 更好的依赖管理3.3 命名空间隔离 四、如何使用C20模块4.1 编译器支持4.2 示例项目4.3 编译和运行…

sql靶场5-6关(报错注入)保姆级教程

目录 sql靶场5-6关&#xff08;报错注入&#xff09;保姆级教程 1.第五关 1.步骤一&#xff08;闭合&#xff09; 2.步骤二&#xff08;列数&#xff09; 3.报错注入深解 4.报错注入格式 5.步骤三&#xff08;数据库表名&#xff09; 6.常用函数 7.步骤四&#xff08;表…

OSPF-单区域的配置

一、单区域概念&#xff1a; 单区域OSPF中&#xff0c;整个网络被视为一个区域&#xff0c;区域ID通常为0&#xff08;骨干区域&#xff09;。所有的路由器都在这个区域内交换链路状态信息。 补充知识点&#xff1a; OSPF为何需要loopback接口&#xff1a; 1.Loopback接口的…