当前位置: 首页 > news >正文

SwiftUI 5.0(iOS 17)进一步定制 TipKit 外观让撸码如虎添翼

在这里插入图片描述

概览

在之前 SwiftUI 5.0(iOS 17)TipKit 让用户更懂你的 App 这篇博文里,我们已经初步介绍过了 TipKit 的基本知识。

在这里插入图片描述

现在,让我们来看看如何进一步利用 SwiftUI 对 TipKit 提供的细粒度外观定制技巧,让 Tip 更加“明眸皓齿”。

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

  • 概览
  • 1. TipKit 温故而知新
  • 2. Tip 外观细粒度定制
  • 3. 完全自己打造 Tip 外观
  • 总结

相信学完本课后,小伙伴们对 TipKit 的内功修为会更加炉火纯青、登峰造极!

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


本文对应的视频课在此,欢迎小伙伴们恣意观赏!

SwiftUI 定制 TipKit 外观进一步让撸码如虎添翼


1. TipKit 温故而知新

在前一篇关于 TipKit 的博文中,我们介绍了什么是 TipKit 以及如何在 App 中支持 TipKit 的方法。

这里再回忆一下:创建一个 Tip 很简单,我们只需让类型遵守 Tip 协议即可。

struct FavoriteTip: Tip {var title: Text {Text("收藏最爱的图片").bold()}var message: Text? {Text("将心仪的图片保存到相册中").font(.headline).foregroundStyle(.gray.gradient)}var image: Image? {Image(systemName: "heart")}
}

然后,我们可以通过嵌入和弹出两种不同方法来显示它:

// 嵌入 Tip
struct ContentView: View {let favTip = FavoriteTip()var body: some View {NavigationStack {VStack {TipView(favTip)}.padding().navigationTitle("TitKit演示")}}
}// 弹出 Tip
struct ContentView: View {let favTip = FavoriteTip()var body: some View {NavigationStack {VStack {...}.padding().navigationTitle("TitKit演示").toolbar {ToolbarItem {Image(systemName: "heart").font(.title.weight(.black)).foregroundStyle(.pink.gradient).popoverTip(favTip, arrowEdge: .top)}}}}
}

嵌入和弹出 Tip 的效果如下图所示:

嵌入 Tip

弹出 Tip

如果大家对于默认 Tip 的外观不甚满意怎么办?别急,SwiftUI 还有“妙计”。

2. Tip 外观细粒度定制

Apple 在推出 TipKit 框架的同时也提供了若干修改器方法,我们可以利用它们来进一步调整 Tip 视图的外观。

首先是 tipCornerRadius() 方法,它可以用来调整 Tip 视图边角的弧度:

struct ContentView: View {let favTip = FavoriteTip()@State var addTipRadius = falsevar body: some View {NavigationStack {VStack {TipView(favTip)Toggle(isOn: $addTipRadius) {Text("增加 Tip 边角弧度").font(.title3)}}.padding().navigationTitle("TitKit演示").tipCornerRadius(addTipRadius ? 30 : 10).frame(maxHeight: .infinity).background(.gray.opacity(0.66).gradient).animation(.bouncy, value: addTipRadius)}}
}

值得注意的是:tipCornerRadius 修改器方法和随后介绍的所有 Tip 外观调整方法都会沿着视图继承树向下传递,这意味着顶层的方法会影响内部所有的 Tip 外观。

在这里插入图片描述

接下来是 tipImageSize() 修改器,我们可以用它来调整 Tip 内部图片的尺寸:

NavigationStack {VStack {TipView(favTip)}.tipImageSize(CGSize(width: incImageSize ? 50 : 24, height: incImageSize ? 50 : 24)).frame(maxHeight: .infinity).background(.gray.opacity(0.66).gradient).animation(.bouncy, value: incImageSize)
}

运行效果如下所示:

在这里插入图片描述

最后,我们可以用 tipBackground() 修改器方法来调整 Tip 视图背景的显示样式:

NavigationStack {VStack {TipView(favTip)}.tipBackground(incBackgroundHue ? Material.ultraThick : .thin).frame(maxHeight: .infinity).background(.gray.opacity(0.66).gradient).animation(.bouncy, value: incImageSize)
}

