【发布时间】:2010-03-27 02:27:21
【问题描述】:
到目前为止,我只是一名 iPhone 开发人员,现在我决定试一试 Android。我在 Android 上无法弄清楚的事情是如何以编程方式防止在 WebView 中滚动?
类似于 iPhone 防止 onTouchMove 事件的东西会很棒!
【问题讨论】:
标签: android android-webview android-scroll android-scrollbar
到目前为止,我只是一名 iPhone 开发人员,现在我决定试一试 Android。我在 Android 上无法弄清楚的事情是如何以编程方式防止在 WebView 中滚动?
类似于 iPhone 防止 onTouchMove 事件的东西会很棒!
【问题讨论】:
标签: android android-webview android-scroll android-scrollbar
这是我在 webview 中禁用所有滚动的代码:
// disable scroll on touch
webview.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return (event.getAction() == MotionEvent.ACTION_MOVE);
}
});
仅隐藏滚动条,但不禁用滚动:
WebView.setVerticalScrollBarEnabled(false);
WebView.setHorizontalScrollBarEnabled(false);
或者您可以尝试使用单列布局,但这仅适用于简单页面并且会禁用水平滚动:
//Only disabled the horizontal scrolling:
webview.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN);
您也可以尝试使用垂直滚动的滚动视图包装您的 webview 并禁用 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>
设置
webview.setScrollContainer(false);
不要忘记在上面添加webview.setOnTouchListener(...) 代码以禁用 web 视图中的所有滚动。垂直 ScrollView 将允许滚动 WebView 的内容。
【讨论】:
WebView 中处理MotionEvent.ACTION_MOVE 事件,请参阅下面的答案。
setOnTouchListener 事件上的ACTION_MOVE 有一些副作用,所以我不推荐这个答案; 1. 快速滑动被视为页面的onclick 事件。 2. 防止页面上的元素溢出滚动,这可能需要根据站点进行适当的交互。 3. JStouchmove事件。 @GDanger 的正确答案是通过扩展 WebView 来覆盖 overScrollBy,因为它没有其他副作用,只是防止页面滚动。 stackoverflow.com/a/26129301/1244574
让WebView 忽略运动事件是错误的做法。如果WebView 需要听到这些事件怎么办?
改为子类WebView 并覆盖非私有滚动方法。
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
}
}
如果您查看source 的WebView,您会看到onTouchEvent 调用doDrag,后者调用overScrollBy。
【讨论】:
我不知道你是否还需要它,但这里是解决方案:
appView = (WebView) findViewById(R.id.appView);
appView.setVerticalScrollBarEnabled(false);
appView.setHorizontalScrollBarEnabled(false);
【讨论】:
如果您的内容正确换行,将边距详细信息添加到正文将阻止滚动,如下所示:
<body leftmargin="0" topmargin="0" rightmargin="0" bottommargin="0">
足够简单,而且代码和错误开销要少得多:)
【讨论】:
在你的 WebView 上设置一个监听器:
webView.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
return(event.getAction() == MotionEvent.ACTION_MOVE));
}
});
【讨论】:
return 行的末尾有一个额外的括号。这也破坏了 HTML5 画布和 JavaScript 触摸事件。
event.getAction() != MotionEvent.ACTION_MOVE 和return true
return false,而不是return true。
我没有尝试过,因为我还没有遇到这个问题,但也许你可以覆盖 onScroll 函数?
@Override
public void scrollTo(int x, int y){
super.scrollTo(0,y);
}
【讨论】:
我的肮脏但易于实施且运行良好的解决方案:
只需将 webview 放在滚动视图中。使 webview 远大于可能的内容(在一个或两个维度上,取决于要求)。 ..并根据需要设置滚动视图的滚动条。
在 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>
我希望这会有所帮助;)
【讨论】:
我通过以下方式解决了闪烁和自动滚动问题:
webView.setFocusable(false);
webView.setFocusableInTouchMode(false);
但是如果由于某种原因仍然无法正常工作,只需创建一个扩展 WebView 的类,并将此方法放在上面:
// disable scroll on touch
setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return (event.getAction() == MotionEvent.ACTION_MOVE);
}
});
我建议扩展 WebView,以提供更有效的控制,例如禁用/启用滑动、启用/禁用触摸、侦听器、控制转换、动画、内部定义设置等等..
【讨论】:
要禁用滚动使用这个
webView.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event)
{
return (event.getAction() == MotionEvent.ACTION_MOVE);
}
});
【讨论】:
这可能不是您的问题的根源,但我花了几个小时试图找出为什么我的应用程序在 iphone 上运行良好导致 android 浏览器不断抛出垂直/水平滚动条并实际移动页面。我有一个高度和宽度设置为 100% 的 html 正文标签,并且正文在不同位置充满了各种标签。无论我尝试什么,android 浏览器都会显示它们的滚动条并稍微移动页面,尤其是在快速滑动时。无需在 APK 中执行任何操作即可为我工作的解决方案是将以下内容添加到 body 标记中:
leftmargin="0" topmargin="0"
似乎body标签的默认边距被应用在机器人上,但在iphone上被忽略了
【讨论】:
如果您子类化 Webview,您可以简单地重写 onTouchEvent 以过滤掉触发滚动的移动事件。
public class SubWebView extends WebView {
@Override
public boolean onTouchEvent (MotionEvent ev) {
if(ev.getAction() == MotionEvent.ACTION_MOVE) {
postInvalidate();
return true;
}
return super.onTouchEvent(ev);
}
...
【讨论】:
研究上述答案几乎对我有用......但我仍然有一个问题,我可以在 2.1 上“抛出”观点(似乎已在 2.2 和 2.3 中修复)。
这是我的最终解决方案
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);
}
}
【讨论】:
这应该是完整的答案。正如@GDanger 所建议的那样。 扩展 WebView 以覆盖滚动方法并将自定义 webview 嵌入到布局 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();
}
}
}
然后按如下方式嵌入到布局文件中
<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"/>
然后在 Activity 中,使用一些额外的方法来禁用滚动条。
ScrollDisabledWebView webView = (ScrollDisabledWebView) findViewById(R.id.webView);
webView.setVerticalScrollBarEnabled(false);
webView.setHorizontalScrollBarEnabled(false);
【讨论】: