Desativar rolagem no webview?

86

Até agora, eu era apenas um desenvolvedor de iPhone e agora decidi dar uma olhada no Android. Algo que não consegui descobrir no Android é como evitar programaticamente a rolagem em um WebView?

Algo parecido com a prevenção de iPhones do onTouchMoveevento seria ótimo!

Jake Sankey
fonte

Respostas:

179

Aqui está o meu código para desativar 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 desativar a rolagem:

WebView.setVerticalScrollBarEnabled(false);
WebView.setHorizontalScrollBarEnabled(false);

ou você pode tentar usar o layout de coluna única, mas isso só funciona 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 envolver sua visualização da web com rolagem vertical de rolagem e desativar toda a rolagem na visualização da web:

<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 na visualização da web. O ScrollView vertical permitirá a rolagem do conteúdo do WebView.

peceps
fonte
funciona bem, mas após alguns segundos causa travamento no Samsung i5700 spica em /system/lib/libwebcore.so.
Lukas de
LayoutAlgorithm.SINGLE_COLUMN ou webview.setOnTouchListener?
peceps
3
Se você colocar um WebView em um ScrollView, defina o atributo android: isScrollContainer do WebView como "false" em vez de definir android: scrollbars como "none". Isso tem o efeito de desabilitar completamente o manuseio de rolagem da visualização da web e permite que ela se expanda de acordo com seu conteúdo. A rolagem será então tratada exclusivamente pela ScrollView pai.
BladeCoder
1
Se você precisar lidar com MotionEvent.ACTION_MOVEeventos em seu, WebViewveja minha resposta abaixo.
GDanger
1
Ignorar o ACTION_MOVEno setOnTouchListenerevento tem alguns efeitos colaterais, então eu NÃO recomendaria esta resposta; 1. Deslizamentos rápidos são contados como onclickeventos na página. 2. Evita o estouro de rolagem de elementos na página, isso pode ser necessário para uma interação adequada, dependendo do site. 3. O touchmoveevento JS . @GDanger tem a resposta correta que está substituindo o overScrollByestendendo o, WebViewpois não tem efeitos colaterais, apenas evita a rolagem da página. stackoverflow.com/a/26129301/1244574
jkasten
22

Não sei se ainda precisa ou não, mas aqui está a solução:

appView = (WebView) findViewById(R.id.appView); 
appView.setVerticalScrollBarEnabled(false);
appView.setHorizontalScrollBarEnabled(false);
umar
fonte
18
Está bem. isso desativa as barras de rolagem, mas não impede a rolagem arrastando. Parece que o html deve caber também ...
rdmueller
Se você está projetando suas páginas da web apenas para visualização na web do Android, então eu recomendo fazer suas páginas na tabela. A largura deve ser como largura = "100%" e igual para a altura. então não haverá mais nenhum arrastamento.
umar de
largura = 100% nem sempre funciona, por exemplo: stackoverflow.com/questions/6460871/…
NoBugs
incrível .. é o que eu preciso. Obrigado
Peter
21

Fazer WebViewignorar eventos de movimento é a maneira errada de fazer isso. E se WebViewprecisar ouvir sobre esses eventos?

Em vez disso, crie uma subclasse WebViewe substitua 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 a fonte para WebViewque você pode ver que as onTouchEventchamadas doDragque chama overScrollBy .

GDanger
fonte
1
Se você precisar desabilitar / habilitar a rolagem programaticamente, dê uma olhada nesta essência que criei.
GDanger
1
Seu método funciona para mim. E eu concordo totalmente com você. No meu caso, não consigo arrastar a barra de progresso de vídeo e áudio incorporada ao WebView usando a resposta de aceitação.
codezjx
Esta é a resposta certa. Embora precise de alguns ajustes nos construtores de substituição. Por favor, olhe minha resposta completa abaixo. stackoverflow.com/a/51936944/393502
Vansi
13

Adicionar os detalhes da margem ao corpo impedirá a rolagem se o conteúdo for agrupado corretamente, da seguinte forma:

<body leftmargin="0" topmargin="0" rightmargin="0" bottommargin="0">

Fácil, e muito menos código + sobrecarga de bug :)

Auri Rahimzadeh
fonte
1
Brilhante! 1 para uma solução simples apenas de HTML. Às vezes eu gostaria, o layout no Android era tão fácil quanto css ...
Pritesh Desai
Parece bom no navegador padrão do Android, mas não parece funcionar no Firefox (Fennec) ... apesar de não haver nada para rolar horizontalmente, o Firefox ainda me permite rolar para a direita até o ponto onde todo o conteúdo rolou fora da tela.
Michael,
1
Não funciona no WebView moderno (Android 5 e superior)
Roel
8

