gpt4 book ai didi

ios - 在 View Controller 之间推送转换时保持 View

转载 作者:行者123 更新时间:2023-12-01 16:06:24 25 4
gpt4 key购买 nike

我有一个标签栏 iOS 应用程序。其中一个选项卡是 map ( MyMapViewController )。 MyMapViewController 顶部有一个自定义的“搜索”栏:

enter image description here

一旦用户点击“搜索”栏,他就会进入搜索屏幕:

enter image description here

现在用户可以输入一些名称,对象列表被过滤,并允许用户找到所需的对象。这一切都很好。

唯一的问题是标签栏在搜索屏幕上可见。我需要在搜索屏幕可见时将其删除,并在用户返回 map 屏幕后立即将其返回。这就是我想要实现的目标:

enter image description here

现在,搜索屏幕是 MyMapViewController 的 subview Controller .它叫MySearchViewController . “ map ”模式和“搜索”模式之间的动画转换是使用 Core Animation 执行的。 View Controller 上没有任何“push”/“pop”或“present”/“dismiss”操作。

我无法隐藏标签栏 ( UITabBar ) isHidden = true或者通过移动它的框架,因为它留下了一个空白的矩形。
据我所知,只有两种方法可以隐藏标签栏:

  • 将新 Controller (带有 hidesBottomBarWhenPushed = true )推送到导航堆栈
  • 提出模态 Controller

  • 所以看来我需要从

    (父 View Controller ) MyMapViewController ,( subview Controller ) MySearchViewController

    UINavigationStack : MyMapViewController --(推送)--> MySearchViewController
    但。在这种情况下,我应该如何处理“搜索”栏?它是 MyMapViewController 的一部分,它是 MySearchViewController 的一部分以及。 View 是否可能是两个的一部分 UIViewControllers ?另外,我需要它在从 MyMapViewController 插入过渡期间动画一点至 MySearchViewController (如您所见,放大的玻璃必须转换为后箭头)。

    最佳答案

    UITabBarController 的问题在于它的 TabBar 是在不使用 NSLayoutConstraints 的情况下添加的(或者,更准确地说,它将自动调整大小掩码转换为约束)。因此,您可以使用两种方法:

    1)按照您现在的方式使用 UITabBarController,但它需要一些技巧来隐藏它 - 基本上在 UINavigationController 内使用 UITabBarController 以便将 View 推送到它上面(但转换将是可见的,即使你将它推送没有动画(键盘将开始隐藏),或者您可以手动隐藏 TabBar 并调整 TabBar 内容 View 的框架大小,如 https://stackoverflow.com/a/6346096/7183675 所示)。

    在最后一种情况下,您还必须在更改内容 View 之前记住它(或在再次取消隐藏 TabBar 之前计算它)。此外,由于它不在官方 API 中,因此您必须考虑到 UITabBarController 中 subview 的顺序可以更改并且效果看起来很奇怪(或者只是使应用程序崩溃)

    2)使用带有 UITabBar 的“普通” UIViewController 及其带有约束的手动添加的项目。它也可以是自定义 UIView 子类和从 XIB 创建的几个按钮。在这里您直接创建约束,因此您可以更好地控制。
    但是这个也不会没有一些技巧,因为添加到单个 UIViewController 的 UITabBar 与此 UIViewController 一起进行每次转换(假设您在每个 UIViewController 中都有 UINavigationController,这将是非常常见的)。

    因此,在这种情况下,主要问题是制作单个底栏并将其传输到 View 的 viewDidAppear 上的 UIWindow,在该 View 中创建唯一的底栏 - 从 Storyboard或 xib 文件中推荐。对于下一个 View ,您将只传递对它的引用或为此将该指针保留在一个类中。您还应该记住在标签栏下创建覆盖安全区域的 View 。

    它看起来像这样:

        private var firstRun = false

    override func viewDidLoad() {
    super.viewDidLoad()
    firstRun = true
    }

    override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    guard firstRun else {
    bottomBar.superview?.bringSubviewToFront(bottomBar)
    bottomSafeAreaView.superview?.bringSubviewToFront(bottomSafeAreaView)
    return
    }

    guard let window = UIApplication.shared.windows.first, let bottomB = bottomBar, let bottomSafeArea = bottomSafeAreaView else { return }

    if bottomB.superview != window {
    bottomB.deactivateConstrainsToSuperview()
    bottomSafeArea.deactivateConstrainsToSuperview()

    window.addSubview(bottomSafeArea)
    window.addSubview(bottomB)
    let bottomLeft = NSLayoutConstraint(item: bottomSafeArea, attribute: .leading, relatedBy: .equal, toItem: window, attribute: .leading, multiplier: 1, constant: 0)
    let bottomRight = NSLayoutConstraint(item: bottomSafeArea, attribute: .trailing, relatedBy: .equal, toItem: window, attribute: .trailing, multiplier: 1, constant: 0)
    let bottomBottom = NSLayoutConstraint(item: bottomSafeArea, attribute: .bottom, relatedBy: .equal, toItem: window, attribute: .bottom, multiplier: 1, constant: 0)
    let leftConstraint = NSLayoutConstraint(item: bottomB, attribute: .leading, relatedBy: .equal, toItem: window, attribute: .leading, multiplier: 1, constant: 0)
    let rightConstraint = NSLayoutConstraint(item: bottomB, attribute: .trailing, relatedBy: .equal, toItem: window, attribute: .trailing, multiplier: 1, constant: 0)
    let bottomConstraint = NSLayoutConstraint(item: bottomB, attribute: .bottom, relatedBy: .equal, toItem: bottomSafeArea, attribute: .top, multiplier: 1, constant: 0)
    NSLayoutConstraint.activate([bottomLeft, bottomRight, bottomBottom, leftConstraint, rightConstraint, bottomConstraint])
    }

    window.layoutIfNeeded()

    DispatchQueue.main.async(execute: {
    bottomB.superview?.bringSubviewToFront(bottomB)
    bottomSafeArea.superview?.bringSubviewToFront(bottomSafeArea)
    })

    firstRun = false
    }

    加上一个在扩展中创建的实用方法:
    extension UIView {

    func deactivateConstrainsToSuperview() {
    guard let superview = self.superview else {return}
    NSLayoutConstraint.deactivate(self.constraints.filter({
    return ($0.firstItem === superview || $0.secondItem === superview)
    }))
    }
    }

    所以要写一些代码,但只有一次。之后,您将拥有在必要时易于显示或隐藏的 TabBar,以这种方式在“内容 View ”和安全区域之间使用约束
    private func hideBottomBar() {
    UIView.animate(withDuration: Constants.appAnimation.duration, animations: { [weak self] in
    guard let self = self else { return }
    self.bottomBar.isHidden = true
    self.bottomBarHeightConstraint.constant = 0
    self.bottomBar.superview?.layoutIfNeeded()
    })
    }


    private func showBottomBar() {
    UIView.animate(withDuration: Constants.appAnimation.duration, animations: { [weak self] in
    guard let self = self else { return }
    self.bottomBar.isHidden = false
    self.bottomBarHeightConstraint.constant = Constants.appConstraintsConstants.bottomBarHeight
    self.bottomBar.superview?.layoutIfNeeded()
    })
    }

    至于覆盖安全区域的 View 高度(在tabBar底部和BottomLayoutGuide顶部之间)
    if #available(iOS 11.0, *) {
    self.bottomSafeAreaViewHeightConstraint.constant = self.view.safeAreaInsets.bottom
    } else {
    self.bottomSafeAreaViewHeightConstraint.constant = 0
    }

    希望能帮到你,祝你好运!

    关于ios - 在 View Controller 之间推送转换时保持 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59619787/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com