LNPopupController 2.10.29

LNPopupController 2.10.29

Jonathan OrthedenBazhen Rzheutskiy 维护。




  • 作者
  • Leo Natan

LNPopupController

LNPopupController 是一个框架,可以将视图控制器作为其他视图控制器的弹出窗口呈现,类似于 Apple Music 和 Podcasts 应用。

对于 SwiftUI,请查看我的 LNPopupUI 库

GitHub release GitHub stars GitHub license PayPal Donation Button

GitHub issues GitHub contributors Carthage compatible

在此处查看现代化弹出窗口的外观和感觉的视频 这里 以及经典弹出窗口的外观和感觉视频 这里

一旦使用内容视图控制器呈现了弹出条,用户可以在弹出窗口的任何地方滑动或点击以呈现内容控制器。完成后,用户可以通过滑动或点击弹出窗口的关闭按钮来关闭弹出窗口。

该框架旨在非常通用并在大多数情况下工作,因此它作为 UIViewController 的类别实现。每个视图控制器都可以在底部视图中呈现弹出条。对于 UITabBarController 子类,默认停靠视图是标签栏。对于 UINavigationController 子类,默认停靠视图是工具栏。对于其他类,弹出条在屏幕底部呈现。视图控制器子类可以提供自己的停靠视图。

在弹出窗口呈现和关闭时,框架正确维护容器控制器的视图及其子控制器的安全区域插图和指南。

弹出窗口的内容是使用与弹出内容视图控制器关联的弹出项目对象(LNPopupItem 类的实例)动态构建的。因此,要更改弹出窗口的内容,您必须因此配置视图控制器的弹出项目。

通常,建议在最外层容器控制器上呈现弹出窗口。因此,如果您有一个包含在导航控制器中的视图控制器,该导航控制器又包含在标签栏控制器中,建议在标签栏控制器上呈现弹出窗口。

请查看示例项目,以获取在各种场景中框架的许多常见用例。它包含 Swift 和 Objective-C 中的示例。

特性

  • 支持 iOS 11 及更高版本,可作为 Xcode 框架或 SPM 包使用
  • 是现代 UIKit 世界中的良好市民
  • 现代 Objective-C 语法和出色的 Swift 互操作性
  • 对于 SwiftUI,请查看我的 LNPopupUI 库

添加到项目中

Swift 包管理器

LNPopupController 支持版本 5.1.0 及以上 SPM。要使用 SPM,您应该使用 Xcode 11 打开项目。点击 文件 -> Swift 包 -> 添加包依赖,输入 https://github.com/LeoNatan/LNPopupController。选择您希望使用的版本。

您也可以手动将包添加到您的 Package.swift 文件中

.package(url: "https://github.com/LeoNatan/LNPopupController.git", from: "2.9.2")

以及目标中的依赖项

.target(name: "BestExampleApp", dependencies: ["LNPopupController"]),

Carthage

将以下内容添加到您的 Cartfile 中

github "LeoNatan/LNPopupController"

请确保您遵循 Carthage 集成说明 在这里

手动

LNPopupController.xcodeproj 项目拖放到您的项目中,并将 LNPopupController.framework 添加到项目目标 通用 选项卡中的 嵌入的二进制文件。Xcode 应该会自行整理其余内容。

CocoaPods

CocoaPods 不受支持。这有几个原因。不要使用 CocoaPods,而是使用 Carthage。您可以为其他依赖项继续使用 CocoaPods,而为 LNPopupController 使用 Carthage。

使用框架

Swift

尽管该框架是用 Objective C 编写的,但它使用现代 Objective C 语法,因此使用 Swift 中的框架应该是非常简单直观的。

项目集成

在您的项目中导入模块

import LNPopupController

弹出项

弹出项应始终反映与相关联的视图控制器中的弹出信息。弹出项应提供要显示在弹出条中的标题和副标题,当视图控制器作为弹出内容控制器呈现时。此外,项目还可能包含额外的按钮,用于在弹出条的leading和/或trailing边缘显示,可以使用 `leadingBarButtonItems` 和 `trailingBarButtonItems` 实现。

管理弹出条

要显示弹出条,创建内容控制器、更新其弹出项并显示弹出条。

let demoVC = DemoPopupContentViewController()
demoVC.view.backgroundColor = .red
demoVC.popupItem.title = "Hello World"
demoVC.popupItem.subtitle = "And a subtitle!"
demoVC.popupItem.progress = 0.34
	
tabBarController?.presentPopupBar(withContentViewController: demoVC, animated: true, completion: nil)

当弹出条正在显示并且弹出本身打开时,可以呈现新的内容控制器。

要程序化地打开和关闭弹出,分别使用 openPopup(animated:completion:)closePopup(animated:completion:)

tabBarController?.openPopup(animated: true, completion: nil)

