2016-01-14 7 views
12

Ho una pagina web a scopo di test (https://storage.googleapis.com/htmltestingbucket/nested_scroll_helper.html), che si limita a stampare un contatore della manifestazione di scorrimento del HTML ha catturato in un colpo di testa fissaHTML scorrimento eventi in un WebView Android che è all'interno di uno ScrollView

Quando il WebView Android è l'unico elemento scroll-able nel frammento tutto è a posto e la WebView invia gli eventi di scorrimento alla pagina

Se voglio aggiungere elementi nativi sopra e sotto la WebView, le cose diventano molto più complesse.

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:custom="http://schemas.android.com/apk/res-auto" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

    <LinearLayout 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:orientation="vertical"> 

     <TextView 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:padding="20dp" 
      android:text="SOMETHING ABOVE THE WEBVIEW" /> 

     <WebView 
      android:id="@+id/webview" 
      android:layout_width="match_parent" 
      android:layout_height="match_parent" /> 

     <TextView 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:padding="20dp" 
      android:text="SOMETHING BELOW THE WEBVIEW" /> 

    </LinearLayout> 
</ScrollView> 

io so che non è bene avere una WebView all'interno di uno ScrollView ma devo fornire una sola esperienza di scorrimento con i contenuti ibridi ed eventi scorrimento corretto nel documento HTML. ho trovato un sacco di domande sulla materia, ma sono stato in grado di creare una soluzione completa end-to-end


Inoltre, so lint ha un controllo Ufficiale per questo:

NestedScrolling --------------- Sommario: nidificati widgets scorrimento

Priorità: 7/10 di gravità: avviso Categoria: esattezza

un widget scorrimento come ad esempio uno Scro llView non deve contenere nidificati widget scorrimento dal momento che questo ha diversi problemi di usabilità

Eppure, non posso accettare il contenuto visualizzazione Web in nativo quindi ho bisogno di un modo alternativo per farlo

+0

vedere la risposta accettata di http://stackoverflow.com/questions/9718245/webview-in-scrollview – MASh

+0

l'ho visto prima che ho postato, avviso: "Dal momento che Android KitKat nessuna delle soluzioni descritte di seguito stanno lavorando - si sarà necessario cercare approcci diversi come ad esempio FadingActionBar di Manuel Peinado che fornisce un'intestazione a scorrimento per WebViews." -> Non sto cercando di risolvere un problema con l'elemento nativo sopra la webview, che è molto più semplice –

+0

Non sto cercando di risolvere un problema con l'elemento nativo SOLO sopra la webview, che è molto più semplice –

risposta

1

Per Tenere Webview all'interno di scrollview qui è necessario misurare l'altezza della webview e impostarla nei parametri di layout.

Qui ho provato a dare una risposta per la visualizzazione web scorrevole.

<ScrollView 
     android:layout_width="fill_parent" android:background="#FF744931" 
     android:layout_height="fill_parent"> 

     <LinearLayout 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:orientation="vertical" 
      tools:ignore="WebViewLayout"> 

      <TextView 
       android:id="@+id/txtVoiceSeachQuery" 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:textColor="#FF0000" 
       android:textSize="26sp" /> 

      <TextView 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content" 
       android:padding="20dp" 
       android:text="SOMETHING ABOVE THE WEBVIEW" /> 

      <com.example.ScrollableWebView 
       android:id="@+id/webview" 
       android:layout_width="match_parent" 
       android:layout_height="match_parent" 
       app:isWebViewInsideScroll="true" /> 

      <TextView 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content" 
       android:padding="20dp" 
       android:text="SOMETHING BELOW THE WEBVIEW" /> 

     </LinearLayout> 
    </ScrollView> 

res/valori/attrs.xml

Per aggiungere attributo per il controllo personalizzato

<?xml version="1.0" encoding="utf-8"?> 
<resources> 
<declare-styleable name="ScrollableWebView"> 
    <attr name="isWebViewInsideScroll" format="boolean"></attr> 
</declare-styleable> 
</resources> 

ScrollableWebView

public class ScrollableWebView extends WebView { 
    private boolean webViewInsideScroll = true; 
    public static final String RESOURCE_NAMESPACE = "http://schemas.android.com/apk/res-auto"; 

    public ScrollableWebView(Context context) { 
     super(context); 
    } 

    public ScrollableWebView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     setWebViewInsideScroll(attrs.getAttributeBooleanValue 
       (RESOURCE_NAMESPACE, "isWebViewInsideScroll", true)); 
    } 

    @Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
     if (isWebViewInsideScroll()) { 
      int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK, MeasureSpec.AT_MOST); 
      super.onMeasure(widthMeasureSpec, expandSpec); 
      ViewGroup.LayoutParams params = getLayoutParams(); 
      params.height = getMeasuredHeight(); 
      setLayoutParams(params); 
     } else { 
      super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
     } 
    } 

    public boolean isWebViewInsideScroll() { 
     return webViewInsideScroll; 
    } 

    public void setWebViewInsideScroll(boolean webViewInsideScroll) { 
     this.webViewInsideScroll = webViewInsideScroll; 
    } 
} 

