2011-12-15 11 views
15

Sto tentando un editor di testo RTF (con capacità di esportazione HTML) per un'applicazione iPhone su cui sto lavorando e ho deciso di utilizzare il supporto WebKit di iOS 5 per contentEditable/designMode. Ho colpito un muro con un problema che si sta rompendo per quello di cui ho bisogno. Quando si modifica il contenuto in UIWebView, non vi è uno scorrimento automatico per seguire il cursore, ad esempio, in UITextView. Durante la digitazione, il cursore continua sotto scrollView e l'utente deve scorrere manualmente verso l'alto.Scorrimento automatico quando contentEditable/designMode in una UIWebView

Ecco alcuni codice rilevante:

- (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]; 
} 

Delle idee come risolvere questo problema? Non sono sicuro che ciò avvenga anche in Safari o solo nell'implementazione di WebKit di UIWebView.

Se si verifica questo problema, assicurarsi di andare a https://bugreport.apple.com e duplicare rdar: // 16455638.

risposta

3

Per rispondere alla mia domanda, alla fine abbiamo lavorato molto per garantire che questo funzioni correttamente su più versioni di iOS. Abbiamo scoperto che tutti gli eventi di scorrimento erano dovuti allo UIWebView che tentava di gestire il suo UIWebScrollView. Abbiamo deciso invece di utilizzare uno UIWebView, prenderemmo il UIWebDocumentView/UIWebBrowserView interno e aggiungerlo alla nostra vista di scorrimento. Questo ci ha permesso di gestire le dimensioni del contenuto e di scorrere noi stessi e rimosso la maggior parte dei problemi che avevamo precedentemente sperimentato.

+0

Voglio esplorare questo percorso, ma sono preoccupato perché quelle sono classi private che penso (non molto documentate). Hai avuto problemi quando hai inviato questa app? Esistono modi "sicuri" per fare questo e cose da evitare? Ad esempio, devi creare un UIWebView e quindi riparare le visualizzazioni, o creare direttamente queste altre classi, per evitare il rifiuto dell'app store? – eselk

+1

@eselk Usiamo molti trucchi, come il metodo swizzling, ISA swizzling, ecc. In questo caso, è molto più semplice. Prendiamo la sottoview dalla vista scroll, che è esposta in API pubbliche e la aggiungiamo ad un'altra scrollview, che è sotto il nostro controllo. –

+0

@LeoNatan puoi scrivere un codice per lo stesso? – iDhaval

1

Prima È necessario registrare le notifiche della tastiera e, in tale metodo KeyboardWillShow, attivare un metodo di scorrimento con intervallo di tempo di 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]; 

    } 

Creare una variabile membro nel file .h e allocare memoria per esso nel metodo init().

NSString *prevStr; 

all'interno di tale metodo di scorrimento, effettuare le seguenti operazioni.

-(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]; 
    } 

} 

Ciò consentirà di scorrere verso il basso quando si modifica il contenuto e il contenuto è più grande della cornice di WebView. E in altri momenti sarai in grado di scorrere fino alla parte superiore della pagina (lo scorrimento automatico verrà messo in attesa in quel momento).

+0

Ciao selvin, non scorrere quella webview verso il basso? Questo non è qualcosa di cui ho bisogno in ogni momento. Ad esempio, se ho un testo lungo e clicco nel mezzo del testo, il cursore dovrebbe rimanere dove ho cliccato, non scorrere verso il basso. O forse ho frainteso? –

+0

Ciao @Leo. Purtroppo non so come farlo. Perché non sono in grado di ottenere l'offset corrente della scrollview quando posizioni il cursore a metà del testo. Forse dovremmo cercare di ottenere l'offset del contenuto corrente e se non è vicino al fondo, dobbiamo interrompere lo scorrimento automatico . – Selvin

10

Dopo ore di ricerca ho trovato una soluzione migliore, quindi ho pensato di condividere.

C'è un errore nell'implementazione contentEditable di iOS 5 in cui la scrollView principale non scorre con il cursore. Se si effettua il tag body (o qualsiasi elemento di dimensioni dinamiche) contentEditable, il caret andrà sempre fuori dallo schermo.

Se si imposta un div edit in overflow: scorrere, si noterà che il div scorrerà. Lo scorrimento del div non "rimbalza" o ha barre di scorrimento per impostazione predefinita, ma è possibile applicare l'attributo -webkit-overflow-scrolling: touch al div per risolvere il problema.

Con queste informazioni, è possibile risolvere il problema con un wrapper in questo modo:

<!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> 

In sostanza si sta scorrendo il div invece del documento.

Sfortunatamente la "scrollView" del div non è a conoscenza della tastiera virtuale, quindi il cursore scompare dietro la tastiera. Tuttavia, noterai che la posizione del cursore è ancora sullo schermo nella parte inferiore dietro la tastiera. Quindi, per risolvere il problema, riduci l'altezza di div/UIWebView per adattarla alla tastiera.

Un'altra cosa che si potrebbe desiderare di fare è lo scorrimento disabilitare lo ScrollView principale:

webView.scrollView.scrollEnabled = NO; 

Lo ScrollView principale non deve scorrere in ogni caso, ma dovrebbe evitare difetti di scorrimento.

+0

Ciao Luke, stabilirò la tua risposta come risposta accettata. In realtà ho tentato di farlo da solo (sans il '-webkit-overflow-scrolling'), ma sfortunatamente era ancora un po 'buggy. Lo accetto perché è il più vicino a ciò di cui avevo bisogno nella domanda. –

+0

Vorrei aggiungere che non è necessario avere un #wrap, è possibile passare tutto il codice CSS sul corpo e che funzionerà altrettanto bene. – Heilemann

+1

Ottima soluzione! Ma ho notato un piccolo problema: se seleziono (evidenzia) una parola e inizi a scorrere lo stato evidenziato rimane mentre lo scorrimento e va solo quando termina lo scorrimento. Ad ogni modo per superare questo? – vivek241

0

Non ho potuto fare il trucco di impostare "overflow: scroll" dato che ha incasinato il nostro già buono css (se avessimo cambiato l'overflow facendo clic sul div editabile, il layout si sarebbe incasinato). Siamo andati con questo:

$(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 
    } 
}); 

Spero che questo aiuti qualcuno. PITA

Problemi correlati