滚动时收缩大标题(非UITableViewController)iOS 11

26

我有一个嵌入了导航控制器的视图控制器,且使用了大标题选项;在视图控制器内部有一个滚动视图。

我想要在滚动时使导航栏收缩。

如何实现这一目标?

Xcode 9、Swift 4、iOS 11


你是想隐藏还是恢复正常大小? - Mathi Arasan
@user3589771 我的意思是普通尺寸。 - Jonathan Solorzano
我不知道。但在尝试使用UIView动画和撤消更大的标题之前,请先检查此链接 - Mathi Arasan
@user3589771 这仅适用于表视图控制器。 - Jonathan Solorzano
12个回答

88

我没有使用UIScrollView实现这个功能,但我使用其他的ViewControllers,其中第一个视图使用了UITableView来实现。

如果tableView不是第一个视图,那么大标题就无法自动隐藏。你需要确保你的tableView是主视图子视图数组中的第一个元素。

输入图像描述

希望这能解决你的问题。


我不认为这是一个问题。在我的应用程序中,我想始终保持导航栏的大小(不会在滚动时隐藏)。 - Markus
1
OP明确要求不使用UITableViewController的解决方案。 - Andrew Kirna
2
如果你正在以编程方式构建视图,你必须首先将表格/滚动视图作为子视图添加。如果你使用"bringSubviewToFront",你也会失去大标题转换的效果。 - Tristan Newman
这个方法不能在我的TableView首次出现时隐藏大标题。另外,我已经为来自不同View的安全区域提供了顶部约束。 - Kudos
只有在为TableView启用“滚动反弹”时,这才有效。 - Kudos
显示剩余2条评论

8
你尝试过这样的东西吗?在内容向上滚动时,它会将大标题显示模式转换为小标题。
class P1ViewController: UIViewController, UIScrollViewDelegate
{
    var canTransitionToLarge = false
    var canTransitionToSmall = true    

    func scrollViewDidScroll(_ scrollView: UIScrollView)
    {
        if canTransitionToLarge && scrollView.contentOffset.y <= 0 {
            UIView.animate(withDuration: 0.5) {
                self.navigationItem.largeTitleDisplayMode = .always
            }
            canTransitionToLarge = false
            canTransitionToSmall = true
        }
        else if canTransitionToSmall && scrollView.contentOffset.y > 0 {
            UIView.animate(withDuration: 0.5) {
                self.navigationItem.largeTitleDisplayMode = .never
            }
            canTransitionToLarge = true
            canTransitionToSmall = false
        }
    }
}

这个可以工作,但不够流畅,没有使用tableviewcontrollers那样自然。 - Jonathan Solorzano
1
这很有帮助;但我选择了另一个建议,将我的模态UITableViewController嵌套在UINavigationController中。这使我能够同时:(1)显示UINavigationBar和(2)使用navigationController?.navigationBar.prefersLargeTitles = true显示大标题(自动调整滚动手势)。 - Andrew Kirna
如果您喜欢使用标准的 UIViewController,其中包含一个嵌套的 UINavigationBar 和用于滚动内容的 UITextView,那么您应该考虑使用额外的 UIScrollViewDelegate 方法,例如 scrollViewWillBeginDragging(_:)scrollViewDidScroll(_:)scrollViewDidScrollToTop(_:) 来更频繁地更新 largeTitleDisplayMode。请记住,UITextViewDelegate 继承自 UIScrollViewDelegate,因此您可以访问所有这些超类方法。请记得在 viewDidLoad() 中使用从 UITextView 的 outlet 设置视图控制器中的委托,如 textView.delegate = self - Andrew Kirna

6

在代码中设置prefersLargeTitles可以使导航栏标题随滚动而收缩或展开。我注意到如果你通过InterfaceBuilder设置该属性,收缩功能将无法正常工作。

IB Property Inspector

相反,应该像这样在代码中设置:

    self.navigationController?.navigationBar.prefersLargeTitles = true

你能展示一下你的故事板元素层次结构吗? - Jonathan Solorzano
如果TableView不在安全区域以下的视图层次结构中,则此方法无法正常工作。 - Dhaval Bhimani

5
这种方法对我有效。我按照以下步骤进行:
  1. 将TableView移动到视图控制器场景中列表的顶部(安全区域下方)。
  2. 使FirstView由FirstViewController加载。

解决方案截图


2

我曾经遇到过类似的问题,原因是在视图控制器中有许多基于UIScrollView的视图,并且我没有首先滚动层次结构。一旦只有一个UIScrollViewWKWebViewUITextView,它们就可以正常工作,而不需要任何代码。


这对我也起作用了。在UIScrollView之前,我添加了一个背景视图。谢谢! - Kqtr

2
我使用了dsk1306的解决方案,如上所述。但在我的情况下,UIViewController中有一个带有大标题的WebView。

因此,我必须设置UIWebView ScrollView代理:

self.webView.scrollView.delegate = self

并且

extension MyViewController: UIScrollViewDelegate {

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    if #available(iOS 11.0, *) {
        UIView.animate(withDuration: 0.5, animations: {
            self.navigationController?.navigationBar.prefersLargeTitles = (velocity.y < 0)
        })
    }
}

}

1

如果有人需要在顶部放置一些视图,比如菜单,然后是一个UITableView/UICollectionView,且在滚动时大标题不会隐藏,就像我制作的这张“精彩”的图片一样:

你需要为UIView和UITableView/UICollectionView设置所有必需的约束条件,但最重要的部分是:

确保你的UITableView/UICollectionView是第一个子视图,然后是UIView或其他任何视图。

以下是一个示例:


1

我在使用类似于Kamil Szostakowski的答案来处理包含UICollectionView的视图。

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    UIView.animate(withDuration: 0.5, animations: {
        self.navigationController?.navigationBar.prefersLargeTitles = (velocity.y < 0)
    })
}

这可能不太流畅,但我还没有找到更好的选项。

0

@HabibAli,在你给出负评之前,你是否测试过最新的iOS 11.2版本?我在多个设备上测试过,通过全新的git克隆确实可以正常工作。 - DazChong
@HabibAli,它甚至可以在iOS 11.0.1上运行,因为苹果不再允许下载iOS 11.0模拟器。请在评判之前将您的系统更新到最新版本。 - DazChong
1
除非您编辑您的答案并告诉人们使用最新的Xcode和11.2模拟器,否则我无法为此投票。请编辑您的答案。 - Habib Ali

0
如果您在从呈现的VC的scrollView中折叠根navigationBar时遇到问题,可以尝试以下操作: 将UIScrollView添加到RootVC中。重要提示 - UIScrollView必须是根视图(索引为0)。 在presentedVC中,我们可以使用scrollViewDidScroll并在我们的根UIScrollView上设置偏移量。 请参见此处的gif和代码 RootVC视图层次结构: 截图(抱歉,链接不够有声望)
func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if #available(iOS 11.0, *) {
            let offset = scrollView.contentOffset
            rootVC.scrollView.contentOffset = offset
        }
}

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