Per recuperare il valore dell'attributo è possibile utilizzare anche Stylable ma qui ho fatto senza usarlo.

ScrollableWebView webview = (ScrollableWebView) findViewById(R.id.webview); 
     webview.loadUrl("https://storage.googleapis.com/htmltestingbucket/nested_scroll_helper.html"); 

Di seguito collegamento dell'uscita

Se non volete creare un file attributo & aggiungere attributi personalizzati in res/valori/attrs.xml di quanto tu possa ignorare quel file & controllo this pastebin qui ho dato senza alcun attributo personalizzato come isWebViewInsideScroll. puoi rimuoverlo anche dal layout xml. Fatemi sapere se qualcosa.

+0

Grazie per lo sforzo e l'investimento ma la tua risposta non è buona poiché non risolve ciò che ho chiesto. in effetti gli screenshot che hai fornito lo hanno già mostrato. Basta aprire il link che ho fornito in chrome mobile o desktop, vedere come si comporta (o qualsiasi browser). Il testo nero dovrebbe rimanere in cima alla webview e stampare gli eventi di scorrimento JS ricevuti. Infatti, non è necessario che l'evento onMeasure() che hai scritto per inserire una WebView in una vista a scorrimento –

+0

funzioni perfettamente per l'integrazione all'interno una panoramica di riciclaggio. sebbene usi WebView.getSettings(). setUseWideViewPort (true) sembra rovinarlo. per me funziona benissimo grazie – Ramin

0

