概览
在之前 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 的外观不甚满意怎么办?别急,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 内部布局的方法,包您满意!
感谢观赏,再会!😎
- Swift 语言开发精讲
还没有评论,来说两句吧...