Wyłączyć przewijanie w widoku internetowym?

86

Do tej pory byłem tylko programistą iPhone'a, a teraz postanowiłem dać Androidowi wir. Coś, czego nie udało mi się znaleźć w systemie Android, to programowe zapobieganie przewijaniu w WebView?

Coś podobnego do zapobiegania onTouchMovezdarzeniu na iPhone'ach byłoby super!

Jake Sankey
źródło

Odpowiedzi:

179

Oto mój kod do wyłączania całego przewijania w widoku internetowym:

  // disable scroll on touch
  webview.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
      return (event.getAction() == MotionEvent.ACTION_MOVE);
    }
  });

Aby tylko ukryć paski przewijania, ale nie wyłączać przewijania:

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

lub możesz spróbować użyć układu jednokolumnowego, ale działa to tylko z prostymi stronami i wyłącza przewijanie w poziomie:

   //Only disabled the horizontal scrolling:
   webview.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN);

Możesz także spróbować owinąć widok sieciowy widokiem przewijanym w pionie i wyłączyć całe przewijanie widoku internetowego:

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

I nastaw

webview.setScrollContainer(false);

Nie zapomnij dodać webview.setOnTouchListener(...)powyższego kodu, aby wyłączyć przewijanie w widoku sieciowym. Pionowy ScrollView pozwoli na przewijanie zawartości WebView.

peceps
źródło
działa dobrze, ale po kilku sekundach powoduje awarię na Samsungu i5700 spica w /system/lib/libwebcore.so.
Lukas
LayoutAlgorithm.SINGLE_COLUMN czy webview.setOnTouchListener?
peceps
3
Jeśli umieścisz WebView w ScrollView, ustaw atrybut android: isScrollContainer WebView na „false” zamiast ustawiania android: scrollbars na „none”. Powoduje to całkowite wyłączenie obsługi przewijania widoku internetowego i umożliwia jego rozszerzanie zgodnie z zawartością. Przewijanie będzie wtedy obsługiwane wyłącznie przez element nadrzędny ScrollView.
BladeCoder
1
Jeśli chcesz obsłużyć MotionEvent.ACTION_MOVEzdarzenia w swoim, WebViewzobacz moją odpowiedź poniżej.
GDanger,
1
Ignorując ACTION_MOVEna setOnTouchListenerrazie ma pewne skutki uboczne, więc nie polecam tę odpowiedź; 1. Szybkie przesunięcia są liczone jako onclickzdarzenia na stronie. 2. Zapobiega przewijaniu się elementów strony przez przepełnienie, może to być potrzebne do właściwej interakcji w zależności od witryny. 3. touchmoveWydarzenie JS . @GDanger ma poprawną odpowiedź, która zastępuje overScrollByrozszerzenie przez rozszerzenie, WebViewponieważ nie ma innych efektów ubocznych, po prostu zapobiega przewijaniu strony. stackoverflow.com/a/26129301/1244574
jkasten
22

Nie wiem, czy nadal tego potrzebujesz, czy nie, ale oto rozwiązanie:

appView = (WebView) findViewById(R.id.appView); 
appView.setVerticalScrollBarEnabled(false);
appView.setHorizontalScrollBarEnabled(false);
umar
źródło
18
ok. powoduje to wyłączenie pasków przewijania, ale nie zapobiega przewijaniu przez przeciąganie. Wygląda na to, że html też musi pasować ...
rdmueller
Jeśli projektujesz swoje strony internetowe tylko dla Androida, polecam umieścić swoje strony internetowe w tabeli. Szerokość powinna być taka sama jak width = "100%" i taka sama dla wysokości. więc nie będzie już ciągnięcia.
umar
width = 100% nie zawsze działa, na przykład: stackoverflow.com/questions/6460871/…
NoBugs
niesamowite ... to jest to, czego potrzebuję. Dziękuję
Peter,
21

Dokonywanie WebViewignorować zdarzeń ruchu jest niewłaściwy sposób się do tego zabrać. A jeśli WebViewtrzeba usłyszeć o tych wydarzeniach?

Zamiast podklasy WebViewi nadpisania nieprywatnych metod przewijania.

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
    }
}

Jeśli spojrzeć na źródła dla WebViewwidać, że onTouchEventrozmowy doDrag, które nazywa overScrollBy .

GDanger
źródło
1
Jeśli chcesz programowo wyłączyć / włączyć przewijanie, spójrz na tę treść, którą utworzyłem.
GDanger
1
Twoja metoda działa na mnie. I całkiem się z tobą zgadzam. W moim przypadku nie mogę przeciągnąć paska postępu wideo i audio osadzonego w WebView, używając odpowiedzi akceptuj.
codezjx
To jest właściwa odpowiedź. Chociaż wymaga pewnych poprawek w nadpisujących konstruktorach. Proszę spojrzeć na moją pełną odpowiedź poniżej. stackoverflow.com/a/51936944/393502
Vansi,
13

Dodanie szczegółów marginesów do treści zapobiegnie przewijaniu, jeśli zawartość zostanie odpowiednio opakowana, tak jak:

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

Dość łatwo i dużo mniej kodu + narzut na błędy :)

Auri Rahimzadeh
źródło
1
Znakomity! +1 za proste rozwiązanie oparte tylko na HTML. Czasami chciałbym, żeby układ na
Androidzie
Wygląda dobrze w standardowej przeglądarce Androida, ale wydaje się, że nie działa w Firefoksie (Fennec) ... mimo że nie ma nic do przewijania w poziomie, Firefox nadal pozwala mi przewijać w prawo do punktu, w którym cała zawartość została przewinięta z ekranu.
Michael,
1
Nie działa na nowoczesnym WebView (Android 5 i nowszy)
Roel,
8

