有人能告诉我如何在iOS 10的新苹果地图应用程序中模仿底部表格吗?

在Android中,你可以使用一个BottomSheet来模仿这种行为,但我在iOS中找不到任何类似的东西。

这是一个简单的带有内容嵌入的滚动视图,以便搜索栏在底部吗?

我对iOS编程相当陌生,所以如果有人能帮助我创建这个布局,那将是非常感谢的。

这就是我所说的“底稿”:


当前回答

我写了自己的库来实现ios地图应用程序的预期行为。这是一个面向协议的解决方案。因此,您不需要继承任何基类,而是创建一个表控制器,并按照您的意愿进行配置。它还支持内部导航/表示,有或没有UINavigationController。

更多细节请参见下面的链接。

https://github.com/OfTheWolf/UBottomSheet

其他回答

2021年的iOS 15添加了UISheetPresentationController,这是苹果首次公开发布苹果地图风格的“底稿”:

UISheetPresentationController UISheetPresentationController lets you present your view controller as a sheet. Before you present your view controller, configure its sheet presentation controller with the behavior and appearance you want for your sheet. Sheet presentation controllers specify a sheet's size based on a detent, a height where a sheet naturally rests. Detents allow a sheet to resize from one edge of its fully expanded frame while the other three edges remain fixed. You specify the detents that a sheet supports using detents, and monitor its most recently selected detent using selectedDetentIdentifier. https://developer.apple.com/documentation/uikit/uisheetpresentationcontroller

在WWDC Session 10063:在UIKit中自定义和调整表大小中探索了这个新的底部表控件


不幸的是……

在iOS 15中,UISheetPresentationController已经启动,只有中型和大型止动。

值得注意的是,iOS 15 API中没有一个小的缺陷,它将被要求显示像Apple Maps那样始终呈现的“折叠”底部表:

在UISheetPresentationController中自定义更小的止损?

释放了介质止动,以处理共享表或邮件中的“•••More”菜单等用例:按钮触发的半页。

在iOS 15中,苹果地图现在使用这种UIKit表格表示,而不是自定义实现,这是朝着正确方向迈出的一大步。iOS 15中的苹果地图继续显示“小”条,以及1/3高的条。但是这些视图大小并不是开发人员可用的公共API。

WWDC 2021实验室的UIKit工程师似乎知道,一个小的detent将是一个非常受欢迎的UIKit组件。我希望明年能看到iOS 16的API扩展。

我们刚刚发布了一个支持iOS 11.4+的纯Swift包,它为您提供了一个底部表,其中包含您可以自定义的主题和行为选项。该组件使用方便,灵活。你可以在这里找到它:https://github.com/LunabeeStudio/LBBottomSheet。 在这个存储库中还提供了一个演示项目。

例如,它支持不同的方式来管理所需的高度,还添加到它后面的控制器的能力,以检测高度变化和适应其底部内容嵌入。

你可以在GitHub存储库和文档中找到更多信息:https://lbbottomsheet.lunabee.studio。

我觉得它能帮你做你想做的事。如果你有意见或问题,请不要犹豫,告诉我:)

在这里你可以看到所有可能的BottomSheet配置之一:

我不知道新地图应用程序的底部表单是如何响应用户交互的。但您可以创建一个自定义视图,看起来就像屏幕截图中的视图,并将其添加到主视图中。

我想你知道如何:

1-通过故事板或使用xib文件创建视图控制器。

2-使用谷歌地图或苹果的MapKit。

例子

创建2个视图控制器,例如MapViewController和BottomSheetViewController。第一个控制器将承载映射,第二个控制器是底层表本身。

配置MapViewController

创建一个方法来添加底层工作表视图。

func addBottomSheetView() {
    // 1- Init bottomSheetVC
    let bottomSheetVC = BottomSheetViewController()

    // 2- Add bottomSheetVC as a child view 
    self.addChildViewController(bottomSheetVC)
    self.view.addSubview(bottomSheetVC.view)
    bottomSheetVC.didMoveToParentViewController(self)

    // 3- Adjust bottomSheet frame and initial position.
    let height = view.frame.height
    let width  = view.frame.width
    bottomSheetVC.view.frame = CGRectMake(0, self.view.frame.maxY, width, height)
}