se si posiziona si WebView dentro ScrollView non sarà possibile ottenere html effetto di scorrimento, perché il contenuto di visualizzazione web non scorrerà (verrà posizionato piena lengtth all'interno ScrollView.)
di affrontare le tue necessità di posizionare gli elementi di cui sopra e sotto di voi puoi ascoltare lo scroll del webview e usare DragViewHelper o nineoldandroids per spostare header e footer, così l'utente penserà, sono un singolo elemento (non hai bisogno di scrollview).

webView.setOnScrollChangeListener(new View.OnScrollChangeListener() { 
    @Override 
    public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { 

     ViewHelper.setTranslationY(headerTextView, -event.getY()); 

    } 
}); 


public class ObservableWebView extends WebView { 
private OnScrollChangeListener onScrollChangeListener; 

public ObservableWebView(Context context) { 
    super(context); 
} 

public ObservableWebView(Context context, AttributeSet attrs) { 
    super(context, attrs); 
} 

public ObservableWebView(Context context, AttributeSet attrs, int defStyleAttr) { 
    super(context, attrs, defStyleAttr); 
} 

@Override 
protected void onScrollChanged(int l, int t, int oldl, int oldt) { 
    super.onScrollChanged(l, t, oldl, oldt); 
    if (onScrollChangeListener != null) { 
     onScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 
    } 
} 

public void setOnScrollChangeListener(OnScrollChangeListener onScrollChangeListener) { 
    this.onScrollChangeListener = onScrollChangeListener; 
} 

public OnScrollChangeListener getOnScrollChangeListener() { 
    return onScrollChangeListener; 
} 

public interface OnScrollChangeListener { 
    /** 
    * Called when the scroll position of a view changes. 
    * 
    * @param v   The view whose scroll position has changed. 
    * @param scrollX Current horizontal scroll origin. 
    * @param scrollY Current vertical scroll origin. 
    * @param oldScrollX Previous horizontal scroll origin. 
    * @param oldScrollY Previous vertical scroll origin. 
    */ 
    void onScrollChange(WebView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 
} 
} 

Questo esempio dovrebbe aiutare a nascondere header, ho usato nineoldandroid per esso

+0

Lo proverò, il mio problema è che intorno alla mia webview ci sono molti elementi tra cui popup ed ecc. Quindi è molto (!!!) ingombrante gestire tutto da solo. Mi chiedo se posso incapsularlo nel mio punto di vista che estende un WebView ma implementa anche tutte le funzionalità di una scrollview. Il problema è che ho bisogno di estendere anche un FrameLayout per implementare la mia vista di scorrimento .. ogni strada che sbircio diventa più disordinata .. –

+0

Ma come nota a margine, mentre apprezzo molto la tua risposta, la mia domanda è intitolata "Eventi di scorrimento HTML in una WebView Android che si trova all'interno di una ScrollView" e stai suggerendo di eliminare ScrollView. Ho messo una taglia su questo esattamente perché non voglio rilasciare ScollView ... I DO need need. La domanda è stata semplificata per mostrare solo textview sopra e sotto, la vera App è molto più complessa –

0

in realtà non è così buono porre visualizzazione scorrevole in un altro. Provate a usare questo:

<LinearLayout 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical"> 

E

<WebView 
    android:id="@+id/webview" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:layout_weight="1"/> 
0

Sembra che il modo più elegante che ho trovato per gestire questa situazione è la seguente: - Ascoltare i rotoli SrollView: È possibile utilizzare un'ObservableScrollView o chiamare setOnScrollChangeListener() dal livello di API 23 - Calcolare l'offset in pixel Y scroll - chiamare il WebView.evaluateJavascript() - pass it tutti i dettagli della manifestazione di scorrimento Così i concetti generali sta passando: "$ (document) .trigger ('scroll');" come il primo evaluateJavascript param

che sto ancora testando i dettagli e lavorando i nodi, ma sembra che il modo migliore per andare, cercherò di modificare questa risposta con più informazioni, come posso risolvere questo

Se in ogni caso ha una soluzione migliore per Vorrei sentirlo

0

ho lo stesso problema di recente e ho trovato il tuo post qui :)

ho un WebView nidificato in un ScrollVIew. E la pagina che ho caricato in WebView ha bisogno di chiamare una funzione JS quando scorre fino alla fine, ma nella vista di scorrimento, la pagina web window.onscroll = functionXXX() {} non viene mai chiamata.

Infine, devo impostare un OnScrollListener al ScrollView, e chiamare la mia funzione JS manualmente il codice qui sotto

@Override 
public void onScroll(int scrollY) { 
    if (!scrollView.canScrollVertically(scrollY)) { 
     mWebView.loadUrl("javascript:functionXXX();"); 
    } 
} 

Forse le nostre situazioni sono diverse, ma spero che vi darà qualche ispirazione u :)

+0

Ho avuto un caso diverso ma grazie per l'aggiornamento. probabilmente dovresti chiamare evaluateJavascript() al posto di loadUrl. come loadUrl attiva alcuni listener di eventi –

Problemi correlati