Swift呈现控制器解除栏指示器

5

对于大多数人来说,这应该是一个简单的问题。如附图所示,现在展示视图控制器时会在控制器上方添加一个条形栏(见红箭头),表示用户可以向下滑动以关闭控制器。请回答以下任意一个问题:

  • 这个图标的正确术语是什么?
  • 它是 Swift 的 UI 工具/库的一部分,还是只是 UIImage?
  • 有人能提供一个简单的代码片段来实现吗——或许类似于以下代码
let sampleController = SampleController()
sampleController.POSSIBLE_OPTION_TO_SHOW_BAR_ICON = true
present(sampleController, animated: true, completion: nil)

请看我所指的图标上的红色箭头。
点击这里查看该图标,图片如下: enter image description here

你找到这个需求的解决方案了吗?我目前正在寻找与你完全相同的需求的解决方案。 - loongman
嗯,不太对。我已经了解到你需要自己构建它,而它并不是Swift UI / Library的一部分。然而,我没有了解到这个图标的名称叫什么。如果你找到了,请告诉我。 - teamvtechnology
我按照 https://fluffy.es/facebook-draggable-bottom-card-modal-1/ 和 https://fluffy.es/facebook-draggable-bottom-card-modal-2/ 上的指南实现了该功能。顺便提一下。 - loongman
谢谢@loongman。这是一篇很棒的文章,但我有一个问题。在第7步中,它提到要将UI View添加为“Handle”视图。对我来说,这就是我们图标的答案,但它没有说明如何做到这一点。如何将UI View添加为“Handle”视图?以下是带有此内容的图像链接。https://iosimage.s3.amazonaws.com/2019/62-bottom-card/step7.png - teamvtechnology
在我的情况下,“Handle”视图被添加为常规UIView,大小为(36, 4),cornerRadius为(2),加上特定的backgroundColor,放置在暗淡的视图中。并将其底部固定到卡片视图的顶部,因此,每当卡片视图滚动时,手柄视图也会滚动。 - loongman
3个回答

4
  1. Grabber

抓手是一个小的水平指示器,可以出现在窗格的顶部边缘。

一般情况下,在可调整大小的窗格中包括抓手。 抓手显示用户可以拖动窗格来调整大小,他们也可以点击它来依次遍历卡槽。除了提供可调整大小的视觉指示器外,抓手还与VoiceOver配合使用,因此用户可以在不看屏幕的情况下调整窗格的大小。有关开发人员指南,请参见prefersGrabberVisible。

https://developer.apple.com/design/human-interface-guidelines/ios/views/sheets/

  1. iOS 15+开始,UISheetPresentationController具有属性prefersGrabberVisible https://developer.apple.com/documentation/uikit/uisheetpresentationcontroller/3801906-prefersgrabbervisible

抓手是一种视觉效果,用于提示一个窗格是可调整大小的。当不明显时,显示抓手可能会很有用,或者当窗格无法交互式地解除时。

将此值设置为true以使系统在标准的系统定义位置绘制抓手。系统会在适当的时间自动隐藏抓手,例如当窗格在紧凑高度尺寸类别中全屏显示或另一个窗格在其上方呈现时。

  1. iOS 15的Playground片段:
import UIKit
import PlaygroundSupport

let viewController = UIViewController()
viewController.view.frame = CGRect(x: 0, y: 0, width: 380, height: 800)
viewController.view.backgroundColor = .white

PlaygroundPage.current.liveView = viewController.view
PlaygroundPage.current.needsIndefiniteExecution = true

let button = UIButton(primaryAction: UIAction { _ in showModal() })
button.setTitle("Show page sheet", for: .normal)
viewController.view.addSubview(button)
button.frame = CGRect(x: 90, y: 100, width: 200, height: 44)

func showModal {
    let viewControllerToPresent = UIViewController()
    viewControllerToPresent.view.backgroundColor = .blue.withAlphaComponent(0.5)
    viewControllerToPresent.modalPresentationStyle = .pageSheet // or .formSheet
    if let sheet = viewControllerToPresent.sheetPresentationController {
        sheet.detents = [.medium(), .large()]
        sheet.prefersGrabberVisible = true
    }
    viewController.present(viewControllerToPresent, animated: true, completion: nil)
}

Grabber example


0

您所要求的功能在UIKit中不可用。

您必须通过子类化UIPresentationController来实现自定义视图控制器转换动画,以呈现上拉/下拉句柄。

UIPresentationController (developer.apple.com)

对于自定义演示,您可以提供自己的演示控制器,以使呈现的视图控制器具有自定义外观。演示控制器管理与视图控制器及其内容分开的任何自定义chrome。例如,放置在视图控制器视图后面的调暗视图将由演示控制器管理。Apple Documentation

这可以通过任何UIView实现,或者如果您想要添加子视图到UIPresentationController的contentView上方的presentedView,则可以使用任何图像。

要提供滑动手势以解除/呈现,您必须实现UIPercentDrivenInteractionController

你可以参考下面的教程来深入了解。

raywenderlich.com的UIPresentationController教程

在你的情况下,你应该寻找presentationDirection = .bottom

对于手势驱动的解除,你应该查看下面的教程

自定义UIViewcontroller转换入门

我希望这能帮到你。


0
如果您不想进行任何自定义操作,只使用默认转场并在被呈现的视图控制器中添加此指示器,则需要将其添加到within视图控制器中。
首先要考虑的是视图层次结构,该指示器是否将成为导航栏的一部分,或者您的视图没有导航栏 - 因此,您可能需要一些代码来查找正确的视图以添加此指示器。
在我的情况下,我需要一个导航栏,因此我的视图控制器位于导航控制器中,但您也可以直接在您的视图控制器内执行相同的操作:
1:子类化导航控制器
这是可选的,但将所有这些自定义封装到导航控制器中会很好。
我检查以查看NavigationController是否正在被呈现。这可能不是最佳检查方式,但由于这不是问题的一部分,请参阅这些答案以检查视图控制器是否以模式呈现。
class CustomNavigationController: UINavigationController {
  override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    
    // this checks if the ViewController is being presented
    if presentingViewController != nil {
      addModalIndicator()
    }
  }

  private func addModalIndicator() {
    let indicator = UIView()
    indicator.backgroundColor = .tertiaryLabel
    let indicatorSize = CGSize(width: 30, height: 5)
    let indicatorX = (navigationBar.frame.width - indicatorSize.width) / CGFloat(2)
    indicator.frame = CGRect(origin: CGPoint(x: indicatorX, y: 8), size: indicatorSize)
    indicator.layer.cornerRadius = indicatorSize.height / CGFloat(2.0)
    navigationBar.addSubview(indicator)
  }
}

2:展示自定义导航控制器

let someVC = UIViewController()
let customNavigationController = CustomNavigationController()
customNavigationController.setViewControllers([stationsVC], animated: false)
present(playerNavigationController, animated: true) { }

3: 这将会产生以下的结果 iOS Swift UIKit modal present dismiss indicator

根据你的情境/视图控制器层次结构,你可能需要修改一些逻辑,但希望这能给你一些想法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接