9

我正在从具有大样式UINavigationItem的视图过渡到具有大样式UINavigationItemUISearchController. 我已经自定义了UINavigationBar.

UINavigationBar出于某种原因,在和之间有一个 1px 的线或空格UISearchController。我可以从 中看出它NavigationBar,因为如果我滚动以使搜索栏贴在顶部,则该行会消失。我只是不确定是什么产生了这条线。barTintColor除了设置和之外,我没有使用阴影或任何花哨的东西tintColor。如果我不使用大样式标题,我会看到这条线,但仅在视图之间转换时。就像在过渡时UISearchControllerjust 不坚持UINavigationBar.

任何帮助找出这条线来自哪里的任何帮助表示赞赏。

更新:在进一步调查中,似乎这只发生在navigationItem.hidesSearchBarWhenScrolling设置为false. 如果它最初是隐藏的,那么前一个视图的动画是平滑的,并且显示条也是平滑的。

行的示例截图

4

4 回答 4

5

测试您描述的导航项和搜索栏设置,我只能在过渡动画期间重现 1px/point 线。

解决方法:此行实际上是一个背景布局视图( forLastBaselineLayout),UINavigationBar由于UISearchBar. 设置其背景以匹配您的导航栏颜色以将其隐藏在后站点中

// MARK: UINavigationControllerDelegate

public func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
    viewController.navigationController?.navigationBar
        .forLastBaselineLayout.backgroundColor = .red // TODO:
}

确保将对象实现UINavigationControllerDelegate设置为navigationController.delegate接收上述委托调用。

另外(不是问题的一部分): UISearchBar在控制器之间转换(推送和弹出)时似乎表现得很奇怪,尤其是当一个有/显示一个searchBar但没有另一个时。解决方法,我发现暂时隐藏搜索栏以显示控制器在视觉上更令人愉悦。这是我使用的代码:

public func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
    if let sender = navigationStack.popLast() {
        prepareSearchBarForTransition(from: sender)
    }
    navigationStack = navigationController.children
}

/// Set only from `navigationController: willShow`
private var navigationStack: [UIViewController] = []

func prepareSearchBarForTransition(from sender: UIViewController) {
    if #available(iOS 11.0, *) {
        let searchController = sender.navigationItem.searchController
        sender.navigationItem.searchController = nil
        weak var weakSender = sender
        let navigationTransitionDuration: TimeInterval = 0.33
        DispatchQueue.main.asyncAfter(deadline: .now() + navigationTransitionDuration) {
            /// Reset the search bar.
            weakSender?.navigationItem.searchController = searchController
        }
    } else {
        // TODO: Check if the above workaround is neccessary for < iOS 11
    }
}
于 2018-09-21T04:03:39.793 回答
2

从整个应用程序中删除一条像素线。

UINavigationBar.appearance().shadowImage = UIImage()

上面的代码从整个应用程序中删除了底线。如果只想删除某些特定控制器,则需要管理隐藏/显示底栏图像。对于使用下面UINavigationBar的扩展来管理隐藏显示底栏一个像素图像。

extension UIView {

    fileprivate var hairlineImageView: UIImageView? {
        return hairlineImageView(in: self)
    }

    fileprivate func hairlineImageView(in view: UIView) -> UIImageView? {
        if let imageView = view as? UIImageView, imageView.bounds.height <= 1.0 {
            return imageView
        }

        for subview in view.subviews {
            if let imageView = self.hairlineImageView(in: subview) {
                return imageView
            }
        }
        return nil
    }
}

extension UINavigationBar {

    func hideBottomHairline() {
        self.hairlineImageView?.isHidden = true
    }

    func showBottomHairline() {
        self.hairlineImageView?.isHidden = false
    }
}

管理隐藏/显示

self.navigationController?.navigationBar.hideBottomHairline()

self.navigationController?.navigationBar.showBottomHairline()

以上UIView扩展名hairlineImageView也可以用于其他UIControls类似UIToolBar

extension UIToolbar {

    func hideBottomHairline() {
        self.hairlineImageView?.isHidden = true
    }

    func showBottomHairline() {
        self.hairlineImageView?.isHidden = false
    }
}
于 2018-09-18T09:32:27.247 回答
1

使用以下代码:

navigationController?.navigationBar.shadowImage = UIImage()
于 2018-09-18T01:54:57.203 回答
1

如果要删除 UINavigationBar 上的 1px 行,在整个应用程序中,您可以在 AppDelegate (didFinishLaunchingWithOptions) 中使用以下代码(测试代码)

UINavigationBar.appearance().shadowImage = UIImage()
于 2018-09-18T06:16:22.750 回答