Мне пришлось самому заниматься этим вопросом недавно. В конце концов, я использовал модификацию решения , предложенную Крисом МакКленагеном .
На самом деле его оригинальное решение довольно хорошо, и оно работает в самых простых случаях. Однако он работал только для меня на страницах с текстом. Вероятно, он также работает на страницах с изображениями, которые имеют статическую высоту. Однако это определенно не работает, если у вас есть изображения, размер которых определяется атрибутами max-height
и max-width
.
И это потому, что эти элементы могут быть изменены после загрузки страницы. Таким образом, высота, возвращаемая в onLoad
, всегда будет правильной. Но это будет только верно для этого конкретного примера. Обходной путь - отслеживать изменение высоты body
и отвечать на него.
document.body
var shouldListenToResizeNotification = false
lazy var webView:WKWebView = {
//Javascript string
let source = "window.onload=function () {window.webkit.messageHandlers.sizeNotification.postMessage({justLoaded:true,height: document.body.scrollHeight});};"
let source2 = "document.body.addEventListener( 'resize', incrementCounter); function incrementCounter() {window.webkit.messageHandlers.sizeNotification.postMessage({height: document.body.scrollHeight});};"
//UserScript object
let script = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
let script2 = WKUserScript(source: source2, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
//Content Controller object
let controller = WKUserContentController()
//Add script to controller
controller.addUserScript(script)
controller.addUserScript(script2)
//Add message handler reference
controller.add(self, name: "sizeNotification")
//Create configuration
let configuration = WKWebViewConfiguration()
configuration.userContentController = controller
return WKWebView(frame: CGRect.zero, configuration: configuration)
}()
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
guard let responseDict = message.body as? [String:Any],
let height = responseDict["height"] as? Float else {return}
if self.webViewHeightConstraint.constant != CGFloat(height) {
if let _ = responseDict["justLoaded"] {
print("just loaded")
shouldListenToResizeNotification = true
self.webViewHeightConstraint.constant = CGFloat(height)
}
else if shouldListenToResizeNotification {
print("height is \(height)")
self.webViewHeightConstraint.constant = CGFloat(height)
}
}
}
Это решение на сегодняшний день является самым элегантным что я мог бы придумать. Есть, однако, две вещи, о которых вы должны знать.
Во-первых, перед загрузкой вашего URL-адреса вы должны установить shouldListenToResizeNotification
на false
. Эта дополнительная логика необходима для случаев, когда загруженный URL-адрес может быстро изменяться. Когда это происходит, уведомления из старого контента по какой-то причине могут пересекаться с сообщениями из нового контента. Чтобы предотвратить такое поведение, я создал эту переменную. Это гарантирует, что как только мы начнем загрузку нового контента, мы больше не будем обрабатывать уведомление из старого, и мы возобновим обработку уведомлений о размерах после загрузки нового контента.
Самое главное, однако, вы должны знать о это:
Если вы примете это решение, вам необходимо принять во внимание, что если вы измените размер вашего WKWebView
на все, кроме размера, указанного уведомлением, уведомление будет снова запущено.
Будьте осторожны с этим, так как легко вводить бесконечный цикл. Например, если вы решите обработать уведомление, сделав высоту равной сообщаемой высоте + добавочное дополнение:
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
guard let responseDict = message.body as? [String:Float],
let height = responseDict["height"] else {return}
self.webViewHeightConstraint.constant = CGFloat(height+8)
}
Как вы можете видеть, потому что я добавляю 8 к указанной высоте, после этого будет изменен размер моего body
, и уведомление будет опубликовано снова.
Будьте внимательны к таким ситуациям, и в противном случае вы должны быть в порядке.
И, пожалуйста, дайте мне знать если вы обнаружите какие-либо проблемы с этим решением - я полагаюсь на него сам, поэтому лучше знать, есть ли некоторые ошибки, которые я не заметил!
При использовании реализации кучи на основе массивов массив, отсортированный от наименьшего к наибольшему, является минимальной кучей. Свойство кучи, что родительский узел больше, чем его дочерние узлы (2i + 1 и 2i + 2, при использовании массивов, основанных на нулях), действует для всех узлов, имеющих дочерние узлы.
Минимальное значение кучи max находится в одном из листовых узлов, но вы не знаете в каком. Поскольку минимальный узел по определению не может иметь дочерних узлов, он должен быть листом. Свойство кучи, однако, не определяет, как узлы листьев сравниваются друг с другом, только со своим родителем.
Является ли отсортированный массив минимальной кучей?
Да, если вы используете типичное соглашение о куче, хранящейся в массиве.
Где минимальное значение максимальной кучи?
На одном из листьев. Что точно не определено.