Как узнать, когда UIWebView завершил рендеринг (не загружается)? - PullRequest
34 голосов
/ 27 апреля 2011

Я знаю, когда загрузка будет завершена ... (webViewDidFinishLoad), но я хочу использовать

[webView.layer renderInContext:UIGraphicsGetCurrentContext()];

для создания изображения из UIWebView.Иногда я получаю изображение до того, как webView завершит его рендеринг.Я могу использовать executeSelector, чтобы задержать получение изображения, но количество ожидания является произвольным и хрупким.

Ответы [ 6 ]

4 голосов
/ 03 мая 2013

Это может зависеть от вида графического контекста, в который вам нужно визуализировать представление, но вы можете вызвать

- (void)drawRect:(CGRect)area forViewPrintFormatter:(UIViewPrintFormatter *)formatter

, который, по-видимому, обманывает UIWebView, заставляя его думать, что он печатается. Это может помочь, если вашей конечной целью является захват всей страницы. Недавно у нас возникла проблема, заключающаяся в том, что даже если страница была полностью загружена, при вызове простого старого -drawRect: не отображалась вся страница, если какая-то ее часть была за кадром.

2 голосов
/ 17 марта 2013

У меня была похожая проблема в приложении, где я полностью контролирую контент. Это не будет работать, если вы загрузите произвольные страницы из Интернета, но оно может работать, если вы знаете свою высокоуровневую структуру DOM, и она не сильно изменится .

Для меня сработало следующее.

Мне пришлось рекурсивно найти первое UIWebView подпредставление типа UIWebOverflowScrollView с рамкой (0, 0, 1024, 768). Если я не мог найти тот, это был верный признак, что содержание еще не было предоставлено. Найдя его, я проверяю это представление layer.sublayers.count. Когда рендеринг заканчивается, я всегда получаю один или три подслоя. Однако, если рендеринг еще не завершен, представление содержимого всегда содержало не более один подслой.

Теперь, , это специфично для моей структуры DOM - но возможно, что вы создадите аналогичный «тест», если вы сравните дерево подслоев до и после рендеринга. Для меня эмпирическое правило было «первое рекурсивно найденное подпредставление типа UIWebOverflowScrollView будет иметь как минимум три подслоя», для вас оно, скорее всего, будет другим.

В любом случае, будьте очень осторожны, если вы решите использовать этот подход, поскольку, хотя вы не будете отклонены за просмотр представления и иерархии слоев UIWebView, такое поведение ненадежно и, скорее всего, изменится. в будущих версиях iOS. Это вполне может быть несовместимо между iOS 5 и iOS 6.

Наконец, отрывки кода для MonoTouch, которые должны быть простыми для перевода в Objective C:

bool IsContentScrollView (UIScrollView scrollView)
{
    return scrollView.Frame.Equals (new RectangleF (0, 0, 1024, 768));
}

[DllImport ("/usr/lib/libobjc.dylib")]
private static extern IntPtr object_getClassName (IntPtr obj);

public static string GetClassName (this UIView view) {
    return Marshal.PtrToStringAuto (object_getClassName (view.Handle));
}
bool IsWebOverflowScrollView (UIScrollView scrollView)
{
    return scrollView.GetClassName () == "UIWebOverflowScrollView";
}

IEnumerable<UIScrollView> ScrollViewsInside (UIView view)
{
    foreach (var subview in view.Subviews) {
        foreach (var scrollView in ScrollViewsInside (subview).ToList())
            yield return scrollView;

        if (subview is UIScrollView)
            yield return (UIScrollView)subview;
    }
}

bool CanMakeThumbnail {
    get {
        var scrollViews = ScrollViewsInside (this).Where (IsWebOverflowScrollView).ToList ();
        var contentView = scrollViews.FirstOrDefault (IsContentScrollView);

        // I don't know why, but this seems to be a good enough heuristic.
        // When the screen is black, either contentView is null or it has just 1 sublayer.

        // This may *break* on any iOS updates or DOM changes--be extra careful!

        if (contentView == null)
            return false;

        var contentLayer = contentView.Layer;
        if (contentLayer == null || contentLayer.Sublayers == null || contentLayer.Sublayers.Length < 3)
            return false;

        return true;
    }
}
2 голосов
/ 15 декабря 2011


А как насчет использования события window.onload или jQuerys $ (document) .ready для запуска обратного вызова shouldStartLoad?

Что-то вроде:

$(document).ready(function(){
    location.href = "app://do.something"
})

и в вашем UIWebViewDelegateсделать что-то вроде:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    NSURL *url = request.URL;

    if([url.host isEqualToString:@"app"]){
        //maybe check for "do.something"
        //at this point you know, when the DOM is finished
    }
}

С помощью этого метода вы можете пересылать каждое возможное событие из кода JS в ваш код obj-c.

Надеюсь, что это поможет.Пример кода написан в браузере и поэтому не проверен!; -)

0 голосов
/ 30 сентября 2015
- (void)webViewDidFinishLoad:(UIWebView *)webView {
   if (webView.isLoading)
        return;
    else
    {
            [self hideProgress];
    }

}
0 голосов
/ 23 марта 2013
if (webView.loading == YES)
        {
            //Load image
        }

Нечто подобное может работать.

0 голосов
/ 19 декабря 2011

Если у вас есть доступ к HTML-файлу и вы можете его редактировать - просто добавьте некоторую специальную переменную, которая сообщит коду, что рендеринг выполнен.
Затем используйте метод stringByEvaluatingJavaScriptFromString, чтобы узнать, стоит ли вам запускать какие-либо действия или нет.
Пример ниже довольно грязный, но надеюсь, что он поможет и даст вам идею:

(void)webViewDidFinishLoad:(UIWebView *)webView
{
    BOOL renderingDone = NO;
    while (!(renderingDone == [[webView stringByEvaluatingJavaScriptFromString:@"yourjavascriptvariable"] isEqualToString:@"YES"]))
    {
        // the app will be "freezed" till the moment when your javascript variable will not get "YES" value 
    }
    // do your stuff, rendering is done 
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...