What I have:
Right now I have a Scroll view as a parent. Inside this scroll view, I am using a WebView that loads a URL and then shows text in it.
Here is my xml:
<ScrollView
android:id="@+id/parentScroll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/Heading" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp" >
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="@drawable/webview" />
</RelativeLayout>
</ScrollView>
What I want:
I want to scroll webView inside it. When I touch the webView, unfortunately the parent scroll view gets called.
I have to keep Parent scroll view also but besides this I want to scroll WebView content inside it when I touch on webView.
How can I do this?
Create a Custom Touch Intercepting Webview
CustomWebview.java
package com.mypackage.common.custom.android.widgets
public class CustomWebview extends WebView {
public CustomWebview(Context context) {
super(context);
}
public CustomWebview(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomWebview(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean onTouchEvent(MotionEvent event){
requestDisallowInterceptTouchEvent(true);
return super.onTouchEvent(event);
}
}
in layout.xml
<com.package.custom.widgets.CustomWebview
android:id="@+id/view_extra"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
According to Android design documents you should never put a scrolling container inside a scrolling container if they scroll the same direction. It's not meant to handle such a thing.
I had the same problem. You should set your webView Height equal as its content. for this do this:
add this lines to your onCreate method in Activity:
webView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
webView.loadUrl("javascript:MyApp.resize(document.body.getBoundingClientRect().height)");
super.onPageFinished(view, url);
}
});
webView.addJavascriptInterface(this, "MyApp");
and add this method to your activity:
@JavascriptInterface
public void resize(final float height) {
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
webView.setLayoutParams(new LinearLayout.LayoutParams(getResources().getDisplayMetrics().widthPixels, (int) (height * getResources().getDisplayMetrics().density)));
}
});
}
Nested scrollable widgets are generally discouraged. It is a confusing user experience because it's easy to scroll the wrong thing. Say I intend to scroll the outer scroll region but I touched the inner region first and flinged really hard. Then the inner one will scroll and I'll be like huh? Why didn't it scroll?
Even if one scrolls horizontal and the other is vertical the gesture recognizers might confuse one for another so you get the same effect. It's a valid use case but it's still iffy and I'd avoid it. (IE: Humans don't perfectly swipe vertically and horizontally properly, it's usually with an angle.)
I would push to change the design to break out the scrollable areas. Ideally 1 scrollable item per page. Even propose one yourself and provide to the designer both experiences and see which one they choose.
To express how this will suck. Look at this example. This isn't a solution but just to show the experience.
<ScrollView
android:id="@+id/parentScroll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/Heading" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent" android:orientation="vertical"
android:padding="5dp" >
<TextView
android:id="@+id/topText"
android:layout_width="match_parent"
android:layout_height="1000dp"
android:text="@string/lotsoftext" />
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="@drawable/webview" />
<TextView
android:id="@+id/topText"
android:layout_width="match_parent"
android:layout_height="1000dp"
android:text="@string/lotsoftext" />
</RelativeLayout>