或者,可以使用 presentPopupBar(withContentViewController:openPopup:animated:completion:) 在一个动画中展示弹出条并打开弹出。

tabBarController?.presentPopupBar(withContentViewController: demoVC, openPopup:true, animated: true, completion: nil)

要消失弹出条,使用 dismissPopupBarAnimated:completion:

tabBarController?.dismissPopupBar(animated: true, completion: nil)

如果在消失弹出条时弹出是打开的,弹出内容也会消失。

弹出视图控制器容器

任何 UIViewController 子类都可以是弹出视图控制器容器。弹出条连接到底部锚定视图。默认情况下,UITabBarControllerUINavigationController 的子类返回它们的底部 条作为锚定视图;而其他控制器将在视图底部返回一个高度为 0pt 的隐藏视图。在你的子类中,覆盖 bottomDockingViewForPopupBardefaultFrameForBottomDockingView 并相应地返回你的视图和框架。 返回的视图必须连接到视图控制器的底部视图,否则结果是不确定的。

override var bottomDockingViewForPopupBar: UIView? {
  return myCoolBottomView
}

override var defaultFrameForBottomDockingView: CGRect {
  var bottomViewFrame = myCoolBottomView.frame
  
  if isMyCoolBottomViewHidden {
    bottomViewFrame.origin = CGPoint(x: bottomViewFrame.x, y: view.bounds.height)
  } else {
    bottomViewFrame.origin = CGPoint(x: bottomViewFrame.x, y: view.bounds.height - bottomViewFrame.height)
  }
  
  return bottomViewFrame
}

外观和行为

现代外观和感觉

LNPopupController 提供两种不同的弹出窗口样式和外观,一种是基于现代音乐应用程序的样式和外观,另一种是之前基于 iOS 9 样式和外观的。弹出栏样式被任意标记为“显眼”以用于现代样式弹出栏,而“紧凑”用于 iOS 9 样式。弹出交互样式被标记为“快速”以用于现代样式的快速弹出,而“拖动”用于 iOS 9 的互动弹出交互。弹出关闭按钮的样式被标记为“箭头”以用于现代样式的箭头关闭按钮,而“圆形”用于 iOS 9 样式关闭按钮。对于每种样式,都有一个“默认”样式,用于选择当前操作系统版本最合适的样式。

默认设置包括

  • 显眼的栏样式
  • 快速交互样式
  • 箭头关闭按钮样式
  • 无进度视图样式
栏样式

通过设置弹出栏的 barStyle 属性来实现自定义弹出栏样式。

navigationController?.popupBar.barStyle = .compact
交互样式

通过设置包含控制器的弹出表示的 popupInteractionStyle 属性来实现自定义弹出交互样式。

navigationController?.popupInteractionStyle = .drag
进度视图样式

通过设置弹出栏的 progressViewStyle 属性来实现自定义弹出栏进度视图样式。

navigationController?.popupBar.progressViewStyle = .top

要隐藏进度视图,将 progressViewStyle 属性设置为 LNPopupBarProgressViewStyle.none

关闭按钮样式

通过设置弹出内容视图的 popupCloseButtonStyle 属性来实现自定义弹出关闭按钮样式。

navigationController.popupContentView.popupCloseButtonStyle = .round

要隐藏弹出关闭按钮,将 popupCloseButtonStyle 属性设置为 LNPopupCloseButtonStyle.none

弹出栏外观

对于导航和标签栏控制器弹出容器,弹出栏的样式根据底部栏的外观确定。对于其他容器控制器,样式是默认样式。对于每种样式,标题和按钮颜色将相应调整。

在更新容器控制器底部栏外观后,要更新弹出栏外观,请调用 updatePopupBarAppearance() 方法。

为标题和/或副标题提供长文本会导致文本滚动。否则,文本将居中。

所有控制器均支持 hidesBottomBarWhenPushed 属性。当设置时,弹出栏将过渡到容器控制器视图的底部。设置 isToolbarHidden = true 并调用 setToolbarHidden(_:animated:) 也是支持的。

尊重并适用时应用弹出内容视图控制器的状态栏管理。

交互手势识别器

LNPopupContentViewpopupInteractionGestureRecognizer 属性的方式公开了弹出交互手势识别器的访问。这个手势识别器在打开弹出内容、通过向上滑动弹出栏(当弹出栏关闭时)和关闭弹出内容、通过滑动弹出内容视图(当弹出栏打开时)时是共享的。

当打开弹出时,系统会查询弹出内容视图控制器的 viewForPopupInteractionGestureRecognizer 属性以确定要将交互手势识别器添加到哪个视图。默认情况下,该属性返回控制器的根视图。可以覆盖属性的getter以更改此行为。

可以实现交互手势识别器的代理,以影响其行为,例如在用户与弹出内容内部的控件或视图交互时阻止弹出交互。

