Swift 3,iOS 10 – 以编程方式声明UIStackView不适合屏幕宽度

我是一个新的Swift开发人员用WKWebView实现Safari的主要部分(我需要JavaScript和Swift之间的接口,所以SFSafariViewController不是一个选项),并试图以编程方式声明所有元素。

为了模仿Safari的search栏和进度条,我想把UISearchBar设置为一个UIProgressView的顶部,作为UIViewControllerUINavigationItemtitleView 。 我可以用一个元素来pipe理它,但不能与两个元素的堆栈。

以下是我的项目现在的样子。 UISearchBarUIProgressView太宽或太薄,不能正确填充UINavigationBar ,具体取决于旋转:

肖像视图 景观视图

这是我的代码为ViewController.swift:

 import WebKit import UIKit class ViewController: UIViewController, WKNavigationDelegate, UISearchBarDelegate { var searchBar: UISearchBar = UISearchBar() var progressView: UIProgressView = UIProgressView(progressViewStyle: .bar) var stackView: UIStackView = UIStackView() var webView: WKWebView! override func loadView() { webView = WKWebView() webView.navigationDelegate = self view = webView } override func viewDidLoad() { super.viewDidLoad() /** Watches for changes in the WKWebView.estimatedProgress variable, and */ webView.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: .new, context: nil) /** Initialise toolbar elements */ let spacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) let refresh = UIBarButtonItem(barButtonSystemItem: .refresh, target: webView, action: #selector(webView.reload)) toolbarItems = [spacer, refresh] navigationController?.isToolbarHidden = false /** Initialise the UISearchBar */ searchBar.delegate = self // not clear yet whether setting this is necessary. searchBar.searchBarStyle = UISearchBarStyle.minimal searchBar.showsCancelButton = true searchBar.widthAnchor.constraint(equalToConstant: (navigationController?.navigationBar.bounds.width)!).isActive = true // searchBar.heightAnchor.constraint(equalToConstant: 44.0).isActive = true // searchBar.sizeToFit() /** Initialise the UIProgressView */ progressView.widthAnchor.constraint(equalToConstant: (navigationController?.navigationBar.bounds.width)!).isActive = true // progressView.heightAnchor.constraint(equalToConstant: 4.0).isActive = true // progressView.sizeToFit() /** Add the UISearchBar & UIProgressView to the UIStackView, then initialise it and finally set it as the UINavigationItem's titleView.*/ stackView.axis = UILayoutConstraintAxis.vertical stackView.alignment = UIStackViewAlignment.center stackView.distribution = UIStackViewDistribution.fillProportionally stackView.addArrangedSubview(searchBar) stackView.addArrangedSubview(progressView) stackView.translatesAutoresizingMaskIntoConstraints = false; /* These two constraints are causing a crash, so disabling them for now. */ // stackView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true // stackView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true navigationItem.titleView = stackView navigationController?.hidesBarsOnSwipe = true let url = URL(string: "https://en.wikipedia.org")! webView.load(URLRequest(url: url)) webView.allowsBackForwardNavigationGestures = true } /** Updates the UIProgressView. */ override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { // keyPath "estimatedProgress" is equivalent to #keyPath(WKWebView.estimatedProgress) if keyPath == "estimatedProgress" { // progressView.isHidden = webView.estimatedProgress == 1 // if we want to hide upon 100% progressView.progress = Float(webView.estimatedProgress) } } /** Sets the webView's title upon navigation finishing. */ func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { title = webView.title } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } 

注意:任何被接受的解决scheme必须在callback之后继续正确地显示元素堆栈,以隐藏由navigationController?.hidesBarsOnSwipe (即navigationController?.hidesBarsOnSwipe启动的UINavigationBar 。 当用户在WKWebView上执行滑动手势时。

回报我的最终代码,感谢Hacking With Swift作者在Reddit上给出的解决scheme :

 class ViewController: UIViewController, UISearchBarDelegate { var webView: WKWebView? var searchBar: UISearchBar? var progressView: UIProgressView? override func loadView() { super.loadView() setUpWebView() view = self.webView! // TODO: fix constraints error when video is run. setUpSearchbar() setUpProgressView() let url = URL(string: "http://www.bbc.com")! webView!.load(URLRequest(url: url)) } func setUpWebView(){ webView = WKWebView() } func setUpSearchbar(){ searchBar = UISearchBar() searchBar!.delegate = self } func setUpProgressView() { webView!.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: .new, context: nil) guard let bar = navigationController?.navigationBar else { return; } progressView = UIProgressView(progressViewStyle: .bar) progressView!.translatesAutoresizingMaskIntoConstraints = false bar.addSubview(progressView!) progressView!.leadingAnchor.constraint(equalTo: bar.leadingAnchor).isActive = true progressView!.trailingAnchor.constraint(equalTo: bar.trailingAnchor).isActive = true progressView!.bottomAnchor.constraint(equalTo: bar.bottomAnchor).isActive = true } override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { if keyPath == "estimatedProgress" { // progressView.isHidden = webView.estimatedProgress == 1 /* Optional. This hides progressView on 100% */ progressView!.progress = Float((webView?.estimatedProgress)!) } } }