Desativar a rolagem no WebView?
-
22-09-2019 - |
Pergunta
Até agora, sou apenas um desenvolvedor de iPhone e agora decidi dar um giro do Android. Algo que não consegui descobrir no Android é como impedir programaticamente a rolagem em um WebView
?
Algo semelhante à prevenção dos iPhones do onTouchMove
Evento seria ótimo!
Solução
Aqui está o meu código para desativando toda a rolagem no webview:
// disable scroll on touch
webview.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return (event.getAction() == MotionEvent.ACTION_MOVE);
}
});
Para ocultar apenas as barras de rolagem, mas não desative a rolagem:
WebView.setVerticalScrollBarEnabled(false);
WebView.setHorizontalScrollBarEnabled(false);
ou você pode tentar usar Layout de coluna única Mas isso funciona apenas com páginas simples e desativa a rolagem horizontal:
//Only disabled the horizontal scrolling:
webview.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN);
Você também pode tentar Enrole sua visão da web Com rolagem verticalmente ScrollView e desativar toda a rolagem no 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>
E definir
webview.setScrollContainer(false);
Não se esqueça de adicionar o webview.setOnTouchListener(...)
Código acima para desativar toda a rolagem no WebView. O vertical ScrollView permitirá a rolagem do conteúdo da WebView.
Outras dicas
Não sei se você ainda precisa ou não, mas aqui está a solução:
appView = (WebView) findViewById(R.id.appView);
appView.setVerticalScrollBarEnabled(false);
appView.setHorizontalScrollBarEnabled(false);
Fazendo o WebView
Ignore Motion Events é o caminho errado para fazer isso. E se o WebView
precisa ouvir sobre esses eventos?
Em vez disso, subclasse WebView
e substituir os métodos de rolagem não privados.
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
}
}
Se você olhar para o fonte por WebView
você pode ver isso onTouchEvent
chamadas doDrag
que chama Overcrollby.
Adicionar os detalhes da margem ao corpo impedirá a rolagem se o seu conteúdo for adequado, como assim:
<body leftmargin="0" topmargin="0" rightmargin="0" bottommargin="0">
Fácil o suficiente e muito menos código + sobrecarga de bug :)
Defina um ouvinte no seu WebView:
webView.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
return(event.getAction() == MotionEvent.ACTION_MOVE));
}
});
Eu não tentei isso, pois ainda não encontrei esse problema, mas talvez você possa superar a função Onscroll?
@Override
public void scrollTo(int x, int y){
super.scrollTo(0,y);
}
Minha solução suja, mas fácil de implementar e bem funcionar:
Basta colocar o WebView dentro de um scrollView. Torne a WebView ser muito maior que o possível conteúdo (em uma ou ambas as dimensões, dependendo dos requisitos). ..e configure a (s) barra de rolagem do scrollView como desejar.
Exemplo para desativar a barra de rolagem horizontal em um 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>
Eu espero que isso ajude ;)
Para desativar a rolagem, use isso
webView.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event)
{
return (event.getAction() == MotionEvent.ACTION_MOVE);
}
});
Isso pode não ser a fonte do seu problema, mas passei horas tentando rastrear por que meu aplicativo funcionou bem no iPhone, porque o navegador Android vomitou constantemente as barras de rolagem vertical/horizontal e realmente move a página. Eu tinha uma etiqueta corporal HTML com altura e largura definidas para 100%, e o corpo estava cheio de várias etiquetas em diferentes locais. Não importa o que eu tentei, os navegadores do Android mostrariam suas barras de rolagem e moveriam a página um pouco, principalmente ao fazer um golpe rápido. A solução que funcionou para mim sem ter que fazer nada em um apk foi adicionar o seguinte à tag corporal:
leftmargin="0" topmargin="0"
Parece que as margens padrão para a etiqueta corporal estavam sendo aplicadas no dróide, mas ignoradas no iPhone
Eu resolvi a lama e a rolagem automática por:
webView.setFocusable(false);
webView.setFocusableInTouchMode(false);
No entanto, se ainda não funcionar por algum motivo, basta fazer uma aula que estende a WebView e coloque esse método:
// disable scroll on touch
setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return (event.getAction() == MotionEvent.ACTION_MOVE);
}
});
Estou sugerindo estender a WebView, a fim de fornecer controle mais eficaz, como desativar/habilitar swipes, ativar/desativar toques, ouvintes, transições de controle, animações, definir configurações internamente assim ..
Se você subclasse WebView, você pode simplesmente substituir o OnTouchEvent para filtrar os eventos de movimentação que acionam a rolagem.
public class SubWebView extends WebView {
@Override
public boolean onTouchEvent (MotionEvent ev) {
if(ev.getAction() == MotionEvent.ACTION_MOVE) {
postInvalidate();
return true;
}
return super.onTouchEvent(ev);
}
...
Estudando as respostas acima quase funcionou para mim ... mas ainda tinha um problema que eu poderia 'arremessar' a vista no 2.1 (parecia estar corrigido com 2.2 e 2.3).
Aqui está minha solução final
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);
}
}
Esta deve ser a resposta completa. Conforme sugerido por @gdanger. Estenda a WebView para substituir os métodos de rolagem e incorporar o WebView personalizado no 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();
}
}
}
E depois incorpore o arquivo de layout da seguinte maneira
<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"/>
Então, na atividade, use alguns métodos adicionais para desativar as barras de rolagem também.
ScrollDisabledWebView webView = (ScrollDisabledWebView) findViewById(R.id.webView);
webView.setVerticalScrollBarEnabled(false);
webView.setHorizontalScrollBarEnabled(false);
Apenas use android:focusableInTouchMode="false"
Nas suas WebView.