Прокрутка HTML-событий в Android WebView, которая находится внутри ScrollView
У меня есть веб-страница для тестирования (https://storage.googleapis.com/htmltestingbucket/nested_scroll_helper.html), которая просто печатает счетчик события прокрутки, который html обнаружил в фиксированный заголовок
Когда Android WebView является единственным прокручиваемым элементом во фрагменте, все в порядке, и WebView отправляет события прокрутки на страницу
Если я хочу добавить собственные элементы выше и ниже WebView, тогда все становится намного сложнее.
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="SOMETHING ABOVE THE WEBVIEW" />
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="SOMETHING BELOW THE WEBVIEW" />
</LinearLayout>
</ScrollView>
Я знаю, что не хорошо иметь WebView внутри ScrollView, но я должен предоставить единый прокручиваемый опыт с гибридным контентом и соответствующими прокручивающими событиями в html-документе.
Я нашел много вопросов по этому вопросу, но я смог создать полное сквозное решение
Кроме того, я знаю, что у lint есть официальная проверка для этого:
NestedScrolling --------------- Описание: Вложенные виджеты прокрутки
Приоритет: 7/10 Уровень важности: Предупреждение Категория: Правильность
Виджет прокрутки, такой как ScrollView, не должен содержать вложенных прокрутки виджеты, поскольку это имеет различные проблемы удобства использования
И все же я не могу реализовать контент веб-представления в native, поэтому мне нужен альтернативный способ сделать это
Ответы
Ответ 1
Чтобы сохранить Webview внутри scrollview здесь, вам нужно измерить высоту веб-представления и установить его в параметрах макета.
Здесь я попытался дать ответ для прокручиваемого веб-представления.
<ScrollView
android:layout_width="fill_parent" android:background="#FF744931"
android:layout_height="fill_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:ignore="WebViewLayout">
<TextView
android:id="@+id/txtVoiceSeachQuery"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF0000"
android:textSize="26sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="SOMETHING ABOVE THE WEBVIEW" />
<com.example.ScrollableWebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:isWebViewInsideScroll="true" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="SOMETHING BELOW THE WEBVIEW" />
</LinearLayout>
</ScrollView>
RES/значение/attrs.xml
Чтобы добавить атрибут для пользовательского элемента управления
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ScrollableWebView">
<attr name="isWebViewInsideScroll" format="boolean"></attr>
</declare-styleable>
</resources>
ScrollableWebView
public class ScrollableWebView extends WebView {
private boolean webViewInsideScroll = true;
public static final String RESOURCE_NAMESPACE = "http://schemas.android.com/apk/res-auto";
public ScrollableWebView(Context context) {
super(context);
}
public ScrollableWebView(Context context, AttributeSet attrs) {
super(context, attrs);
setWebViewInsideScroll(attrs.getAttributeBooleanValue
(RESOURCE_NAMESPACE, "isWebViewInsideScroll", true));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (isWebViewInsideScroll()) {
int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
setLayoutParams(params);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public boolean isWebViewInsideScroll() {
return webViewInsideScroll;
}
public void setWebViewInsideScroll(boolean webViewInsideScroll) {
this.webViewInsideScroll = webViewInsideScroll;
}
}
Чтобы извлечь значение атрибута, вы также можете использовать Stylable, но здесь я сделал, не используя его.
ScrollableWebView webview = (ScrollableWebView) findViewById(R.id.webview);
webview.loadUrl("https://storage.googleapis.com/htmltestingbucket/nested_scroll_helper.html");
Ниже приведена ссылка выхода
Если вы не хотите создавать файл атрибута и добавлять пользовательские атрибуты в res/values /attrs.xml, вы можете игнорировать этот файл и проверить этот pastebin здесь я дал без какого-либо пользовательского атрибута, например isWebViewInsideScroll
. вы также можете удалить его из макета xml.
Дайте мне знать, если что-нибудь.
Ответ 2
если вы разместите веб-просмотр внутри scrollview, вы не получите эффект прокрутки html, потому что ваш контент в веб-браузере не будет прокручиваться (он будет размещен на полной длине внутри scrollview.)
Чтобы удовлетворить ваши потребности в размещении элементов выше и ниже, вы можете прослушивать прокрутку веб-просмотра и использовать DragViewHelper
или nineoldandroids
для перемещения header
и footer
, поэтому пользователь будет думать, что они представляют собой один элемент (вам не требуется прокрутка).
webView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
ViewHelper.setTranslationY(headerTextView, -event.getY());
}
});
public class ObservableWebView extends WebView {
private OnScrollChangeListener onScrollChangeListener;
public ObservableWebView(Context context) {
super(context);
}
public ObservableWebView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ObservableWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (onScrollChangeListener != null) {
onScrollChangeListener.onScrollChange(this, l, t, oldl, oldt);
}
}
public void setOnScrollChangeListener(OnScrollChangeListener onScrollChangeListener) {
this.onScrollChangeListener = onScrollChangeListener;
}
public OnScrollChangeListener getOnScrollChangeListener() {
return onScrollChangeListener;
}
public interface OnScrollChangeListener {
/**
* Called when the scroll position of a view changes.
*
* @param v The view whose scroll position has changed.
* @param scrollX Current horizontal scroll origin.
* @param scrollY Current vertical scroll origin.
* @param oldScrollX Previous horizontal scroll origin.
* @param oldScrollY Previous vertical scroll origin.
*/
void onScrollChange(WebView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY);
}
}
Этот пример поможет вам скрыть header
, я использовал nineoldandroid
для него
Ответ 3
на самом деле это не так хорошо, чтобы прокрутить представление в другое. Попытайтесь использовать это:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
И
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"/>
Ответ 4
Кажется, самый элегантный способ, который я мог найти, чтобы справиться с этим, заключается в следующем:
- Прослушивание свитков SrollView: вы можете использовать ObservableScrollView или вызвать setOnScrollChangeListener() из уровня API 23
- Рассчитать сдвиг Y сдвига в пикселях
- Вызовите WebView.evaluateJavascript()
- Передайте все детали события прокрутки
Итак, общие понятия проходят:
"$ (Документ).trigger( 'свитка');" как первый параметр оценитьJavascript
Я все еще проверяю детали и разрабатываю кинки, но это похоже на лучший способ, я попытаюсь отредактировать этот ответ с дополнительной информацией, поскольку я решаю этот
Если в любом случае есть лучшее решение, я бы хотел его услышать.
Ответ 5
У меня такая же проблема в последнее время, и я нашел ваши сообщения здесь:)
У меня есть WebView
, вложенный в ScrollVIew
. И страница, которую я загрузил в WebView
, нужно вызвать функцию JS, когда она прокручивается до конца, но в режиме прокрутки веб-страница window.onscroll = functionXXX() {}
никогда не вызывается.
Наконец, я должен установить OnScrollListener
в ScrollVIew
и вызвать функцию JS вручную по коду ниже
@Override
public void onScroll(int scrollY) {
if (!scrollView.canScrollVertically(scrollY)) {
mWebView.loadUrl("javascript:functionXXX();");
}
}
Возможно, наши ситуации разные, но я надеюсь, что это даст вам некоторое вдохновение:)