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!!!😉


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 = false
    
    var 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 in
                    Button {
                        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 = false
    
    var 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 内部布局的方法,包您满意!

感谢观赏,再会!😎

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

灯塔工厂产业数字化平台解决方案(50页PPT)

方案介绍: 随着工业4.0和智能制造的快速发展,传统工厂正面临着转型升级的迫切需求。为了提升生产效率、优化资源配置、增强市场竞争力,我们推出了灯塔工厂产业数字化平台解决方案。该方案旨在通过先进的信息技术手段,将传统工厂转…

springboot发送短信验证码,结合redis 实现限制,验证码有效期2分钟,有效期内禁止再次发送,一天内发送超3次限制

springboot结合redis发送短信验证码,实现限制发送操作 前言(可忽略)实现思路正题效果图示例手机号不符合规则校验图成功发送验证码示例图redis中缓存随机数字验证码,2分钟后失效删除redis缓存图验证码有效期内 返回禁止重复发送图验证码24小时内发送达到3次&#xf…

Https自签名证书

openSSL下载 https://slproweb.com/products/Win32OpenSSL.html 1_整体流程 (1)https介绍 HTTPS 是 Hypertext Transfer Protocol Secure 的简称,是基于 SSL 加密方式的 HTTP 协议 (2)CA机构介绍 介绍&#xff1a…

2024年,游戏行业还值得进入吗?

来自知乎问题“2024年,游戏行业还值得进入吗?”的回答。 ——原问题描述:从超小厂执行策划做起,未来有前途吗? 展望2024年,国内外的游戏市场环境或将变得更加复杂,曾经那个水大鱼大的时代过去了…

考试宝典——软件过程与管理重点知识总结

概论 软件工程三要素 过程方法工具 软件过程的定义 软件过程是用于软件开发及维护的一系列活动、方法及实践。 常见软件过程分类(五大类) 客户-供应商过程:内部直接影响到客户、外部直接影响开发、向客户交付软件以及软件正确操作与使用的过…

路由器交换机直连方案(RM50+RTL8367N)

不经过网口和变压器,实现板级网口扩展。 通过网口,网线连接 板级芯片直接连接,验证OK 激光导航控制板通过路由器上网成功

二叉搜索树BST ——(C++)

本篇将会讲解有关二叉树的搜索原理,以及关于二叉搜索树的建立,以及二叉树搜索树的插入、删除和查找等基本操作。最后我们还会对二叉搜索树进行功能扩展,介绍有关搜索二叉树的 K 模型和 KV 模型。目录如下: 目录 1. 搜索二叉树 二叉…

PageHelper分页查询时,count()查询记录总数与实际返回的数据数量不一致

目录 场景简介代码判断异常情况排查原因解决 场景简介 1、使用PageHelper进行分页查询 2、最终构建PageInfo对象时,total与实际数据量不符 代码判断 异常情况 排查 通过对比count()查询的SQL与查询记录的SQL,发现是PageHelper分页查询时省去了order b…

香橙派 AIpro开发板:开启AI视觉的无限可能

前言 在当今这个由数据和智能驱动的时代, 人工智能(AI) 已经成为推动技术创新和实现自动化的关键。 特别是在计算机视觉领域,AI的潜能被无限放大,它使得机器能够“看见”并理解视觉世界,从而执行复杂的任务…

安捷伦Agilent 8114A脉冲发生器的特点资料

Agilent 8114A 脉冲发生器有助于测试当今的电信和计算机系统组件,这些组件越来越多地利用在高电压或大电流下运行的激光和红外二极管、EEPROMS 和闪存等设备。 Agilent 8114A 高功率脉冲发生器的特点包括: 频率高达 15 MHz 时,高达 100 V 的…

前端 CSS 经典:图片边框

前言&#xff1a;有这么一个业务&#xff0c;需要边框随着图片宽度的变化而变化&#xff0c;比如一些聊天的气泡框等。 实现原理&#xff1a;使用 border-image 属性 效果图&#xff1a; 实现代码&#xff1a; <!DOCTYPE html> <html lang"en"><he…

Qt/C++音视频开发75-获取本地有哪些摄像头名称/Qt内置函数方式

一、前言 在需要打开本地摄像头的场景中&#xff0c;有个需求绕不开&#xff0c;那就是如何获取本地有哪些摄像头设备名称&#xff0c;这样可以提供下拉框给用户选择&#xff0c;不然你让用户去填设备名&#xff0c;你觉得用户会知道是啥&#xff0c;他会操作吗&#xff1f;就…

[猫头虎分享21天微信小程序基础入门教程] 第17天:小程序的用户授权与安全

[猫头虎分享21天微信小程序基础入门教程] 第17天&#xff1a;小程序的用户授权与安全 第17天&#xff1a;小程序的用户授权与安全 &#x1f512; 自我介绍 大家好&#xff0c;我是猫头虎&#xff0c;一名全栈软件工程师。今天我们继续微信小程序的学习&#xff0c;重点了解如…

【C++】Vector的简易模拟与探索

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#x…

【C++初阶】auto关键字

目录 1.auto简介 2.auto的使用 1.auto简介 在早期C/C中auto的含义是&#xff1a;使用auto修饰的变量&#xff0c;是具有自动存储器的局部变量&#xff0c;但遗憾的 是一直没有人去使用它&#xff0c;大家可思考下为什么&#xff1f; C11中&#xff0c;标准委员会赋予了auto全…

Go语言

Go语言 Go语言全称Golanguage&#xff0c;Go&#xff08;又称 Golang&#xff09;是 Google 的 Robert Griesemer&#xff0c;Rob Pike 及 Ken Thompson 开发的一种静态强类型、编译并发型语言。于2009年首次发布 官网 特点 简单易学&#xff1a;Go语言语法简洁明了&#x…

【AD21】原理图PDF文件的输出

原理图PDF文件可以共享给团队成员&#xff0c;用于设计审核、讨论和协同工作。 菜单栏中点击文件->智能PDF。 在弹出的界面点击Next&#xff0c;勾选当前项目&#xff0c;修改文件名&#xff0c;避免与制造装备图PDF文件重名将其覆盖&#xff0c;点击Next。 只输出原理图…

SmartEDA革新电路设计,效率飙升,Multisim与Proteus迎来强劲对手!

在电路设计领域&#xff0c;Multisim和Proteus一直以其强大的仿真功能和广泛的应用范围受到设计师们的青睐。然而&#xff0c;随着科技的不断进步和创新&#xff0c;一款名为SmartEDA的新兴软件正以其独特的优势&#xff0c;重新定义着电路设计的效率。 SmartEDA的崛起&#x…

基于Ubuntu的Bash脚本实现SystemUI的编译真机验证

使用场景描述 当开发SystemUI的时候&#xff0c;开发完一个需求后需要到真机上验证&#xff0c;虽然SystemUI模块开发最后的产物也是APK&#xff0c;但是这个APK 却不能单独安装查看效果&#xff0c;因为SystemUI是系统级别的应用&#xff0c;需要放置到系统指定的目录下。这时…

这13个前端库,帮我在工作中赢得了不少摸鱼时间

前言 平时开发的过程中&#xff0c;常常会使用到一些第三方库来提高开发效率&#xff0c;我总结了自己工作这么久以来经常用到的 13 个库&#xff0c;希望对大家有帮助&#xff5e; antd 全称应该是Ant Design&#xff0c;这是一个 React 的组件库&#xff0c;旨在提供一套常…