Автоматическая прокрутка, когда contentEditable/designMode в UIWebView

Я пытаюсь использовать редактор текстового редактора (с возможностью экспорта HTML) для приложения iPhone, над которым я работаю, и решил использовать поддержку IK 5 WebKit для contentEditable/designMode. Я ударил стену с одной проблемой, которая ломается за то, что мне нужно. При редактировании содержимого в UIWebView автоматическая прокрутка курсора, как, например, в UITextView, отсутствует. При наборе текста курсор продолжается под scrollView, и пользователю приходится вручную прокручивать вверх.

Вот какой код:

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    NSString *string = @"document.body.contentEditable=true;document.designMode='on';void(0)";
    [webView stringByEvaluatingJavaScriptFromString:string];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}

Есть идеи, как исправить эту проблему? Я не уверен, что это также происходит в Safari или только в реализации UIWebView WebKit.

Если вы столкнулись с этой проблемой, обязательно перейдите к https://bugreport.apple.com и дублируйте rdar://16455638.

Ответы

Ответ 1

Чтобы ответить на мой собственный вопрос, мы в конечном итоге закончили большую работу, чтобы обеспечить правильную работу в нескольких версиях iOS. Мы выяснили, что все события прокрутки связаны с тем, что UIWebView пытается управлять своим UIWebScrollView. Мы решили вместо использования UIWebView взять внутренний UIWebDocumentView/UIWebBrowserView и добавить его в наш собственный вид прокрутки. Это позволило нам управлять размером контента и прокручивать себя и удалять большинство проблем, которые мы ранее испытывали.

Ответ 2

После нескольких часов исследований я нашел лучшее решение, поэтому я решил поделиться с ним.

В iOS 5 есть проблема с реализацией contentEditable, где основной scrollView не будет прокручиваться с помощью каретки. Если при создании тега body (или любого элемента с динамическим размером) contentEditable, карет всегда будет покидать экран.

Если вы установите редактируемый div для переполнения: прокрутите, вы заметите, что div будет прокручиваться. Прокрутка div не "отскакивает" или имеет полосы прокрутки по умолчанию, но вы можете применить атрибут -webkit-overflow-scrolling: touch к div, чтобы исправить это.

С помощью этой информации вы можете исправить ее с помощью обертки:

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=no;"/>
<style type="text/css">
    html, body {height: 100%;}
    body {
        margin: 0;
    }
    #wrap {
        height: 100%;
        width: 100%;
        overflow-y: scroll;
        -webkit-overflow-scrolling: touch;
    }
    #editor {
        padding: 10px;
    }
</style>
</head>
<body>
<div id="wrap">
    <div id="editor" contenteditable="true">

    </div>
</div>
</body>
</html>

В основном вы прокручиваете div вместо документа.

К сожалению, div "scrollView" не знает виртуальной клавиатуры, поэтому каретка исчезнет за клавиатурой. Однако вы заметите, что позиция каретки все еще находится на экране внизу за клавиатурой. Поэтому, чтобы исправить это, уменьшите высоту div/UIWebView, чтобы разместить клавиатуру.

Что-то еще, что вы можете захотеть сделать, это отключить прокрутку на основном scrollView:

webView.scrollView.scrollEnabled = NO;

Основной scrollView не должен прокручиваться в любом случае, но он должен предотвращать любые прокрутки.

Ответ 3

Сначала вам нужно зарегистрировать уведомления о клавиатуре, и в этом методе keyboardWillShow запускается метод прокрутки с интервалом 0,1 таймера.

 -(void) keyboardWillShow:(NSNotification *)note
    {

        timer   =   [NSTimer    scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(scroll) userInfo:nil repeats:YES];

    }

    -(void) keyboardWillHide:(NSNotification *)note
    {
        [timer invalidate];

    }

Сделайте одну переменную-член в файле .h и выделите для нее память в методе init().

  NSString    *prevStr;

внутри этого метода прокрутки выполните следующие действия.

-(void)scroll{

    if (![prevStr isEqualToString:[WebView stringByEvaluatingJavaScriptFromString:@"document.body.innerHTML"]]) {
        prevStr  =   [[WebView stringByEvaluatingJavaScriptFromString:@"document.body.innerHTML"] retain];
        NSInteger height = [[WebView stringByEvaluatingJavaScriptFromString:@"document.body.offsetHeight;"] intValue];
        NSString* javascript = [NSString stringWithFormat:@"window.scrollBy(0, %d);", height];   
        [WebView stringByEvaluatingJavaScriptFromString:javascript];   
    }

}

Это позволит вам прокручивать нижнюю часть, когда вы редактируете контент, а содержимое больше, чем кадр WebView. И в другое время вы сможете прокручивать верхнюю часть страницы (в это время автосканирование будет удержано).

Ответ 4

Я не мог сделать трюк настройки "переполнение: прокрутка", поскольку он испортил наш уже неплохой css (если мы изменили переполнение при нажатии на редактируемый div, тогда макет перепутался). Пошел с этим:

$(this).on('keypress',function(e){
    //$(this) is the contenteditable div
    var lineHeight = parseInt($(this).css('line-height')) + 2;
    //gets the height of the div        
    newh=$(this).height();
    if (typeof oldh === 'undefined')
        oldh=newh;//saves the current height
    if(oldh!=newh)//checks if the height changes
    {
        //if height changes, scroll up by 1 line (plus a little 2 px)            
        window.scrollBy(0,lineHeight);
        oldh=newh;//resave the saved height since it changed
    }
});

Надеюсь, это поможет кому-то. PITA