Swift 3,iOS 10 - 以编程方式声明 UIStackView 不适合屏幕宽度
Posted
技术标签:
【中文标题】Swift 3,iOS 10 - 以编程方式声明 UIStackView 不适合屏幕宽度【英文标题】:Swift 3, iOS 10 - programmatically declared UIStackView not fitting screen width 【发布时间】:2017-02-12 02:13:50 【问题描述】:我是一名新的 Swift 开发人员,使用 WKWebView 实现 Safari 的主要部分(我需要在 javascript 和 Swift 之间进行接口,因此 SFSafariViewController 不是一个选项)并尝试以编程方式声明所有元素。
为了模仿 Safari 的搜索栏和进度条,我想设置一个 UISearchBar,堆叠在 UIProgressView 的顶部,作为 UIViewController 的 titleView
的 UINavigationItem。我可以只使用一个元素来管理它,但不能使用两个元素的堆栈。
这是我的项目现在的样子。 UISearchBar 和 UIProgressView 太宽或太薄,无法正确填充 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.
注意:任何接受的解决方案都必须在回调后继续正确显示元素堆栈,以隐藏由navigationController?.hidesBarsOnSwipe
发起的UINavigationBar,即。当用户在 WKWebView 上执行滑动手势时。
【问题讨论】:
【参考方案1】:在Hacking With Swift 的作者在 Reddit 上提供的 solution 的指导下,用我的最终代码进行报告:
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)!)
【讨论】:
以上是关于Swift 3,iOS 10 - 以编程方式声明 UIStackView 不适合屏幕宽度的主要内容,如果未能解决你的问题,请参考以下文章
iOS - 在 Swift 3 中以编程方式删除和激活新约束时布局损坏
如何以编程方式从 iOS Swift 3 中的 XIB 推送和呈现给 UIViewController