Pull down to refresh WebView
Page in flutter with RefreshIndicator
.
Tested with webview_flutter : ^4.4.2
.
A simple working solution of pull down to refresh WebView
page with RefreshIndicator
and without
SingleChildScrollView
which causes issues with the WebView
page scroll behavior of the rendered sites:
This version resolves following issues w/o SingleChildScrollView
:
SingleChildScrollView
has always the absolute height of the page
e.g. if a text box was not expanded from the beginning (javascript),
the scroll height exceeds the page height.exceedsLoadingTime
: Checks if loading time exceeds a maximum time (e.g. 3 seconds)
to re-allow drag to refresh if page is still loading (Check pull_to_refresh.dart).REFRESH_DISTANCE_MIN
: Calculates in pull_to_refresh.dart from the screen size
the needed dragging distance to start the refresh process (default is 0.2
WebView screen pixels).I changed using ScrollNotification
which RefreshIndicator
interprets right when FixedScrollMetrics
are set. So we have the original animation like in SingleChildScrollView
or e.g. chrome browser
.
Just use DragGesturePullToRefresh
from my pull_to_refresh.dart like in my webview.dart example in yours (commented with // Here
), that's it:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_web_refresh/pull_to_refresh.dart';
import 'package:webview_flutter/webview_flutter.dart';
class MyWebViewWidget extends StatefulWidget {
final String initialUrl;
const MyWebViewWidget({
Key? key,
required this.initialUrl,
}) : super(key: key);
@override
State<MyWebViewWidget> createState() => _MyWebViewWidgetState();
}
class _MyWebViewWidgetState extends State<MyWebViewWidget>
with WidgetsBindingObserver {
WebViewController _controller = WebViewController();
late DragGesturePullToRefresh dragGesturePullToRefresh; // Here
@override
void initState() {
super.initState();
dragGesturePullToRefresh = DragGesturePullToRefresh(); // Here
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..enableZoom(true)
..setNavigationDelegate(
NavigationDelegate(
onPageStarted: (String url) {
// Don't allow RefreshIndicator if page is loading, but not needed
dragGesturePullToRefresh.started(); // Here
},
onPageFinished: (String url) {
// Hide RefreshIndicator for page reload if showing
dragGesturePullToRefresh.finished(); // Here
},
onWebResourceError: (WebResourceError error) {
//debugPrint('MyWebViewWidget:onWebResourceError(): ${error.description}');
// Hide RefreshIndicator for page reload if showing
dragGesturePullToRefresh.finished(); // Here
},
),
)
..loadRequest(Uri.parse(widget.initialUrl));
dragGesturePullToRefresh // Here
.setController(_controller)
.setDragHeightEnd(200)
.setDragStartYDiff(10)
.setWaitToRestart(3000);
//setState(() {});
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
// remove listener
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
Widget build(context) {
return RefreshIndicator(
triggerMode: RefreshIndicatorTriggerMode.onEdge,
onRefresh: dragGesturePullToRefresh.refresh, // Here
child: Builder(
builder: (context) {
// IMPORTANT: Use the RefreshIndicator context!
dragGesturePullToRefresh.setContext(context); // Here
return WebViewWidget(
controller: _controller,
// Add it to the WebViewWidget
gestureRecognizers: {Factory(() => dragGesturePullToRefresh)}, // Here
);
},
),
);
}
}
SingleChildScrollView
or to e.g. the chrome browserRefreshIndicator
shows no initial animation by dragging it down until the distance
is reached to start the refresh process.refreshPage()
in the pull_to_refresh.dart