概览
在之前 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 的外观不甚满意怎么办?别急,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 内部布局的方法,包您满意!
感谢观赏,再会!😎