LNPopupUI
是一个 SwiftUI 库,用于将视图呈现为弹出窗口,类似于 Apple Music 和 Podcasts 应用。
这是一个 LNPopupController 框架的 SwiftUI 封装,经过调整以与 SwiftUI 配合使用。
一旦使用内容视图呈现弹出栏,用户可以随时滑动或点击弹出栏以呈现内容视图。 完成后,用户可以通过滑动内容视图或点击弹出窗口关闭按钮来关闭弹出窗口。
该库使用新的功能扩展了 SwiftUI 的 View
,用于呈现和自定义带有内容视图的弹出窗口,以及设置诸如弹出栏的标题、图像和栏按钮项等信息。 呈现弹出栏时,弹出栏会自动适应呈现它的视图,以获得最佳外观。
通常,建议在最外层的视图(例如 TabView
或 NavigationStack
)上呈现弹出栏。 例如,如果您有一个包含在导航堆栈中的视图,而该视图又包含在标签视图中,则建议在标签视图上呈现弹出栏。
查看演示项目,快速重现 Apple 的音乐应用。
LNPopupUI
支持 SPM 版本 5.5 (Xcode 13) 及更高版本。 在 Xcode 中,点击 File
-> Swift Packages
-> Add Package Dependency
,输入 https://github.com/LeoNatan/LNPopupUI
。 选择您要使用的版本。
您也可以手动将包添加到您的 Package.swift 文件中
.package(url: "https://github.com/LeoNatan/LNPopupUI.git", from: "1.5.0")
以及您的目标中的依赖项
.target(name: "BestExampleApp", dependencies: ["LNPopupUI"]),
在您的项目中导入模块
import LNPopupUI
弹出窗口由弹出栏和弹出内容视图组成。 弹出栏的信息(例如标题、图像和栏按钮项)使用提供的修饰符 API 进行配置。
要呈现弹出栏,请使用 popup(isBarPresented:isPopupOpen:content:)
修饰符。 然后,用户可以与弹出栏和弹出内容进行交互。
要以编程方式呈现和关闭弹出栏,请切换 isPopupBarPresented
绑定变量。 要以编程方式打开或关闭弹出窗口,请切换 isPopupOpen
绑定变量。
有关更多信息,请参阅 LNPopupUI.swift 中的文档。
TabView {
//Container content
AlbumViews()
}
.popup(isBarPresented: $isPopupBarPresented, isPopupOpen: $isPopupOpen) {
//Popup content, visible when the popup opens
PlayerView(song: currentSong)
.popupTitle(currentSong.title)
.popupSubtitle(currentSong.subtitle)
.popupImage(Image(currentSong.imageName))
.popupBarItems {
ToolbarItemGroup(placement: .popupBar) {
Button {
isPlaying.toggle()
} label: {
Image(systemName: "play.fill")
}
Button {
nextSong()
} label: {
Image(systemName: "forward.fill")
}
}
}
}
LNPopupUI
提供了三种不同的弹出窗口外观和感觉风格,每种风格都基于 Apple 多年来推出的 Music 应用的外观和感觉。 弹出栏样式标记为“floating”(浮动)、“prominent”(突出)和“compact”(紧凑),与相应的 Apple 风格匹配。 弹出窗口交互样式标记为“snap”(吸附)表示现代风格的吸附弹出窗口,以及“drag”(拖动)表示 iOS 9 交互式弹出窗口交互。 弹出窗口关闭按钮样式标记为“chevron”(雪佛龙)表示现代风格的雪佛龙关闭按钮,以及“round”(圆形)表示 iOS 9 风格的关闭按钮。 对于每种样式,都有一个“default”(默认)样式,用于为当前平台和操作系统版本选择最合适的样式。
默认值是
iOS 17
浮动栏样式
吸附交互样式
雪佛龙关闭按钮样式
无进度视图样式
iOS 16 及以下版本
吸附交互样式
雪佛龙关闭按钮样式
无进度视图样式
您还可以呈现完全自定义的弹出栏。 有关更多信息,请参阅 自定义弹出栏视图。
默认情况下,对于导航视图和标签视图,弹出栏的外观根据容器的底部栏的外观确定。 对于其他容器视图,使用最适合当前环境的默认外观。
要禁用继承底部栏的外观,请使用 false
调用 popupBarInheritsAppearanceFromDockingView()
修饰符。
通过调用 .popupBarStyle()
修饰符来实现自定义弹出栏样式。
.popup(isBarPresented: $isPopupPresented, isPopupOpen: $isPopupOpen) {
//Popup content view
}
.popupBarStyle(.floating)
通过调用 .popupInteractionStyle()
修饰符来实现自定义弹出窗口交互样式。
.popup(isBarPresented: $isPopupPresented, isPopupOpen: $isPopupOpen) {
//Popup content view
}
.popupInteractionStyle(.drag)
通过调用 .popupBarProgressViewStyle()
修饰符来实现自定义弹出栏进度视图样式。
.popup(isBarPresented: $isPopupPresented, isPopupOpen: $isPopupOpen) {
//Popup content view
}
.popupBarProgressViewStyle(.top)
要隐藏进度视图,请将栏进度视图样式设置为 .none
。
通过调用 .popupCloseButtonStyle()
修饰符来实现自定义弹出窗口关闭按钮样式。
.popup(isBarPresented: $isPopupPresented, isPopupOpen: $isPopupOpen) {
//Popup content view
}
.popupCloseButtonStyle(.round)
要隐藏弹出窗口关闭按钮,请将 popupCloseButtonStyle
设置为 .none
。
LNPopupUI
公开了许多 API 来自定义默认弹出栏的外观。
.popup(isBarPresented: $isPopupPresented, isPopupOpen: $isPopupOpen) {
//Popup content view
}
.popupBarInheritsAppearanceFromDockingView(false)
.popupBarTitleTextAttributes(AttributeContainer()
.font(Font.custom("Chalkduster", size: 14, relativeTo: .headline))
.foregroundColor(.yellow)
.paragraphStyle(customizationParagraphStyle))
.popupBarSubtitleTextAttributes(AttributeContainer()
.font(.custom("Chalkduster", size: 12, relativeTo: .subheadline))
.foregroundColor(.green)
.paragraphStyle(customizationParagraphStyle))
.popupBarFloatingBackgroundShadow(color: .red, radius: 8)
.popupBarImageShadow(color: .yellow, radius: 5)
.popupBarFloatingBackgroundEffect(UIBlurEffect(style: .dark))
.popupBarBackgroundEffect(UIBlurEffect(style: .dark))
如果启用了文本跑马灯滚动,为标题和/或副标题提供长文本将导致文本滚动。 否则,文本将被截断。 要启用文本跑马灯滚动,请使用 popupBarMarqueeScrollEnabled()
修饰符。
您可以通过调用 .popupBarContextMenu()
修饰符向您的弹出栏添加上下文菜单。
.popup(isBarPresented: $isPopupPresented, isPopupOpen: $isPopupOpen) {
//Popup content view
}
.popupBarContextMenu {
Button {
print("Context Menu Item 1")
} label: {
Text("Context Menu Item 1")
Image(systemName: "globe")
}
Button {
print("Context Menu Item 2")
} label: {
Text("Context Menu Item 2")
Image(systemName: "location.circle")
}
}
LNPopupUI
完全支持 iPhone 和 iPad 上的 ProMotion。
对于 iPhone 13 Pro 及更高版本,您需要将 CADisableMinimumFrameDurationOnPhone
键添加到您的 Info.plist 并将其设置为 true
。 有关更多信息,请参阅 优化 iPhone 13 Pro 和 iPad Pro 的 ProMotion 刷新率。 如果缺少此键或设置为 false
,LNPopupUI
将在控制台中记录一条警告消息。
该库完全支持从右到左的布局。
您可以使用 .popupBarCustomView()
修饰符,显示您自己的视图作为弹出栏,而不是系统提供的视图。
.popup(isBarPresented: $isPopupPresented, isPopupOpen: $isPopupOpen) {
//Popup content view
}
.popupBarCustomView(wantsDefaultTapGesture: false, wantsDefaultPanGesture: false, wantsDefaultHighlightGesture: false) {
//Custom popup bar view content
}
wantsDefaultTapGesture
、wantsDefaultPanGesture
和 wantsDefaultHighlightGesture
参数控制是否应启用或禁用弹出栏的默认系统手势。
提示
只有当您需要的 标准弹出栏样式的设计有很大不同时,才实现自定义弹出栏。 在将这些弹出栏样式与 SwiftUI 视图系统集成方面已经投入了大量的精力和工作,包括外观、感觉、过渡和交互。 自定义栏为您提供了一个空白画布来实现您自己的栏视图,但是如果您最终重新创建了一个类似于标准栏设计的栏设计,那么您很可能会丢失在标准实现中多年来添加和完善的细微之处。 考虑使用许多自定义 API来调整标准栏样式以适应您应用的设计。
包含的演示项目包含一个自定义弹出栏场景示例。
LNPopupUI
公开了 .popupBarCustomizer()
修饰符,允许通过 UIKit LNPopupBar
对象进行更低级别的自定义。
.popup(isBarPresented: $isPopupPresented, isPopupOpen: $isPopupOpen) {
//Popup content view
}
.popupBarCustomizer { popupBar in
popupBar.popupOpenGestureRecognizer.delegate = self.gestureRecognizerDelegateHelper
popupBar.barHighlightGestureRecognizer.isEnabled = false
}
提示
.popupBarCustomizer()
修饰符公开了来自 LNPopupController
框架的底层 LNPopupBar
。 此框架允许修改 SwiftUI 中未原生公开的属性,例如直接手势识别器控制。 虽然可以使用此修饰符自定义栏的外观,但此 API 仅接受 UIKit 数据类型,例如 UIColor
和 UIFont
。 相反,请使用支持 SwiftUI 原生数据类型(例如 Color
和 Font
)的 SwiftUI 原生自定义 API,并且与 SwiftUI 视图模型的其余部分更好地集成。
除了主要的 SwiftUI 功能外,该库还为 LNPopupController
提供了扩展,用于将 SwiftUI 视图托管为弹出内容和自定义弹出栏内容。
使用 LNPopupContentHostingController
创建弹出内容托管控制器
let controller = LNPopupContentHostingController {
PlayerView(song: currentSong)
.popupTitle(currentSong.name, subtitle: currentSong.album.name)
.popupImage(currentSong.artwork ?? currentSong.album.artwork)
}
tabBarController?.presentPopupBar(with: controller, animated: true)
或直接使用 UIViewController.presentPopupBar(with:animated:)
tabBarController?.presentPopupBar(with: {
PlayerView(song: currentSong)
.popupTitle(currentSong.name, subtitle: currentSong.album.name)
.popupImage(currentSong.artwork ?? currentSong.album.artwork)
}, animated: true)
使用 LNPopupCustomBarHostingController
创建自定义弹出栏托管控制器
tabBarController?.popupBar.customBarViewController = LNPopupCustomBarHostingController {
MyCustomPlaybackControlsView()
}
该库使用
此外,演示项目使用