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!

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.


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

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 .


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


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

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

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


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.


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

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


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

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

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

-3

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.