带有大标题和右 UIBarButtonItem 的导航栏

Navigation bar with large titles and right UIBarButtonItem

我正在尝试复制 Podcasts 应用程序(由 Apple)中显示的行为。

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

带有大标题的 rightBarButtonItem 的默认行为显示在图书馆部分:

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

谢谢。

我不认为他们在播客应用程序中使用实际的大标题。看起来他们只是在使用 tableHeaderView 并使其看起来像是导航栏的一部分。这是有效的,因为它们擦除了导航栏中导航控制器的 shadowImage。然后他们在 table header 视图中放置一个带有 .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 是自定义视图,其中 UI 您希望显示为 "large title" UI。

例如:

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
 }

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