I want to detect scrolling in WebView_Flutter and hide the padding - flutter

I am using Webview_Flutter.
The header of the site overlaps the position of the statusbar and I would like to add padding to avoid this.
This is the process of inserting padding to avoid the statusbar if the webview is opened or if there is a scroll position at the top.
body: Padding(
padding: (controller?.getScrollY() == null || controller?.getScrollY() == 0)
? EdgeInsets.only(top: height)
: EdgeInsets.only(top: 0),
child: Expanded(
child: Padding(
padding: const EdgeInsets.only(bottom: 0.0),
child: WebView(
javascriptMode: JavascriptMode.unrestricted,
initialUrl: Uri.parse(widget.link).toString(),
onWebResourceError: (error) {
// print(error.domain);
},
onWebViewCreated: (controller) {
this.controller = controller;
},
onProgress: (progress) {
setState(() {
this.progress = progress / 100;
progressPercent = progress;
});
},
),

To detect WebView scroll event, you can use the flutter_inappwebview plugin (I'm the author) and implement the InAppWebView.onScrollChanged event.
However, probably you don't need to add top padding for your WebView. You can set the AppBar.toolbarHeight to 0, so the app bar will have the right height to cover the status bar.
Here is a full code example with both cases using the current latest version 6 available of the plugin (6.0.0-beta.16):
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
if (!kIsWeb &&
kDebugMode &&
defaultTargetPlatform == TargetPlatform.android) {
await InAppWebViewController.setWebContentsDebuggingEnabled(kDebugMode);
}
runApp(const MaterialApp(home: MyApp()));
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final GlobalKey webViewKey = GlobalKey();
InAppWebViewController? webViewController;
int scrollY = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
toolbarHeight: 0,
),
body: Padding(
padding: EdgeInsets.only(top: scrollY <= 0 ? 25 : 0),
child: Column(
children: [
Expanded(
child: InAppWebView(
key: webViewKey,
initialUrlRequest:
URLRequest(url: WebUri("https://github.com/flutter")),
onWebViewCreated: (controller) {
webViewController = controller;
},
onScrollChanged: (controller, x, y) {
setState(() {
scrollY = y;
});
},
),
)
],
),
));
}
}

I tried to find the listener of the webView scroll, I couldn't find it , you're right. There is a solution ^^, it's simple, we could wrap WebView in ListView then we could use scrollListener(1) or notificationListener(2)
and don't forget to use setState to update Padding values
class _HomeScreenState extends State<HomeScreen> {
WebViewController? _webViewController;
ScrollController _scrollController = ScrollController();
#override
Widget build(BuildContext context) {
return
Scaffold(
body:Scaffold(
backgroundColor: Colors.green,
appBar: AppBar(
title: const Text('Flutter WebView example'),
// This drop down menu demonstrates that Flutter widgets can be shown over the web view.
actions: <Widget>[
],
),
//NotificationListener(2)
body: NotificationListener<ScrollNotification>(
onNotification: (scrollNotification) {
if (scrollNotification is ScrollStartNotification) {
WidgetsBinding.instance.addPostFrameCallback((_) {
print("ScrollStartNotification / pixel => ${scrollNotification.metrics.pixels}");
});
} else if (scrollNotification is ScrollEndNotification) {
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
print("ScrollEndNotification / pixel =>${scrollNotification.metrics.pixels}");
});
});
}
return true;
},
child: ListView(
physics: ClampingScrollPhysics(),
controller: _scrollController,
children: <Widget>[
ConstrainedBox(
constraints: BoxConstraints(maxHeight: 10000),
child: WebView(
initialUrl: 'https://flutter.dev',
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {},
onProgress: (int progress) {
print('WebView is loading (progress : $progress%)');
},
javascriptChannels: <JavascriptChannel>{
},
onPageStarted: (String url) {},
onPageFinished: (String url) {},
gestureNavigationEnabled: true,
backgroundColor: const Color(0x00000000),
),
),
],
),
)));
}
#override
void initState() {
super.initState();
//scrollListener(1)
_scrollController.addListener(() {
print("scrollListener / pixel =>${_scrollController.position.pixels}");
});
}
}

Related

Web view doesn't show the web page in Flutter application

