Подтвердить что ты не робот

Как узнать, когда UIWebView выполняется рендеринг (а не загрузка)?

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

[webView.layer renderInContext:UIGraphicsGetCurrentContext()];

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

4b9b3361

Ответ 1

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

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

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

Ответ 2


Как насчет использования события 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.

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

Ответ 3

У меня была аналогичная проблема в приложении, где я полностью контролирую контент. Это не будет работать, если вы загружаете произвольные страницы из Интернета, но это может сработать, если вы знаете свою структуру 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;
    }
}

Ответ 4

- (void)webViewDidFinishLoad:(UIWebView *)webView {
   if (webView.isLoading)
        return;
    else
    {
            [self hideProgress];
    }

}

Ответ 5

Если у вас есть доступ к 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 
}

Ответ 6

if (webView.loading == YES)
        {
            //Load image
        }

Что-то вроде этого может работать.