Автоматическая прокрутка, когда contentEditable / designMode в UIWebView - PullRequest
15 голосов
/ 15 декабря 2011

Я пытаюсь использовать текстовый редактор (с возможностью экспорта HTML) для приложения iPhone, над которым я работаю, и решил использовать поддержку WebKit для iOS 5 для 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.

Ответы [ 5 ]

11 голосов
/ 26 июля 2012

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

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

Если вы установите редактируемый div в overflow: scroll, вы заметите, что 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 вместо документа.

К сожалению, scrollView div не знает о виртуальной клавиатуре, поэтому каретка исчезнет за клавиатурой. Тем не менее, вы заметите, что позиция каретки по-прежнему на экране внизу за клавиатурой. Чтобы это исправить, уменьшите высоту div / UIWebView, чтобы разместить клавиатуру.

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

webView.scrollView.scrollEnabled = NO;

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

3 голосов
/ 01 января 2014

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

1 голос
/ 22 декабря 2011

Сначала необходимо зарегистрировать уведомления клавиатуры, и в этом методе 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.И в других случаях вы сможете прокрутить до верхней части страницы (автопрокрутка будет удерживаться в это время).

0 голосов
/ 21 марта 2018

Вы можете попытаться получить рамку каретки с небольшим хитрым взломом и вручную прокрутить до видимого прямоугольника.

0 голосов
/ 21 января 2014

Я не смог выполнить трюк с настройкой «переполнения: прокрутка», так как это испортило наш и без того хороший 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

...