I have this code in my flutter app :
class WebViewWidget1 extends StatefulWidget {
WebViewWidget1({Key? key}) : super(key: key);
#override
State<WebViewWidget1> createState() => _WebViewWidget1State();
}
class _WebViewWidget1State extends State<WebViewWidget1> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text('title'),
),
body: const WebView(
initialUrl: "https://github.com/ArjunMalhotra07",
javascriptMode: JavascriptMode.unrestricted,
),
);
}
}
I want to implement web view and this was the code I took from the internet. This just doesn't work. It shows a blank white screen with app bar only. Where am I wrong? can't deduce.
please add pubspec.yaml
flutter pub add flutter_inappwebview
inappwebview
Example:
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
class InAppWebViewPage extends StatefulWidget {
final String title, uri;
const InAppWebViewPage({Key? key, required this.title, required this.uri})
: super(key: key);
#override
_InAppWebViewPageState createState() => _InAppWebViewPageState();
}
class _InAppWebViewPageState extends State<InAppWebViewPage> {
int _stackIndex = 1;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Padding(
padding: EdgeInsets.all(12),
child: Expanded(
child: IndexedStack(
index: _stackIndex,
children: [
InAppWebView(
initialUrlRequest: URLRequest(url: Uri.parse(widget.uri)),
initialOptions: InAppWebViewGroupOptions(
crossPlatform:
InAppWebViewOptions(useShouldOverrideUrlLoading: true),
),
onLoadStop: (_, __) {
setState(() {
_stackIndex = 0;
});
},
onLoadError: (_, __, ___, ____) {
setState(() {
_stackIndex = 0;
});
//TODO: Show error alert message (Error in receive data from server)
},
onLoadHttpError: (_, __, ___, ____) {
setState(() {
_stackIndex = 0;
});
//TODO: Show error alert message (Error in receive data from server)
},
),
const SizedBox(
height: 50,
child: CircularProgressIndicator(),
),
],
),
),
),
);
}
}
Try to wrap WebView with SizedBox and give width and height to it.
SizedBox(
width: MediaQuery.of(context).size.width, // it uses all the width of screen, you can change it
height: MediaQuery.of(context).size.height, // it uses all the height of screen, you can change it
child: WebView(
initialUrl: "https://github.com/ArjunMalhotra07",
javascriptMode: JavascriptMode.unrestricted,
),
),
And don't forget to add webview_flutter package to your pubspec.yaml file.

Flutter WebView is not updating URL correctly for some sites

I am using the flutter_webView in my app like this:
WebView(
initialUrl: 'https://www.mediamarkt.de/',
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_controller = webViewController;
},
onPageStarted: (String url) {
setState(() {
_isLoading = true;
});
},
onPageFinished: (String url) {
setState(() {
_currentUrl = url;
_isLoading = false;
print('onagePageFinished: $_currentUrl');
});
},
),
Problem:
As you can see, I am updating the url everytime onPageFinished is called. That works for most of the time. However when navigating https://www.mediamarkt.de/ nothing is called. The URL is always the same.
What am I missing here? Let me know if you need any more information!
so the solution was rather simple:
final String? url = await _controller.currentUrl();
not quite sure why onPageFinished is not always refreshing correctly but with the above code everything is working just as expected.
I am having the same issue my url is not refreshing you should see 2 boxes not one.
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
double heights = 800;
#override
void initState() {
super.initState();
}
Widget build(BuildContext context) {
WebViewController? _webviewController;
return SafeArea(
child: Scaffold(
appBar: AppBar(
actions: [],
),
body: RefreshIndicator(
onRefresh: () {
return Future.delayed(Duration(seconds: 1), () {
_webviewController!.reload();
});
},
child: Expanded(
child: SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
child: Column(
children: [
SizedBox(
height: heights,
child: WebView(
javascriptMode: JavascriptMode.unrestricted,
initialUrl:
"https://christfamilychurchnashville.org/acalendar/",
onWebViewCreated: (WebViewController webViewController) {
_webviewController = webViewController;
},
onPageFinished: (content) async {
var _heights = double.parse(await _webviewController!
.evaluateJavascript(
"document.documentElement.scrollHeight"));
heights = _heights;
// setState(() {});
},
),
),
],
),
),
),
),
),
);
}
}

How to show Loading Indicator background transparent in WebView Flutter?

I'm new to flutter and making my first webview app. Here I'm trying to add a spinner every time when a user tries to click the link or page load. I want to make spinner background opacity a bit low just like the given example(right picture) but opacity doesn't work at all.
Here is my approach:
// ignore_for_file: prefer_const_constructors
// ignore: use_key_in_widget_constructors
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: WebViewClass()
)
);
}
}
class WebViewClass extends StatefulWidget {
WebViewState createState() => WebViewState();
}
class WebViewState extends State<WebViewClass>{
int position = 1 ;
final key = UniqueKey();
doneLoading(String A) {
setState(() {
position = 0;
});
}
startLoading(String A){
setState(() {
position = 1;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: null,
body: SafeArea(child: IndexedStack(
index: position,
children: <Widget>[
WebView(
initialUrl: 'https://google.com',
javascriptMode: JavascriptMode.unrestricted,
key: key ,
onPageFinished: doneLoading,
onPageStarted: startLoading,
),
Container(
color: Colors.white70,
child: Center(
child: CircularProgressIndicator()),
),
]))
);
}
}
Any help or guidance will highly appreciated.
You can try like this. every time when you come in the web view screen. the loader will show.
class WebViewClass extends StatefulWidget {
WebViewState createState() => WebViewState();
}
class WebViewState extends State<WebViewClass> {
bool isLoading = false;
final key = UniqueKey();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: null,
body: SafeArea(
child: IgnorePointer(
ignoring: isLoading,
child: Stack(
children: [
WebView(
initialUrl: 'https://google.com',
javascriptMode: JavascriptMode.unrestricted,
key: key,
onPageFinished: (value) {
setState(() {
isLoading = false;
});
},
onPageStarted: (value) {
setState(() {
isLoading = true;
});
},
),
isLoading ? Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.grey.withOpacity(0.5),
child: const Center(child: CircularProgressIndicator()) ,
) : Container(),
],
),
)),);
}
}

