Отключить прокрутку в веб-просмотре?


86

До сих пор я был разработчиком только для iPhone, а теперь решил попробовать Android. Что-то, чего я не смог понять на Android, - это как программно предотвратить прокрутку в WebView?

Что-то похожее на предупреждение айфонов о onTouchMoveсобытии было бы здорово!

Ответы:


179

Вот мой код для отключения всей прокрутки в веб-просмотре:

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

Вы также можете попробовать обернуть свой веб-просмотр вертикальной прокруткой прокрутки и отключить всю прокрутку в веб-просмотре:

<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(...)выше код, чтобы отключить всю прокрутку в веб-просмотре. Вертикальный ScrollView позволит прокручивать содержимое WebView.


работает нормально, но через несколько секунд вызывает сбой на Samsung i5700 spica в /system/lib/libwebcore.so.
Лукас

LayoutAlgorithm.SINGLE_COLUMN или webview.setOnTouchListener?
peceps

3
Если вы помещаете WebView в ScrollView, установите для атрибута android: isScrollContainer WebView значение «false» вместо того, чтобы устанавливать для android: scrollbars значение «none». Это приводит к полному отключению обработки прокрутки веб-представления и позволяет ему расширяться в соответствии с его содержимым. Тогда прокрутка будет обрабатываться исключительно родительским ScrollView.
BladeCoder

1
Если вам нужно обрабатывать MotionEvent.ACTION_MOVEсобытия в вашем, WebViewсм. Мой ответ ниже.
GDanger

1
Игнорирование ACTION_MOVEна setOnTouchListenerсобытии имеет некоторые побочные эффекты, поэтому я бы НЕ рекомендовал этот ответ; 1. Быстрые смахивания считаются onclickсобытиями на странице. 2. Предотвращает переполнение прокрутки элементов на странице, это может понадобиться для правильного взаимодействия в зависимости от сайта. 3. touchmoveСобытие JS . @GDanger имеет правильный ответ, который отменяет, overScrollByрасширяя, WebViewпоскольку он не имеет других побочных эффектов, просто предотвращает прокрутку страницы. stackoverflow.com/a/26129301/1244574
jkasten

22

Не знаю, нужно оно вам или нет, но вот решение:

appView = (WebView) findViewById(R.id.appView); 
appView.setVerticalScrollBarEnabled(false);
appView.setHorizontalScrollBarEnabled(false);

18
ОК. это отключает полосы прокрутки, но не предотвращает прокрутку путем перетаскивания. Кажется, что html тоже должен подходить ...
rdmueller

Если вы разрабатываете свои веб-страницы только для веб-просмотра Android, я рекомендую сделать ваши веб-страницы в виде таблицы. Ширина должна быть такой же, как width = "100%" и такой же для высоты. так что перетаскивания больше не будет.
Умар

width = 100% не всегда работает, например: stackoverflow.com/questions/6460871/…
NoBugs

круто .. это то, что мне нужно. Спасибо
Питер

21

Создание 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
    }
}

Если вы посмотрите на источнике для WebViewвы можете видеть , что onTouchEventвызовы , doDragкоторые называют overScrollBy .


1
Если вам нужно программно отключить / включить прокрутку, посмотрите на эту суть, которую я создал.
GDanger

1
Ваш метод работает у меня. И я полностью с вами согласен. В моем случае я не могу перетащить индикатор выполнения видео и аудио, встроенный в WebView, с помощью ответа принятия.
codezjx

Это правильный ответ. Хотя для этого требуются некоторые настройки переопределяющих конструкторов. Пожалуйста, посмотрите мой полный ответ ниже. stackoverflow.com/a/51936944/393502
Vansi

13

Добавление деталей полей в тело предотвратит прокрутку, если ваш контент правильно обернут, например:

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

Достаточно просто, и намного меньше кода + накладных расходов :)


1
Гениально! +1 для простого решения только для HTML. Иногда мне
хочется,

Выглядит хорошо в стандартном браузере Android, но, похоже, не работает в Firefox (Fennec) ... несмотря на то, что нечего прокручивать по горизонтали, Firefox по-прежнему позволяет мне прокручивать вправо до точки, где прокручивается весь контент за экран.
Майкл

1
Не работает в современном WebView (Android 5 и выше)
Роэль

8

Установите слушателя на свой WebView:

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

3
В конце returnстроки стоит дополнительная скобка . Также это нарушает события касания HTML5 Canvas и JavaScript.
Рохан Сингх,

Это, конечно, отключает его, но как мне позже убить слушателя для рендеринга ввода? Я пробовал не event.getAction() != MotionEvent.ACTION_MOVEхужеreturn true
CQM

Стандартный случай «ничего не делать» - return falseнет return true.
Мэтью Рид

6

Я не пробовал этого, так как я еще не сталкивался с этой проблемой, но, возможно, вы могли бы переопределить функцию onScroll?

@Override
public void scrollTo(int x, int y){
super.scrollTo(0,y);
}

Это то, что мы называем в Индии Jugaad ... хотя все работало нормально
R4chi7

4

Мое грязное, но простое в реализации и хорошо работающее решение:

Просто поместите веб-просмотр внутрь прокрутки. Сделайте веб-просмотр слишком большим, чем возможный контент (в одном или обоих измерениях, в зависимости от требований). ..и настройте полосы прокрутки просмотра по своему желанию.

Пример отключения горизонтальной полосы прокрутки в веб-просмотре:

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

Надеюсь, это поможет ;)


да, но тогда размер прокрутки не был бы слишком большим с большим количеством белого пространства внизу?
Рафаэль Санчес,

1
Что, если ширина содержимого будет 1001dp?
Waltsu

3

Я разрешил мерцание и автопрокрутку:

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, чтобы обеспечить более эффективный контроль, такой как отключение / включение свайпов, включение / отключение касаний, прослушивателей, управляющих переходов, анимации, определение внутренних параметров и т. Д.


3

Чтобы отключить прокрутку, используйте это

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

2

Возможно, это не является источником вашей проблемы, но я потратил часы, пытаясь отследить, почему мое приложение, которое нормально работало на iphone, заставляет браузер Android постоянно отображать вертикальные / горизонтальные полосы прокрутки и фактически перемещать страницу. У меня был тег тела html с высотой и шириной, установленной на 100%, и тело было заполнено различными тегами в разных местах. Независимо от того, что я пробовал, браузеры Android показывали свои полосы прокрутки и немного сдвигали страницу, особенно при быстром смахивании. Решение, которое сработало для меня без необходимости делать что-либо в APK, заключалось в добавлении следующего в тег body:

leftmargin="0" topmargin="0"

Кажется, что поля по умолчанию для тега body применялись к дроиду, но игнорировались на iphone


1

Если вы создаете подкласс 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);
    }
    ...

0

изучение приведенных выше ответов почти сработало для меня ... но у меня все еще была проблема, заключающаяся в том, что я мог `` бросить '' представление на 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);
}
}

У меня работает переопределение метода onScrollChanged (). В моем случае я не могу перетащить индикатор выполнения видео и аудио, встроенный в WebView, с помощью ответа принятия. Большое спасибо!
codezjx

-1

Это должен быть полный ответ. По предложению @GDanger. Расширьте 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);

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.