🔥🔥🔥 新功能 添加了 SwiftUI 支持!
SwiftMessages 是一个非常灵活的视图和视图控制器展示库,适用于 UIKit 和 SwiftUI。
消息视图和视图控制器可以显示在屏幕的顶部、底部或中央,或者在导航栏和标签栏的后面。 有交互式的关闭手势,包括一个有趣的、基于物理的手势。 有多种背景变暗模式。 还有更多功能!
除了大量的配置选项外,SwiftMessages 还提供了几种美观的布局和主题。 但 SwiftMessages 对设计师也很友好,这意味着您可以完全且轻松地自定义视图。
MessageView
并添加元素等。View
或 UIView
的任意实例。在 Xcode 中,转到 File | Swift Packages | Add Package Dependency...
并搜索 "SwiftMessages"。如果找到多个结果,请选择 SwiftKick Mobile 拥有的那个。
将以下行添加到您的 Podfile 中
pod 'SwiftMessages'
将以下行添加到您的 Cartfile 中
github "SwiftKickMobile/SwiftMessages"
如果 Carthage 构建失败,尝试使用该脚本。
SwiftMessages.xcodeproj
添加到您的项目中。SwiftMessages.show(view: myView)
虽然您可以显示 UIView
的任何实例,但 SwiftMessages 提供了一个 MessageView
类和基于 nib 的布局集合,应该可以处理大多数情况。
// Instantiate a message view from the provided card view layout. SwiftMessages searches for nib
// files in the main bundle first, so you can easily copy them into your project and make changes.
let view = MessageView.viewFromNib(layout: .cardView)
// Theme message elements with the warning style.
view.configureTheme(.warning)
// Add a drop shadow.
view.configureDropShadow()
// Set message title, body, and icon. Here, we're overriding the default warning
// image with an emoji character.
let iconText = ["🤔", "😳", "🙄", "😶"].randomElement()!
view.configureContent(title: "Warning", body: "Consider yourself warned.", iconText: iconText)
// Increase the external margin around the card. In general, the effect of this setting
// depends on how the given layout is constrained to the layout margins.
view.layoutMarginAdditions = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
// Reduce the corner radius (applicable to layouts featuring rounded corners).
(view.backgroundView as? CornerRoundingView)?.cornerRadius = 10
// Show the message.
SwiftMessages.show(view: view)
您可能希望使用视图提供程序变体 show(viewProvider:)
以确保您的 UIKit 代码在主队列上执行。
SwiftMessages.show {
let view = MessageView.viewFromNib(layout: .cardView)
// ... configure the view
return view
}
SwiftMessages.Config
结构提供了许多可以传递给 show()
的配置选项。
var config = SwiftMessages.Config()
// Slide up from the bottom.
config.presentationStyle = .bottom
// Display in a window at the specified window level.
config.presentationContext = .window(windowLevel: .statusBar)
Note that, as of iOS 13, it is no longer possible to cover the status bar
regardless of the window level. A workaround is to hide the status bar instead.
config.prefersStatusBarHidden = true
// Disable the default auto-hiding behavior.
config.duration = .forever
// Dim the background like a popover view. Hide when the background is tapped.
config.dimMode = .gray(interactive: true)
// Disable the interactive pan-to-hide gesture.
config.interactiveHide = false
// Specify haptic feedback (see also MessageView/configureTheme)
config.haptic = .success
// Specify a status bar style to if the message is displayed directly under the status bar.
config.preferredStatusBarStyle = .lightContent
// Specify one or more event listeners to respond to show and hide events.
config.eventListeners.append() { event in
if case .didHide = event {
print("yep id=\(String(describing: event.id)")
}
}
SwiftMessages.show(config: config, view: view)
指定默认配置选项
SwiftMessages.defaultConfig.presentationStyle = .bottom
// Show message with default config.
SwiftMessages.show(view: view)
// Customize config using the default as a base.
var config = SwiftMessages.defaultConfig
config.duration = .forever
SwiftMessages.show(config: config, view: view)
SwiftMessages 可以使用 SwiftMessagesSegue
自定义模态 segue 来呈现视图控制器!
SwiftMessagesSegue
是 UIStoryboardSegue
的一个子类,它作为自定义模态 segue 直接集成到 Interface Builder 中,使视图控制器能够利用 SwiftMessages 布局、动画等。 SwiftMessagesSegue
适用于任何 UIKIt 项目——不需要故事板。 有关更多信息,请参阅下面的视图控制器自述文件。
并查看我们的博客文章 优雅的自定义 UIViewController 转场,以学习一种很棒的技术,您可以使用它来构建自己的自定义 segues,这些 segues 利用 UIViewControllerTransitioningDelegate
和 UIViewControllerAnimatedTransitioning
。
可以通过从可观察对象、按钮操作闭包等中调用 SwiftMessages API 来显示任何内置的 SwiftMessages 视图。 但是,SwiftMessages 也可以显示您的自定义 SwiftUI 视图。
采用以下消息视图和配套数据模型
struct DemoMessage: Identifiable {
let title: String
let body: String
var id: String { title + body }
}
struct DemoMessageView: View {
let message: DemoMessage
var body: some View {
VStack(alignment: .leading) {
Text(message.title).font(.system(size: 20, weight: .bold))
Text(message.body)
}
.multilineTextAlignment(.leading)
.padding(30)
// This makes the message width greedy
.frame(maxWidth: .infinity)
.background(.gray)
// This makes a tab-style view where the bottom corners are rounded and
// the view's background extends to the top edge.
.mask(
UnevenRoundedRectangle(bottomLeadingRadius: 15, bottomTrailingRadius: 15)
// This causes the background to extend into the safe area to the screen edge.
.edgesIgnoringSafeArea(.top)
)
}
}
您可以从按钮操作、视图模型或其他类似上下文中显示它,如下所示
struct DemoView: View {
var body: some View {
Button("Show message") {
let message = DemoMessage(title: "Demo", body: "SwiftUI forever!")
let messageView = MessageHostingView(id: message.id, content: DemoMessageView(message: message)
SwiftMessages.show(view: messageView)
}
}
}
但是您也可以使用基于状态的方法,使用 swiftMessage()
视图修饰符
struct DemoView: View {
@State var message: DemoMessage?
var body: some View {
Button("Show message") {
message = DemoMessage(title: "Demo", body: "SwiftUI forever!")
}
.swiftMessage(message: $message) { message in
DemoMessageView(message: message)
}
}
}
这与 .sheet()
修饰符非常相似。 但是,它没有公开 SwiftMessages 的所有功能,例如通过 ID 显式隐藏消息。 使用两种方法的组合是完全合理的。
如果您的消息视图纯粹是数据驱动的,不需要委托、回调等,则 swiftMessage()
有一个稍微简化的变体,不需要视图构建器。 相反,您的数据模型应该符合 MessageViewConvertible
。
extension DemoMessage: MessageViewConvertible {
func asMessageView() -> DemoMessageView {
DemoMessageView(message: self)
}
}
然后,您可以在调用 swiftMessage()
时删除视图构建器
struct DemoView: View {
@State var message: DemoMessage?
var body: some View {
Button("Show message") {
message = DemoMessage(title: "Demo", body: "SwiftUI forever!")
}
.swiftMessage(message: $message)
}
}
在 SwiftUI 演示应用程序中尝试一下!
SwiftMessages 提供了出色的开箱即用的 VoiceOver 支持。
显示消息时,消息的标题和正文会合并为单个公告。 可以设置 MessageView.accessibilityPrefix
属性,以将其他澄清文本添加到公告中。
有时,消息可能包含重要的视觉提示,这些提示未在标题或正文中捕获。 例如,消息可能依赖于黄色背景来传达警告,而不是在标题或正文中包含“警告”一词。 在这种情况下,设置 MessageView.accessibilityPrefix = "warning"
可能会有所帮助。
如果使用 config.dimMode
显示带有昏暗视图的消息,则在隐藏消息之前,昏暗视图下方的元素不可聚焦。 如果 config.dimMode.interactive == true
,则昏暗视图本身将可聚焦并读出“dismiss”,后跟“button”。 可以通过设置 config.dimModeAccessibilityLabel
属性来定制前一个文本。
有关在自定义视图中实现适当的辅助功能支持,请参阅 AccessibleMessage
协议。
KeyboardTrackingView
类可用于使消息视图通过在键盘过于靠近时向上滑动来避开键盘。
var config = SwiftMessages.defaultConfig
config.keyboardTrackingView = KeyboardTrackingView()
即使您未使用 SwiftMessages,也可以将 KeyboardTrackingView
合并到您的应用程序中。 通过将 KeyboardTrackingView
固定到屏幕的底部、前导和尾随边缘,将其安装到您的视图层次结构中。 然后将应避开键盘的内容的底部固定到 KeyboardTrackingView
的顶部。 使用等式约束严格跟踪键盘,或使用不等式约束仅在键盘过于靠近时才移动。 KeyboardTrackingView
通过观察键盘通知并调整其高度以使其顶部边缘保持在键盘上方来工作,从而向上推动您的内容。 有关配置选项,请参阅 KeyboardTrackingView
中的注释。
您可以根据需要多次调用 SwiftMessages.show()
。 SwiftMessages 维护一个队列并一次显示一条消息。 如果您的视图实现了 Identifiable
协议(例如 MessageView
),则会自动删除重复的消息。 可以调整消息之间的暂停
SwiftMessages.pauseBetweenMessages = 1.0
有几种以编程方式隐藏消息的方法
// Hide the current message.
SwiftMessages.hide()
// Or hide the current message and clear the queue.
SwiftMessages.hideAll()
// Or for a view that implements `Identifiable`:
SwiftMessages.hide(id: someId)
// Or hide when the number of calls to show() and hideCounted(id:) for a
// given message ID are equal. This can be useful for messages that may be
// shown from multiple code paths to ensure that all paths are ready to hide.
SwiftMessages.hideCounted(id: someId)
可以使用 SwiftMessages
的多个实例来一次显示多条消息。 请注意,静态 SwiftMessages.show()
和 SwiftMessage
上的其他静态 API 只是共享实例 SwiftMessages.sharedInstance
的便捷包装器)。 实例必须保留,因此它应该是某些东西(例如您的视图控制器)的属性
class SomeViewController: UIViewController {
let otherMessages = SwiftMessages()
func someMethod() {
SwiftMessages.show(...)
otherMessages.show(...)
}
}
有几个 API 可用于检索当前正在显示、隐藏或排队等待显示的消息。 这些 API 对于在发生某些事件时更新消息非常有用,而无需保留临时引用。 另请参阅 eventListeners
。
// Get a message view with the given ID if it is currently
// being shown or hidden.
if let view = SwiftMessages.current(id: "some id") { ... }
// Get a message view with the given ID if is it currently
// queued to be shown.
if let view = SwiftMessages.queued(id: "some id") { ... }
// Get a message view with the given ID if it is currently being
// shown, hidden or in the queue to be shown.
if let view = SwiftMessages.currentOrQueued(id: "some id") { ... }
SwiftMessages 可以显示任何 UIView
。 但是,可以对捆绑的视图进行不同程度的自定义。
与 SwiftMessages 捆绑在一起的所有消息设计都有关联的 nib 文件。 鼓励您将这些 nib 文件中的任何一个复制到您的项目中并根据您的需要进行修改。 SwiftMessages 将加载您的文件副本,而不是原始文件。 可以使用拖放操作在 Xcode 中复制 Nib 文件。
为了方便使用基于 nib 的布局,MessageView
提供了一些类型安全的便捷方法来加载捆绑的 nib
let view = MessageView.viewFromNib(layout: .cardView)
此外,SwiftMessages
类提供了一些通用加载方法
// Instantiate MessageView from a named nib.
let view: MessageView = try! SwiftMessages.viewFromNib(named: "MyCustomNib")
// Instantiate MyCustomView from a nib named MyCustomView.nib.
let view: MyCustomView = try! SwiftMessages.viewFromNib()
MessageView
是所有捆绑设计使用的轻量级视图。 它主要由以下可选的 @IBOutlet
属性组成
元素 | 声明 | 描述 |
---|---|---|
标题 | titleLabel: UILabel? |
消息标题。 |
消息正文 | bodyLabel: UILabel? |
消息的正文。 |
图像图标 | iconImageView: UIImageView? |
基于图像的图标。 |
文本图标 | iconLabel: UILabel? |
图像图标的基于文本(表情符号)的替代方案。 |
按钮 | button: UIButton? |
操作按钮。 |
SwiftMessages nib 文件使用 MessageView
作为顶级视图,其内容连接到这些出口。 布局是使用堆栈视图完成的,这意味着您可以通过简单地隐藏元素来删除元素
view.titleLabel.isHidden = true
一个常见的错误是尝试通过将相应的出口设置为 nil
来删除元素。 这不起作用,因为它不会从视图层次结构中删除元素。
MessageView
提供了许多遵循 configure*
命名约定的方法
view.configureTheme(.warning, includeHaptic: true)
view.configureContent(title: "Warning", body: "Consider yourself warned.", iconText: "🤔")
所有这些方法都是快速配置底层视图属性的快捷方式。 SwiftMessages 努力避免在这些方法中进行任何内部魔法,因此您无需调用它们。 您可以直接配置视图属性或结合使用这两种方法。
MessageView
为按钮提供了一个可选的基于块的点击处理程序,另一个用于视图本身
// Hide when button tapped
messageView.buttonTapHandler = { _ in SwiftMessages.hide() }
// Hide when message view tapped
messageView.tapHandler = { _ in SwiftMessages.hide() }
从 MessageView
作为基础并添加新元素(例如其他按钮)的建议方法如下
MessageView
并为新元素创建出口。Identifiable
的实现,以将新元素合并到消息的标识中。AccessibleMessage
的实现,以将新元素合并到 Voice Over 中。BaseView
是 MessageView
的超类,并提供了许多不特定于 MessageView
的“标题 + 正文 + 图标 + 按钮”设计的选项。 与 MessageView
显着不同的自定义视图(例如进度指示器)应子类化 BaseView
。
CornerRoundingView
是一个自定义视图,消息可以使用它来对全部或部分角进行圆角处理,使用 squircles (在应用图标上看到的更平滑的圆角方法)。具有圆角的 nib 文件将 backgroundView
赋值给 CornerRoundingView
。它提供了一个 roundsLeadingCorners
选项,用于在从顶部或底部呈现时动态地仅对视图的前导角进行圆角处理(用于标签样式布局的功能)。
Animator
是 SwiftMessages 用于呈现和消失动画的协议。自定义动画可以通过 SwiftMessages.PresentationStyle.custom(animator:)
完成。一些相关组件:
TopBottomAnimation
是 Animator
的一个滑动实现,由 .top
和 .bottom
呈现样式在内部使用。它提供了一些自定义选项。PhysicsAnimation
是 Animator
的一个缩放 + 透明度实现,由 .center
呈现样式在内部使用。它提供了一个有趣的基于物理的消失手势,并提供自定义选项,包括 .top
和 .bottom
位置。PhysicsPanHandler
为 PhysicsAnimation
提供了基于物理的消失手势,并且可以合并到其他 Animator
实现中。欢迎提供高质量的 PR,来实现酷炫的 Animator
!
MarginAdjustable
是 BaseView
采用的协议。如果被呈现的视图采用 MarginAdjustable
,SwiftMessages 将拥有该视图的布局边距,以确保在整个呈现上下文中具有理想的间距。
BackgroundViewable
是 BaseView
采用的协议,它要求视图提供一个 backgroundView
属性。 BaseView
初始化 backgroundView = self
,您可以自由地将其重新分配给任何子视图。
如果被呈现的视图采用 BackgroundViewable
,SwiftMessages 将忽略 backgroundView
外部的触摸。这很重要,因为消息视图始终跨越设备的整个宽度。卡片和标签样式布局看起来是从设备的边缘插入的,因为消息视图的背景是透明的,并且 backgroundView
被分配给约束到布局边距的子视图。在这些布局中,应忽略透明边距中的触摸。
Identifiable
是 MessageView
采用的协议,它要求视图提供一个 id
属性,SwiftMessages 使用该属性进行消息去重。
MessageView
基于消息内容计算 id
,但也可以根据需要显式设置 id
。
AccessibleMessage
是 MessageView
采用的协议。如果被呈现的视图采用 AccessibleMessage
,SwiftMessages 将提供改进的 Voice Over。
我们构建高质量的应用程序!如果您在项目中需要帮助,请联系我们。
SwiftMessages 在 MIT 许可下分发。有关详细信息,请参阅 LICENSE。