【问题标题】:Navigation bar with large titles and right UIBarButtonItem带有大标题和右侧 UIBarButtonItem 的导航栏
【发布时间】:2019-04-05 15:59:28
【问题描述】:

我正在尝试复制 Podcasts 应用程序(苹果公司)中显示的行为。

如图所示,rightBarButtonItem 与标题“Listen Now”对齐。图标甚至会随之向上滚动(直到消失)。

rightBarButtonItem 带有大标题的默认行为显示在库部分中:

有人知道如何复制第一个例子吗?我需要一个与标题对齐的按钮。

谢谢。

【问题讨论】:

    标签: ios swift xcode uinavigationbar


    【解决方案1】:

    我认为他们不会在播客应用中使用实际的大标题。看起来他们只是使用tableHeaderView 并使它看起来好像它是导航栏的一部分。这是有效的,因为它们会删除导航栏上导航控制器的shadowImage。然后他们在表头视图中放置一个带有.largeTitle 大小字体的标签。例如:

    class ViewController: UIViewController {
    
        @IBOutlet weak var tableView: UITableView!
    
        lazy var titleStackView: TitleStackView = {
            let titleStackView = TitleStackView(frame: CGRect(origin: .zero, size: CGSize(width: view.bounds.width, height: 44.0)))
            titleStackView.translatesAutoresizingMaskIntoConstraints = false
            return titleStackView
        }()
    
        lazy var tableHeaderView: UIView = {
            let tableHeaderView = UIView(frame: CGRect(origin: .zero, size: CGSize(width: view.bounds.width, height: 44.0)))
            tableHeaderView.addSubview(titleStackView)
            titleStackView.leadingAnchor.constraint(equalTo: tableHeaderView.leadingAnchor, constant: 16.0).isActive = true
            titleStackView.topAnchor.constraint(equalTo: tableHeaderView.topAnchor).isActive = true
            titleStackView.trailingAnchor.constraint(equalTo: tableHeaderView.trailingAnchor, constant: -16.0).isActive = true
            titleStackView.bottomAnchor.constraint(equalTo: tableHeaderView.bottomAnchor).isActive = true
            return tableHeaderView
        }()
    
        override func viewDidLoad() {
            super.viewDidLoad()
            title = nil
            navigationController?.navigationBar.isTranslucent = false
            navigationController?.navigationBar.barTintColor = UIColor.white
            navigationController?.navigationBar.shadowImage = UIImage()
            tableView.tableHeaderView = tableHeaderView
            tableView.register(UITableViewCell.self, forCellReuseIdentifier: "\(UITableViewCell.self)")
        }
    
    }
    

    其中TitleStackView 是一个自定义视图,其中包含您希望显示为“大标题”用户界面的用户界面。

    例如:

    class TitleStackView: UIStackView {
    
        override init(frame: CGRect) {
            super.init(frame: frame)
            commonInit()
        }
    
        required init(coder: NSCoder) {
            super.init(coder: coder)
            commonInit()
        }
    
        private func commonInit() {
            axis = .horizontal
            alignment = .center
            addArrangedSubview(titleLabel)
            addArrangedSubview(button)
        }
    
        lazy var titleLabel: UILabel = {
            let label = UILabel()
            label.font = UIFont.systemFont(ofSize: UIFont.preferredFont(forTextStyle: .largeTitle).pointSize, weight: .heavy)
            label.text = "Listen Now"
            label.setContentHuggingPriority(.defaultLow, for: .horizontal)
            label.translatesAutoresizingMaskIntoConstraints = false
            return label
        }()
    
        lazy var button: UIButton = {
            let buttonWidth: CGFloat = 35.0
            let button = UIButton(frame: CGRect(origin: .zero, size: CGSize(width: buttonWidth, height: buttonWidth)))
            button.backgroundColor = .purple
            button.setTitleColor(.white, for: .normal)
            button.setTitle("B", for: .normal)
            button.translatesAutoresizingMaskIntoConstraints = false
            button.widthAnchor.constraint(equalToConstant: buttonWidth).isActive = true
            button.heightAnchor.constraint(equalToConstant: buttonWidth).isActive = true
            button.layer.cornerRadius = button.bounds.height * 0.5
            button.layer.masksToBounds = true
            return button
        }()
    }
    

    最后,他们使用UIScrollViewDelegate 回调来监控何时显示标题:

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let maxTitlePoint = tableView.convert(CGPoint(x: titleStackView.titleLabel.bounds.minX, y: titleStackView.titleLabel.bounds.maxY), from: titleStackView.titleLabel)
        title = scrollView.contentOffset.y > maxTitlePoint.y ? "Listen Now" : nil
     }
    

    如果你做了所有这些事情,你最终会得到如下效果:

    【讨论】:

    • 谢谢@beyouwulf!当我没有找到任何涉及导航栏的解决方案时,我采取了非常相似的方法。
    • 不要认为这个答案对我有用。 Headerview 不是导航栏的一部分,它会导致一些着色问题。更重要的是,如果表格视图没有足够的内容来滚动。您最终会同时进行两场演出。
    • 同意。我不认为这正是苹果正在做的事情。当你通过这种方法推送/弹出视图控制器时,它不像 Podcasts 应用程序那样工作/看起来很棒......