注意:如果在弹出后禁用手势识别器,必须监控弹出状态,并在用户通过代码关闭时重新启用手势识别器。相反,可以考虑实现手势识别器的代理并提供禁用交互的自定义逻辑。

全面支持从右到左

该框架全面支持从右到左。

默认情况下,弹出条将遵循系统的用户界面布局方向,但会保留条按钮项的顺序。要自定义此行为,请修改弹出条的semanticContentAttributebarItemsSemanticContentAttribute属性。

自定义

可以通过LNPopupBarLNPopupContentViewLNPopupCustomBarViewController类来实现自定义。

弹出条自定义

LNPopupBar提供了API来自定义默认弹出条的外观,无论是通过UIAppearance API还是直接在弹出条对象上。

let appearanceProxy = LNPopupBar.appearance(whenContainedInInstancesOf: [UINavigationController.self])
appearanceProxy.titleTextAttributes = [.font: UIFont(name: "Chalkduster", size: 14)!, .foregroundColor: UIColor.yellow]
appearanceProxy.subtitleTextAttributes = [.font: UIFont(name: "Chalkduster", size: 12)!, .foregroundColor: UIColor.green]
appearanceProxy.backgroundStyle = .systemChromeMaterialDark
appearanceProxy.tintColor = .yellow

自定义弹出条

框架支持实现自定义弹出条。

要实现自定义弹出条,继承LNPopupCustomBarViewController

在你的LNPopupCustomBarViewController子类中,构建弹出条视图层次结构,并使用预期的弹出条高度设置控制器的preferredContentSize属性。重写wantsDefaultTapGestureRecognizer和/或wantsDefaultPanGestureRecognizer属性以禁用添加默认手势识别器。

在你的子类中,实现popupItemDidUpdate方法以接收弹出内容视图控制器的项目更新通知,或当显示新的弹出内容视图控制器(带有新的弹出条项)时。你必须调用此方法的super实现。

最后,将弹出条对象的customBarViewController属性设置为你的LNPopupCustomBarViewController子类实例。这将更改条样式为LNPopupBarStyle.custom

包含的示例项目包含自定义弹出条场景的示例。

无障碍访问

框架支持无障碍访问,并会尊重无障碍标签、提示和值。默认情况下,弹出条的无障碍标签是弹出条项提供的标题和副标题。

要修改弹出条的无障碍标签和提示,请设置弹出内容视图控制器中LNPopupItem对象的accessibilityLabelaccessibilityHint属性。

demoVC.popupItem.accessibilityLabel = NSLocalizedString("Custom popup bar accessibility label", comment: "")
demoVC.popupItem.accessibilityHint = NSLocalizedString("Custom popup bar accessibility hint", comment: "")

为了给按钮添加无障碍标签和提示,请设置 UIBarButtonItem 对象的 accessibilityLabelaccessibilityHint 属性。

let upNext = UIBarButtonItem(image: UIImage(named: "next"), style: .plain, target: self, action: #selector(nextItem))
upNext.accessibilityLabel = NSLocalizedString("Up Next", comment: "")
upNext.accessibilityHint = NSLocalizedString("Double tap to show up next list", comment: "")

要修改弹出关闭按钮的无障碍标签和提示,请设置弹出容器视图控制器的 LNPopupCloseButton 对象的 accessibilityLabelaccessibilityHint 属性。

tabBarController?.popupContentView.popupCloseButton.accessibilityLabel = NSLocalizedString("Custom popup close button accessibility label", comment: "")
tabBarController?.popupContentView.popupCloseButton.accessibilityHint = NSLocalizedString("Custom popup close button accessibility hint", comment: "")

要修改弹出条进度视图的无障碍标签和值,请设置弹出内容视图控制器的 LNPopupItem 对象的 accessibilityProgressLabelaccessibilityProgressValue 属性。

demoVC.popupItem.accessibilityImageLabel = NSLocalizedString("Custom image label", comment: "")
demoVC.popupItem.accessibilityProgressLabel = NSLocalizedString("Custom accessibility progress label", comment: "")
demoVC.popupItem.accessibilityProgressValue = "\(accessibilityDateComponentsFormatter.stringFromTimeInterval(NSTimeInterval(popupItem.progress) * totalTime)!) \(NSLocalizedString("of", comment: "")) \(accessibilityDateComponentsFormatter.stringFromTimeInterval(totalTime)!)"

笔记

  • 不支持不透明的条,可能会导致视觉杂乱或布局错误。苹果本身对这种条有很多问题,支持这些不是 LNPopupController 的优先事项。
    • 相反,可以使用透明条,为您的条设置背景色而不是将其设置为不透明,或者将 extendedLayoutIncludesOpaqueBars 设置为 true 以包含控制器
  • 框架或苹果不支持手动隐藏标签栏。请勿使用 tabBar.hidden = YES 来隐藏标签栏。

致谢

框架使用了

此外,演示项目使用了