Until now I have been an iPhone developer only and now I have decided to give Android a whirl. Something I haven't been able to figure out on Android is how to programmatically prevent scrolling in a WebView
?
Something similar to iPhones prevention of the onTouchMove
event would be great!
Here is my code for disabling all scrolling in webview:
// disable scroll on touch
webview.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return (event.getAction() == MotionEvent.ACTION_MOVE);
}
});
To only hide the scrollbars, but not disable scrolling:
WebView.setVerticalScrollBarEnabled(false);
WebView.setHorizontalScrollBarEnabled(false);
or you can try using single column layout but this only works with simple pages and it disables horizontal scrolling:
//Only disabled the horizontal scrolling:
webview.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN);
You can also try to wrap your webview with vertically scrolling scrollview and disable all scrolling on the webview:
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scrollbars="vertical" >
<WebView
android:id="@+id/mywebview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scrollbars="none" />
</ScrollView>
And set
webview.setScrollContainer(false);
Don't forget to add the webview.setOnTouchListener(...)
code above to disable all scrolling in the webview. The vertical ScrollView will allow for scrolling of the WebView's content.
I don't know if you still need it or not, but here is the solution:
appView = (WebView) findViewById(R.id.appView);
appView.setVerticalScrollBarEnabled(false);
appView.setHorizontalScrollBarEnabled(false);
Making the WebView
ignore motion events is the wrong way to go about it. What if the WebView
needs to hear about these events?
Instead subclass WebView
and override the non-private scroll methods.
public class NoScrollWebView extends WebView {
...
@Override
public boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY,
int scrollRangeX, int scrollRangeY, int maxOverScrollX,
int maxOverScrollY, boolean isTouchEvent) {
return false;
}
@Override
public void scrollTo(int x, int y) {
// Do nothing
}
@Override
public void computeScroll() {
// Do nothing
}
}
If you look at the source for WebView
you can see that onTouchEvent
calls doDrag
which calls overScrollBy.
Adding the margin details to the body will prevent scrolling if your content properly wraps, as so:
<body leftmargin="0" topmargin="0" rightmargin="0" bottommargin="0">
Easy enough, and a lot less code + bug overhead :)
Set a listener on your WebView:
webView.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
return(event.getAction() == MotionEvent.ACTION_MOVE));
}
});
I haven't tried this as I have yet to encounter this problem, but perhaps you could overrive the onScroll function?
@Override
public void scrollTo(int x, int y){
super.scrollTo(0,y);
}
My dirty, but easy-to-implement and well working solution:
Simply put the webview inside a scrollview. Make the webview to be far too bigger than the possible content (in one or both dimensions, depending on the requirements). ..and set up the scrollview's scrollbar(s) as you wish.
Example to disable the horizontal scrollbar on a webview:
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scrollbars="vertical"
>
<WebView
android:id="@+id/mywebview"
android:layout_width="1000dip"
android:layout_height="fill_parent"
/>
</ScrollView>
I hope this helps ;)
To Disable scroll use this
webView.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event)
{
return (event.getAction() == MotionEvent.ACTION_MOVE);
}
});
This may not be the source of your problem but I have spent hours trying to track down why my application that worked fine on the iphone cause the android browser to constantly throw up the vertical/horizontal scrollbars and actually move the page. I had an html body tag with height and width set to 100%, and the body was full of various tags in different locations. No matter what I tried, the android browsers would show their scroll bars and move the page just a little bit, particularly when doing a fast swipe. The solution that worked for me without having to do anything in an APK was to add the following to the body tag:
leftmargin="0" topmargin="0"
It seems the default margins for body tag were being applied on the droid but ignored on the iphone
I resolved the flicker and auto-scroll by:
webView.setFocusable(false);
webView.setFocusableInTouchMode(false);
However if it still does not work for some reason, simply make a class that extends WebView, and put this method on it:
// disable scroll on touch
setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return (event.getAction() == MotionEvent.ACTION_MOVE);
}
});
I am suggesting to extend WebView, in order to provide more effective control, like disable/enable swipes, enable/disable touches, listeners, control transitions, animations, define settings internally so on..
If you subclass Webview, you can simply override onTouchEvent to filter out the move-events that trigger scrolling.
public class SubWebView extends WebView {
@Override
public boolean onTouchEvent (MotionEvent ev) {
if(ev.getAction() == MotionEvent.ACTION_MOVE) {
postInvalidate();
return true;
}
return super.onTouchEvent(ev);
}
...
studying the above answers almost worked for me ... but I still had a problem that I could 'fling' the view on 2.1 (seemed to be fixed with 2.2 & 2.3).
here is my final solution
public class MyWebView extends WebView
{
private boolean bAllowScroll = true;
@SuppressWarnings("unused") // it is used, just java is dumb
private long downtime;
public MyWebView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public void setAllowScroll(int allowScroll)
{
bAllowScroll = allowScroll!=0;
if (!bAllowScroll)
super.scrollTo(0,0);
setHorizontalScrollBarEnabled(bAllowScroll);
setVerticalScrollBarEnabled(bAllowScroll);
}
@Override
public boolean onTouchEvent(MotionEvent ev)
{
switch (ev.getAction())
{
case MotionEvent.ACTION_DOWN:
if (!bAllowScroll)
downtime = ev.getEventTime();
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (!bAllowScroll)
{
try {
Field fmNumSamples = ev.getClass().getDeclaredField("mNumSamples");
fmNumSamples.setAccessible(true);
Field fmTimeSamples = ev.getClass().getDeclaredField("mTimeSamples");
fmTimeSamples.setAccessible(true);
long newTimeSamples[] = new long[fmNumSamples.getInt(ev)];
newTimeSamples[0] = ev.getEventTime()+250;
fmTimeSamples.set(ev,newTimeSamples);
} catch (Exception e) {
e.printStackTrace();
}
}
break;
}
return super.onTouchEvent(ev);
}
@Override
public void flingScroll(int vx, int vy)
{
if (bAllowScroll)
super.flingScroll(vx,vy);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt)
{
if (bAllowScroll)
super.onScrollChanged(l, t, oldl, oldt);
else if (l!=0 || t!=0)
super.scrollTo(0,0);
}
@Override
public void scrollTo(int x, int y)
{
if (bAllowScroll)
super.scrollTo(x,y);
}
@Override
public void scrollBy(int x, int y)
{
if (bAllowScroll)
super.scrollBy(x,y);
}
}
// Disable all scrolling
WebView.setVerticalScrollBarEnabled(false);
WebView.setHorizontalScrollBarEnabled(false);
webview.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return (event.getAction() == MotionEvent.ACTION_MOVE);
}
});
// Disable horizontal scroll only
WebView.setHorizontalScrollBarEnabled(false);
webview.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN);
// Disable vertical scroll only
WebView.setVerticalScrollBarEnabled(false);
webview.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (action)
{
case (MotionEvent.ACTION_DOWN):
/**
* get Y position
*/
start_y = event.getY();
break;
case (MotionEvent.ACTION_MOVE):
/*Disable vertical scrolling*/
if (start_y-event.getY()>THRESHOLD_VALUE || start_y- event.getY()<-THRESHOLD_VALUE)
return true;
break;
}
}
});
In my case threshold value was 20
This should be the complete answer. As suggested by @GDanger . Extend WebView to override the scroll methods and embed the custom webview within layout xml.
public class ScrollDisabledWebView extends WebView {
private boolean scrollEnabled = false;
public ScrollDisabledWebView(Context context) {
super(context);
initView(context);
}
public ScrollDisabledWebView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
initView(context);
}
// this is important. Otherwise it throws Binary Inflate Exception.
private void initView(Context context) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY,
int scrollRangeX, int scrollRangeY, int maxOverScrollX,
int maxOverScrollY, boolean isTouchEvent) {
if (scrollEnabled) {
return super.overScrollBy(deltaX, deltaY, scrollX, scrollY,
scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
}
return false;
}
@Override
public void scrollTo(int x, int y) {
if (scrollEnabled) {
super.scrollTo(x, y);
}
}
@Override
public void computeScroll() {
if (scrollEnabled) {
super.computeScroll();
}
}
}
And then embed in layout file as follows
<com.sample.apps.ScrollDisabledWebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
tools:context="com.sample.apps.HomeActivity"/>
Then in the Activity, use some additional methods for disabling scrollbars too.
ScrollDisabledWebView webView = (ScrollDisabledWebView) findViewById(R.id.webView);
webView.setVerticalScrollBarEnabled(false);
webView.setHorizontalScrollBarEnabled(false);
Just use android:focusableInTouchMode="false"
on your webView.
来源:https://stackoverflow.com/questions/2527899/disable-scrolling-in-webview