运行的效果不出意料:

在这里插入图片描述

上面我们介绍了一些从宏观上调整 Tip 外观的方法,如果小伙伴们还是觉得捉襟见肘、鸟入樊笼怎么办?

别急,我们还可以“欲穷千里目,更上一层楼”:自己动手“丰衣足食”来 100% “恣意”决定 Tip 该如何显示。

3. 完全自己打造 Tip 外观

为了最大程度满足秃头码农们随心所欲定制 Tip 外观的需求,苹果决定将 Tip 的外观样式化(Styling)以便让我们可以无拘无束定制它们“主题皮肤”。

经常撸 SwiftUI 代码的小伙伴们都知道,在 SwiftUI 中大部分原生视图都有对应的样式(Style),比如按钮、Label、Toggle 等等。视图样式为我们充分定制视图的外观带来了极大的便利。

TipKit 也不例外,我们同样可以利用 tipViewStyle() 修改器来排忧解难:

在这里插入图片描述

为了能够安闲自在的 100% 纯手工打造 Tip 的外观,我们首先需要“由着性子”创建一个遵守 TipViewStyle 协议的类型:

struct PureCustomTipViewStyle: TipViewStyle {func makeBody(configuration: Configuration) -> some View {VStack(alignment: .leading) {HStack(alignment: .bottom) {if let image = configuration.image {image.resizable().aspectRatio(contentMode: .fit).font(.title.weight(.heavy)).frame(width: 25, height: 25).foregroundStyle(.teal).padding().overlay {RoundedRectangle(cornerRadius: 15.0).stroke(.secondary, lineWidth: 3.0)}}Rectangle().frame(width: 3, height: 100).foregroundStyle(.white.gradient)VStack(alignment: .leading) {if let title = configuration.title {title.font(.headline)}if let message = configuration.message {Group {message.font(.subheadline).padding()}.background {RoundedRectangle(cornerRadius: 15.0).foregroundStyle(Material.thin)}}}}HStack {Spacer()ForEach(configuration.actions, id: \.id) { action inButton {action.handler()} label: {Image(systemName: "volleyball.fill").foregroundStyle(.yellow.gradient)action.label()}.fontWeight(.bold).buttonStyle(.borderedProminent)}}}.padding().background {Image("bg").resizable().opacity(0.77)}}
}

接着,为了方便起见我们还可以将上面创建的 Tip 自定义样式融入到 TipViewStyle 自身中去:

extension TipViewStyle where Self == PureCustomTipViewStyle {static var pureCustom: Self {Self.init()}
}

最后在 Tip 视图本身或其上层容器中,我们即可悠然自得的调用 tipViewStyle() 修改器方法来施展改头换面的“黑魔法”啦:

struct ContentView: View {let favTip = FavoriteTip()@State var addTipRadius = false@State var incImageSize = false@State var incBackgroundHue = falsevar body: some View {NavigationStack {VStack {TipView(favTip)Toggle(isOn: $addTipRadius) {Text("增加 Tip 边角弧度").font(.title3)}Toggle(isOn: $incImageSize) {Text("增加 Tip 图片大小").font(.title3)}Toggle(isOn: $incBackgroundHue) {Text("增加 Tip 背景色度").font(.title3)}}.padding().navigationTitle("TitKit演示").tipCornerRadius(addTipRadius ? 30 : 10).tipImageSize(CGSize(width: incImageSize ? 50 : 24, height: incImageSize ? 50 : 24)).tipBackground(incBackgroundHue ? Material.ultraThick : .thin)// 应用我们的自定义 Tip 样式.tipViewStyle(.pureCustom).frame(maxHeight: .infinity).background(.gray.opacity(0.66).gradient).animation(.bouncy, value: addTipRadius).animation(.bouncy, value: incImageSize).animation(.bouncy, value: incBackgroundHue)}}
}

编译运行代码,现在用全身毛孔来感受一下纯手工打造 Tip 界面的愉悦之美吧!

在这里插入图片描述

至此,我们完全掌握了 TipKit 中外观调整与定制的全部技巧,小伙伴们还不赶快发挥天马行空般的想象力打造自己的 Tip 视图吧!棒棒哒!💯


想要系统学习 Swift 语言的小伙伴们,千万不要错过我的《Swift 语言开发精讲》专栏哦,欢迎大家恣意观赏:

在这里插入图片描述