Defina um ouvinte em seu WebView:

webView.setOnTouchListener(new View.OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) {
                return(event.getAction() == MotionEvent.ACTION_MOVE));
            }
        });
user322987
fonte
3
Há um parêntese extra no final da returnlinha. Além disso, isso quebra a tela HTML5 e os eventos de toque do JavaScript.
Rohan Singh,
Isso certamente o desativa, mas como faço para matar o ouvinte mais tarde para reativar a entrada? Eu tentei event.getAction() != MotionEvent.ACTION_MOVEtão bem quantoreturn true
CQM
O caso padrão de "não fazer nada" é return falsenão return true.
Matthew leu
6

Não tentei fazer isso porque ainda não encontrei esse problema, mas talvez você possa sobrescrever a função onScroll?

@Override
public void scrollTo(int x, int y){
super.scrollTo(0,y);
}
ZeroTruths
fonte
Isso é o que chamamos de Jugaad na Índia ... embora tenha funcionado muito bem
R4chi7
4

Minha solução suja, mas fácil de implementar e que funciona bem:

Basta colocar o webview dentro de um scrollview. Faça com que a webview seja muito maior do que o conteúdo possível (em uma ou ambas as dimensões, dependendo dos requisitos). ..e configure a (s) barra (s) de rolagem da visualização de rolagem como desejar.

Exemplo para desativar a barra de rolagem horizontal em uma visualização da web:

<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 ;)

user289463
fonte
Sim, mas o tamanho do pergaminho não seria muito grande com muito espaço em branco na parte inferior?
Rafael Sanches
1
E se a largura do conteúdo for 1001 dp?
Waltsu de
3

Resolvi a tremulação e a rolagem automática:

webView.setFocusable(false);
webView.setFocusableInTouchMode(false);

No entanto, se por algum motivo ainda não funcionar, basta fazer uma classe que estenda WebView e colocar este método nela:

// 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 o WebView, a fim de fornecer um controle mais eficaz, como desabilitar / habilitar deslizamentos, habilitar / desabilitar toques, ouvintes, controlar transições, animações, definir configurações internamente e assim por diante.

Abhinav Saxena
fonte
3

Para desativar a rolagem, use este

webView.setOnTouchListener(new View.OnTouchListener() {
    public boolean onTouch(View v, MotionEvent event) 
    {
        return (event.getAction() == MotionEvent.ACTION_MOVE);
    }
});
Saba Chaudry
fonte
2

Esta pode não ser a origem do seu problema, mas passei horas tentando rastrear por que meu aplicativo funcionou bem no iphone faz com que o navegador Android erga constantemente as barras de rolagem vertical / horizontal e realmente mova a página. Eu tinha uma tag de corpo html com altura e largura definidas em 100%, e o corpo estava cheio de várias tags em locais diferentes. Não importava o que eu tentasse, os navegadores Android mostravam suas barras de rolagem e moviam a página um pouco, principalmente ao deslizar rapidamente. A solução que funcionou para mim sem ter que fazer nada em um APK foi adicionar o seguinte à tag do corpo:

leftmargin="0" topmargin="0"

Parece que as margens padrão para a etiqueta do corpo foram aplicadas no droid, mas ignoradas no iphone

Robert Etheredge
fonte
1

Se você criar uma subclasse de Webview, poderá simplesmente substituir 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);
    }
    ...
mischka
fonte
0

estudar as respostas acima quase funcionou para mim ... mas eu ainda tinha o problema de poder 'lançar' a visão no 2.1 (parecia estar corrigido no 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);
}
}
SteelBytes
fonte
Substituir o método onScrollChanged () funciona para mim. No meu caso, não consigo arrastar a barra de progresso de vídeo e áudio incorporada ao WebView usando a resposta de aceitação. Muito obrigado!
codezjx
-1

Esta deve ser a resposta completa. Conforme sugerido por @GDanger. Estenda o WebView para substituir os métodos de rolagem e incorporar o WebView personalizado no XML de layout.

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, em seguida, incorpore no arquivo de layout da seguinte forma

<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"/>

Em seguida, 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);
Vansi
fonte
-3

Basta usar android:focusableInTouchMode="false"no seu webView .

Socratex
fonte