Ustaw odbiornik w swoim WebView:

webView.setOnTouchListener(new View.OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) {
                return(event.getAction() == MotionEvent.ACTION_MOVE));
            }
        });
user322987
źródło
3
Na końcu returnlinii znajduje się dodatkowy nawias . Również to psuje zdarzenia dotykowe HTML5 Canvas i JavaScript.
Rohan Singh
To z pewnością ją wyłącza, ale jak później zabić słuchacza, aby ponownie włączyć wejście? Próbowałem event.getAction() != MotionEvent.ACTION_MOVErównieżreturn true
CQM
Średnia „robić nic” sprawa jest return false, nie return true.
Matthew Przeczytaj
6

Nie próbowałem tego, ponieważ jeszcze nie napotkałem tego problemu, ale może mógłbyś przesłonić funkcję onScroll?

@Override
public void scrollTo(int x, int y){
super.scrollTo(0,y);
}
ZeroTruths
źródło
To jest to, co w Indiach nazywamy Jugaad ... chociaż działało dobrze
R4chi7
4

Moje brudne, ale łatwe do wdrożenia i dobrze działające rozwiązanie:

Po prostu umieść widok internetowy w widoku przewijanym. Ustaw widok sieciowy tak, aby był o wiele za większy niż możliwa zawartość (w jednym lub obu wymiarach, w zależności od wymagań). ..i skonfiguruj paski przewijania widoku przewijania, jak chcesz.

Przykład wyłączenia poziomego paska przewijania w widoku sieci 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>

Mam nadzieję, że to pomoże ;)

user289463
źródło
tak, ale wtedy rozmiar zwoju nie byłby zbyt duży z dużą ilością spacji na dole?
Rafael Sanches
1
Co się stanie, jeśli szerokość treści wyniesie 1001dp?
Waltsu
3

Rozwiązałem migotanie i automatyczne przewijanie przez:

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

Jeśli jednak z jakiegoś powodu nadal nie działa, po prostu utwórz klasę rozszerzającą WebView i umieść na niej tę metodę:

// disable scroll on touch
  setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
      return (event.getAction() == MotionEvent.ACTION_MOVE);
    }
  });

Sugeruję rozszerzenie WebView, aby zapewnić bardziej efektywną kontrolę, taką jak wyłączanie / włączanie przesuwania, włączanie / wyłączanie dotknięć, słuchaczy, przejścia kontrolne, animacje, definiowanie ustawień wewnętrznie itd.

Abhinav Saxena
źródło
3

Aby wyłączyć przewijanie, użyj tego

webView.setOnTouchListener(new View.OnTouchListener() {
    public boolean onTouch(View v, MotionEvent event) 
    {
        return (event.getAction() == MotionEvent.ACTION_MOVE);
    }
});
Saba Chaudry
źródło
2

Może to nie być źródłem twojego problemu, ale spędziłem wiele godzin próbując ustalić, dlaczego moja aplikacja, która działała dobrze na iPhonie, powoduje, że przeglądarka Androida stale wyświetla pionowe / poziome paski przewijania i faktycznie przenosi stronę. Miałem tag HTML body z wysokością i szerokością ustawioną na 100%, a treść była pełna różnych tagów w różnych lokalizacjach. Bez względu na to, co próbowałem, przeglądarki Androida pokazywały paski przewijania i tylko trochę przesuwały stronę, szczególnie podczas szybkiego przesuwania. Rozwiązaniem, które działało dla mnie bez konieczności robienia czegokolwiek w pakiecie APK, było dodanie następującego tagu body:

leftmargin="0" topmargin="0"

Wygląda na to, że domyślne marginesy dla tagu body zostały zastosowane na droidzie, ale zignorowane na iPhonie

Robert Etheredge
źródło
1

Jeśli utworzysz podklasę Webview, możesz po prostu nadpisać onTouchEvent, aby odfiltrować zdarzenia ruchu, które wyzwalają przewijanie.

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
źródło
0

studiowanie powyższych odpowiedzi prawie zadziałało ... ale nadal miałem problem, że mogłem `` rzucić '' widok na 2.1 (wydawało się, że został naprawiony z 2.2 i 2.3).

oto moje ostateczne rozwiązanie

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
źródło
U mnie działa przesłonięcie metody onScrollChanged (). W moim przypadku nie mogę przeciągnąć paska postępu wideo i audio osadzonego w WebView, używając odpowiedzi akceptuj. Wielkie dzięki!
codezjx
-1

To powinna być pełna odpowiedź. Zgodnie z sugestią @GDanger. Rozszerz WebView, aby zastąpić metody przewijania i osadzić niestandardowy widok sieci Web w układzie 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();
        }
    }
}

Następnie umieść w pliku układu w następujący sposób

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

Następnie w działaniu użyj dodatkowych metod wyłączania pasków przewijania.

ScrollDisabledWebView webView = (ScrollDisabledWebView) findViewById(R.id.webView);
webView.setVerticalScrollBarEnabled(false);
webView.setHorizontalScrollBarEnabled(false);
Vansi
źródło
-3

Po prostu użyj android:focusableInTouchMode="false"na swoim webView .

Socratex
źródło