并在viewDidAppear方法中调用它:

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    addBottomSheetView()
}

配置BottomSheetViewController

1)准备背景

创建一个方法来添加模糊和振动效果

func prepareBackgroundView(){
    let blurEffect = UIBlurEffect.init(style: .Dark)
    let visualEffect = UIVisualEffectView.init(effect: blurEffect)
    let bluredView = UIVisualEffectView.init(effect: blurEffect)
    bluredView.contentView.addSubview(visualEffect)

    visualEffect.frame = UIScreen.mainScreen().bounds
    bluredView.frame = UIScreen.mainScreen().bounds

    view.insertSubview(bluredView, atIndex: 0)
}

在viewWillAppear中调用这个方法

override func viewWillAppear(animated: Bool) {
   super.viewWillAppear(animated)
   prepareBackgroundView()
}

确保你的控制器视图背景颜色是clearColor。

2)动画bottomSheet外观

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    UIView.animateWithDuration(0.3) { [weak self] in
        let frame = self?.view.frame
        let yComponent = UIScreen.mainScreen().bounds.height - 200
        self?.view.frame = CGRectMake(0, yComponent, frame!.width, frame!.height)
    }
}

3)修改你的xib,你想要的。

4)在视图中添加Pan Gesture Recognizer。

在你的viewDidLoad方法中添加UIPanGestureRecognizer。

override func viewDidLoad() {
    super.viewDidLoad()

    let gesture = UIPanGestureRecognizer.init(target: self, action: #selector(BottomSheetViewController.panGesture))
    view.addGestureRecognizer(gesture)

}

并执行你的手势行为:

func panGesture(recognizer: UIPanGestureRecognizer) {
    let translation = recognizer.translationInView(self.view)
    let y = self.view.frame.minY
    self.view.frame = CGRectMake(0, y + translation.y, view.frame.width, view.frame.height)
     recognizer.setTranslation(CGPointZero, inView: self.view)
}

可滚动的底页:

如果你的自定义视图是一个滚动视图或任何其他继承的视图,那么你有两个选择:

第一:

使用头视图设计视图,并将panGesture添加到头视图。(糟糕的用户体验)。

第二:

1 -添加panGesture到bottom sheet视图。

实现UIGestureRecognizerDelegate,并将panGesture delegate设置为控制器。

实现shouldrecognizesimulouslywith委托函数,并在以下两种情况下禁用scrollView isScrollEnabled属性:

视图部分可见。 视图是完全可见的,scrollView的contenttoffset属性为0,用户正在向下拖动视图。

否则启用滚动。

  func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
      let gesture = (gestureRecognizer as! UIPanGestureRecognizer)
      let direction = gesture.velocity(in: view).y

      let y = view.frame.minY
      if (y == fullView && tableView.contentOffset.y == 0 && direction > 0) || (y == partialView) {
          tableView.isScrollEnabled = false
      } else {
        tableView.isScrollEnabled = true
      }

      return false
  }

NOTE

如果你将. allowuserinteraction设置为一个动画选项,就像在示例项目中一样,那么如果用户向上滚动,你需要在动画完成闭包上启用滚动。

示例项目

我在这个回购上创建了一个具有更多选项的示例项目,这可能会让您更好地了解如何自定义流程。

在演示中,addBottomSheetView()函数控制应将哪个视图用作底层表。

项目示例截图

—局部视图

——FullView

—可滚动视图

也许你可以试试我的答案https://github.com/AnYuan/AYPannel,灵感来自滑轮。从移动抽屉到滚动列表的平稳过渡。我在容器滚动视图中添加了一个平移手势,并设置shouldRecognizeSimultaneouslyWithGestureRecognizer返回YES。更多细节在我的github链接上面。希望能帮上忙。

如果你正在寻找一个使用视图结构的SwiftUI 2.0解决方案,这里是:

https://github.com/kenfai/KavSoft-Tutorials-iOS/tree/main/MapsBottomSheet