How to add CircularProgressIndicator when loading web page using flutter_inappwebview?

I am new in flutter,
I tried to add a CircularProgressIndicator while waiting to the web page to load,
and then the page display and the circular indicator dosen't show on screen.
where it's should be? maybe in onLoadStart function below?
Source code:
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
class CoursesInformation extends StatefulWidget {
#override
_CoursesInformationState createState() => _CoursesInformationState();
}
class _CoursesInformationState extends State<CoursesInformation> {
InAppWebViewController webView;
#override
void initState() {
super.initState();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.rtl,
child: Scaffold(
appBar: AppBar(
title: const Text('מידע על קורסים'),
centerTitle: true,
),
body: Container(
child: Column(children: <Widget>[
Expanded(
child: InAppWebView(
initialUrl:
"https://shoham.biu.ac.il/BiuCoursesViewer/MainPage.aspx",
initialHeaders: {},
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
debuggingEnabled: true,
preferredContentMode: UserPreferredContentMode.DESKTOP),
),
onWebViewCreated: (InAppWebViewController controller) {
webView = controller;
},
onLoadStart: (InAppWebViewController controller, String url) {
},
onLoadStop: (InAppWebViewController controller, String url) async {
},
))
])),
),
);
}
}
You can onProgressChanged parameter and show the loader. You can also use LinearProgressIndicator (check commented code). Check the following example
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
void main() {
// it should be the first line in main method
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark()
.copyWith(scaffoldBackgroundColor: Color.fromARGB(255, 18, 32, 47)),
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(body: CustomPage());
}
}
class CustomPage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return CustomPageState();
}
}
class CustomPageState extends State<CustomPage> {
InAppWebViewController webView;
double progress = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('מידע על קורסים'),
centerTitle: true,
),
body: Container(
child: Column(children: <Widget>[
Expanded(
child: Stack(
children: <Widget>[
Align(
alignment: Alignment.center,
child: InAppWebView(
initialUrl:
"https://shoham.biu.ac.il/BiuCoursesViewer/MainPage.aspx",
initialHeaders: {},
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
debuggingEnabled: true,
preferredContentMode: UserPreferredContentMode.DESKTOP),
),
onWebViewCreated: (InAppWebViewController controller) {
webView = controller;
},
onLoadStart: (InAppWebViewController controller, String url) {
},
onLoadStop:
(InAppWebViewController controller, String url) async {
},
onProgressChanged: (InAppWebViewController controller, int progress) {
setState(() {
this.progress = progress / 100;
});
},
),
),
Align(
alignment: Alignment.center,
child: _buildProgressBar()
),
],
))
])),
);
}
Widget _buildProgressBar() {
if (progress != 1.0) {
return CircularProgressIndicator();
// You can use LinearProgressIndicator also
// return LinearProgressIndicator(
// value: progress,
// valueColor: new AlwaysStoppedAnimation<Color>(Colors.orange),
// backgroundColor: Colors.blue,
// );
}
return Container();
}
}

Flutter load webview inside the fragment

// Here is my flutter code
import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
class HairtipsPage extends StatefulWidget {
#override
_HairtipsPageState createState() => _HairtipsPageState();
}
class _HairtipsPageState extends State<HairtipsPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child : WebviewScaffold(
url: "https://www.google.com",
appBar: new AppBar(
// title: new Text('Hairtips'),
),
withZoom: true,
withLocalStorage: true,
)
),
);
}
}
I am using bottom navigation in my app and trying to implement webview inside the fragment.i know how to acheive the same in android also i dont want the webview should open in a browser.i am expecting the webview should load inside the app and within the fragment.
You can use the Flutter webview plugin. Here is the URL for the plugin https://pub.dartlang.org/packages/webview_flutter
The webview will load inside the App with CircularProgressIndicator.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class WebView extends StatefulWidget {
#override
_WebViewState createState() => _WebViewState();
}
class _WebViewState extends State<WebView> {
final Completer<WebViewController> _controller =
Completer<WebViewController>();
num _stackToView = 1;
void _handleLoad(String value) {
setState(() {
_stackToView = 0;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: Builder(builder: (BuildContext context) {
return IconButton(
icon: Icon(Icons.volume_up, color: Colors.black,),
onPressed: () {
Navigator.pop(context);
},
);
}),
backgroundColor: Colors.white10,
elevation: 0,
),
body: IndexedStack(
index: _stackToView,
children: [
Column(
children: <Widget>[
Expanded(
child: WebView(
initialUrl: "https://www.google.co.in/",
javascriptMode: JavascriptMode.unrestricted,
onPageFinished: _handleLoad,
onWebViewCreated: (WebViewController webViewController) {
_controller.complete(webViewController);
},
)),
],
),
Container(
child: Center(child: CircularProgressIndicator(),)
),
],
));
}
}