  • Swift 语言开发精讲

总结

在本篇博文中,我们介绍了 SwiftUI 5.0 中从宏观全局调整 Tip 视图显示的几种方式。如果小伙伴们觉得还是不能放开手脚,我们还探讨了如何 100% 纯手工打造自己 Tip 内部布局的方法,包您满意!

感谢观赏,再会!😎

相关文章:

  • Android UI控件详细解析(四)
  • 【新能源大巴BMS结构与乘用车的区别】
  • 每日一题——Python实现PAT甲级1041 Be Unique(举一反三+思想解读+逐步优化)
  • java使用资源过高排查
  • 解析Java中1000个常用类:Cloneable类,你学会了吗?
  • linux-gpio
  • 【代码随想录算法训练营第37期 day21 | LeetCode530.二叉搜索树的最小绝对差、501.二叉搜索树中的众数、236. 二叉树的最近公共祖先】
  • Java集合【超详细】
  • 实战经验分享之移动云快速部署Stable Diffusion SDXL 1.0
  • K8S中Prometheus+Grafana监控
  • Wpf 使用 Prism 实战开发Day30
  • YOLOv5训练自定义数据集模型的参数与指令说明
  • Flutter 中的 SliverFillRemaining 小部件:全面指南
  • Golang | Leetcode Golang题解之第120题三角形最小路径和
  • kafka-消费者组-发布订阅测试
  • 【面试系列】之二:关于js原型
  • 03Go 类型总结
  • iOS高仿微信项目、阴影圆角渐变色效果、卡片动画、波浪动画、路由框架等源码...
  • SegmentFault 技术周刊 Vol.27 - Git 学习宝典:程序员走江湖必备
  • socket.io+express实现聊天室的思考(三)
  • 海量大数据大屏分析展示一步到位:DataWorks数据服务+MaxCompute Lightning对接DataV最佳实践...
  • 我的业余项目总结
  • ​一些不规范的GTID使用场景
  • # Redis 入门到精通(七)-- redis 删除策略
  • #07【面试问题整理】嵌入式软件工程师
  • #1015 : KMP算法
  • $.ajax()参数及用法
  • (1)(1.13) SiK无线电高级配置(六)
  • (2024)docker-compose实战 (8)部署LAMP项目(最终版)
  • (7)STL算法之交换赋值
  • (Arcgis)Python编程批量将HDF5文件转换为TIFF格式并应用地理转换和投影信息
  • (C#)if (this == null)?你在逗我,this 怎么可能为 null!用 IL 编译和反编译看穿一切
  • (八十八)VFL语言初步 - 实现布局
  • (翻译)Quartz官方教程——第一课:Quartz入门
  • (附源码)springboot车辆管理系统 毕业设计 031034
  • (附源码)springboot宠物管理系统 毕业设计 121654
  • (十五)使用Nexus创建Maven私服
  • (四)模仿学习-完成后台管理页面查询
  • (一)Dubbo快速入门、介绍、使用
  • (原創) 如何動態建立二維陣列(多維陣列)? (.NET) (C#)
  • (源码分析)springsecurity认证授权
  • (轉貼) UML中文FAQ (OO) (UML)
  • ****** 二 ******、软设笔记【数据结构】-KMP算法、树、二叉树
  • .java 9 找不到符号_java找不到符号
  • .Net 6.0 Windows平台如何判断当前电脑是否联网
  • .NET Compact Framework 多线程环境下的UI异步刷新
  • .NET Core 网络数据采集 -- 使用AngleSharp做html解析
  • .NET Core工程编译事件$(TargetDir)变量为空引发的思考
  • .net 连接达梦数据库开发环境部署
  • .net 重复调用webservice_Java RMI 远程调用详解,优劣势说明
  • .NET6 命令行启动及发布单个Exe文件
  • .NET处理HTTP请求
  • .net分布式压力测试工具(Beetle.DT)
  • .NET国产化改造探索(一)、VMware安装银河麒麟
  • .net中生成excel后调整宽度