Flutter WebviewPlugin remove header and footer of website - webview

By implementation of FlutterWebviewPlugin, I want to show a particular website in a widget but without header and footer.
is this possible in Flutter?
I guess there is a function in FlutterWebviewPlugin class .evalJavascript('some code') but don't know how to use this function. can I add javascript code to this?
import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
String url = "https://flutter.io/";
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Webview Example',
theme: ThemeData.dark(),
routes: {
"/": (_) => Home(),
"/webview": (_) => WebviewScaffold(
url: url,
withJavascript: true,
withLocalStorage: true,
withZoom: true,
)
},
);
}
}
class Home extends StatefulWidget {
#override
HomeState createState() => HomeState();
}
class HomeState extends State<Home> {
final webView = FlutterWebviewPlugin();
TextEditingController controller = TextEditingController(text: url);
#override
void initState() {
super.initState();
webView.close();
controller.addListener(() {
url = controller.text;
});
}
#override
void dispose() {
webView.dispose();
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("WebView"),
),
body: Center(
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.all(10.0),
child: TextField(
controller: controller,
),
),
RaisedButton(
child: Text("Open Webview"),
onPressed: () {
Navigator.of(context).pushNamed("/webview");
},
)
],
),
)
);
}
}

I suggest using Flutter's official WebView plugin: webview_flutter
The plugin also has a method that can run Javascript using WebViewController.evaluateJavascript(String). This method is recommended to be run after WebView.onPageFinished callback.
Your WebView widget should look like this.
WebView(
initialUrl: 'https://flutter.dev',
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_webViewController = webViewController;
_controller.complete(webViewController);
},
onProgress: (int progress) {
print("WebView is loading (progress : $progress%)");
},
onPageStarted: (String url) {
print('Page started loading: $url');
},
onPageFinished: (String url) {
print('Page finished loading: $url');
// Removes header and footer from page
_webViewController
.evaluateJavascript("javascript:(function() { " +
"var head = document.getElementsByTagName('header')[0];" +
"head.parentNode.removeChild(head);" +
"var footer = document.getElementsByTagName('footer')[0];" +
"footer.parentNode.removeChild(footer);" +
"})()")
.then((value) => debugPrint('Page finished loading Javascript'))
.catchError((onError) => debugPrint('$onError'));
},
);
Here's a complete sample that you can try.
import 'dart:async';
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(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final Completer<WebViewController> _controller =
Completer<WebViewController>();
WebViewController _webViewController;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Builder(builder: (BuildContext context) {
return WebView(
initialUrl: 'https://flutter.dev',
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_webViewController = webViewController;
_controller.complete(webViewController);
},
onProgress: (int progress) {
print("WebView is loading (progress : $progress%)");
},
javascriptChannels: <JavascriptChannel>{
_toasterJavascriptChannel(context),
},
navigationDelegate: (NavigationRequest request) {
if (request.url.startsWith('https://www.youtube.com/')) {
print('blocking navigation to $request}');
return NavigationDecision.prevent;
}
print('allowing navigation to $request');
return NavigationDecision.navigate;
},
onPageStarted: (String url) {
print('Page started loading: $url');
},
onPageFinished: (String url) {
print('Page finished loading: $url');
_webViewController
.evaluateJavascript("javascript:(function() { " +
"var head = document.getElementsByTagName('header')[0];" +
"head.parentNode.removeChild(head);" +
"var footer = document.getElementsByTagName('footer')[0];" +
"footer.parentNode.removeChild(footer);" +
"})()")
.then((value) => debugPrint('Page finished loading Javascript'))
.catchError((onError) => debugPrint('$onError'));
},
gestureNavigationEnabled: true,
);
}),
);
}
JavascriptChannel _toasterJavascriptChannel(BuildContext context) {
return JavascriptChannel(
name: 'Toaster',
onMessageReceived: (JavascriptMessage message) {
// ignore: deprecated_member_use
Scaffold.of(context).showSnackBar(
SnackBar(content: Text(message.message)),
);
});
}
}
How the app looks running

_webViewController.runJavascript(
"document.getElementsByTagName('header')[0].style.display='none'");
_webViewController.runJavascript(
"document.getElementsByTagName('footer')[0].style.display='none'");

You can use the flutter_inappwebview plugin (I'm the author) and inject an UserScript at UserScriptInjectionTime.AT_DOCUMENT_START to hide or remove HTML elements when the web page loads (check JavaScript - User Scripts official docs for User Scripts details).
As I have already answered here for a similar issue, here is a code example using the current latest version 6 (6.0.0-beta.18) with URL https://getmobie.de/impressum that removes the header and footer HTML elements:
import 'dart:collection';
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;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("InAppWebView test"),
),
body: Column(children: <Widget>[
Expanded(
child: InAppWebView(
key: webViewKey,
initialUrlRequest:
URLRequest(url: WebUri("https://getmobie.de/impressum")),
initialUserScripts: UnmodifiableListView([
UserScript(source: """
window.addEventListener('DOMContentLoaded', function(event) {
var header = document.querySelector('.elementor-location-header'); // use here the correct CSS selector for your use case
if (header != null) {
header.remove(); // remove the HTML element. Instead, to simply hide the HTML element, use header.style.display = 'none';
}
var footer = document.querySelector('.elementor-location-footer'); // use here the correct CSS selector for your use case
if (footer != null) {
footer.remove(); // remove the HTML element. Instead, to simply hide the HTML element, use footer.style.display = 'none';
}
});
""", injectionTime: UserScriptInjectionTime.AT_DOCUMENT_START)
]),
onWebViewCreated: (controller) {
webViewController = controller;
},
),
),
]));
}
}
For your use case, use the right CSS selector inside the user script js source to correctly get and remove the header and footer HTML elements from your web page!

Related

Blocking ads (pop ups or that redirects to other websites) in flutter in app webview plugin

i am making an app that contains a button which when pressed will open a website that streams video . i have used flutter inappwebview plugin and i want to use content blockers too in my code.after searching i got some codes but i am getting errors that says some part in my code isnt define.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
final Uri _url = Uri.parse('https://zoro.to');
Future<void> _launchUrl() async {
if (!await launchUrl(_url)) {
throw Exception('Could not launch $_url');
}
}
// Future main() async {
// WidgetsFlutterBinding.ensureInitialized();
//
// if (Platform.isAndroid) {
// await AndroidInAppWebViewController.setWebContentsDebuggingEnabled(true);
// }
//
// runApp(new animflix());
// }
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
if (!kIsWeb &&
kDebugMode &&
defaultTargetPlatform == TargetPlatform.android) {
await AndroidInAppWebViewController.setWebContentsDebuggingEnabled(
kDebugMode);
}
runApp(const MaterialApp(home: animflix()));
}
// void main() {
// runApp(const animflix());
// }
class animflix extends StatelessWidget {
const animflix({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'anime',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: anime(),
);
}
}
class anime extends StatefulWidget {
const anime({Key? key}) : super(key: key);
#override
State<anime> createState() => _animeState();
}
class _animeState extends State<anime> {
final GlobalKey webViewKey = GlobalKey();
final adUrlFilters = [
".*.doubleclick.net/.*",
".*.ads.pubmatic.com/.*",
".*.googlesyndication.com/.*",
".*.google-analytics.com/.*",
".*.adservice.google.*/.*",
".*.adbrite.com/.*",
".*.exponential.com/.*",
".*.quantserve.com/.*",
".*.scorecardresearch.com/.*",
".*.zedo.com/.*",
".*.adsafeprotected.com/.*",
".*.teads.tv/.*",
".*.outbrain.com/.*"
];
final List<ContentBlocker> contentBlockers = [];
var contentBlockerEnabled = true;
InAppWebViewController? webViewController;
#override
void initState() {
super.initState();
// for each ad URL filter, add a Content Blocker to block its loading
for (final adUrlFilter in adUrlFilters) {
contentBlockers.add(ContentBlocker(
trigger: ContentBlockerTrigger(
urlFilter: adUrlFilter,
),
action: ContentBlockerAction(
type: ContentBlockerActionType.BLOCK,
)));
}
// apply the "display: none" style to some HTML elements
contentBlockers.add(ContentBlocker(
trigger: ContentBlockerTrigger(
urlFilter: ".*",
),
action: ContentBlockerAction(
type: ContentBlockerActionType.CSS_DISPLAY_NONE,
selector: ".banner, .banners, .ads, .ad, .advert")));
}
adblock() async {
contentBlockerEnabled = !contentBlockerEnabled;
if (contentBlockerEnabled) {
await webViewController?.setSettings(
settings: InAppWebViewSettings(contentBlockers: contentBlockers));
} else {
await webViewController?.setSettings(
settings: InAppWebViewSettings(contentBlockers: []));
}
webViewController?.reload();
setState(() {});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.pink,
),
home: Scaffold(
appBar: AppBar(title: Text("Anime market")),
body: Center(
child: Column(
children: <Widget>[
Container(
child: ElevatedButton(
onPressed: () {
setState(() {
InAppWebView(
key: webViewKey,
initialUrlRequest: URLRequest(
url: Uri.parse('https://www.tomshardware.com/')),
initialData: InAppWebViewSettings(
contentBlockers: contentBlockers),
onWebViewCreated: (controller) {
webViewController = controller;
},
);
});
},
child: Text("sflix"),
),
)
],
)),
),
);
}
}
"InAppWebviewSettings" throughs an error which says it isnt defined.

How to add a splashscreen to a Flutter webview app?

**Hi guys, how can I add a splashscreen to this webview Flutter app.
Because I would like to upload it to App Store.
I uploaded this code to google Store and it has been accepted.
I am very new to flutter and dont have an experince, so please rewrite the code you would tell me to be sure that the answered code is working.
Thank you in advance.
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'dart:async';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'My Website',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(
title: 'My Website',
url: 'https://www.???.com/'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title, this.url});
final String title;
final String url;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
WebViewController _controller;
final Completer<WebViewController> _controllerCompleter =
Completer<WebViewController>();
//Make sure this function return Future<bool> otherwise you will get an error
Future<bool> _onWillPop(BuildContext context) async {
if (await _controller.canGoBack()) {
_controller.goBack();
return Future.value(false);
} else {
return Future.value(true);
}
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () => _onWillPop(context),
child: Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: SafeArea(
child: WebView(
key: UniqueKey(),
onWebViewCreated: (WebViewController webViewController) {
_controllerCompleter.future.then((value) => _controller = value);
_controllerCompleter.complete(webViewController);
},
javascriptMode: JavascriptMode.unrestricted,
initialUrl: widget.url,
)),
),
);
}
}
you can create a widget that displays a splash screen and hold the widget for some seconds then push it to your new widget, like this:
import 'dart:async';
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,
title: 'My Website',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(
title: 'My Website',
url: 'https://www.google.com/',
),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title, this.url});
final String title;
final String url;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool loading = true;
WebViewController _controller;
final Completer<WebViewController> _controllerCompleter =
Completer<WebViewController>();
//Make sure this function return Future<bool> otherwise you will get an error
Future<bool> _onWillPop(BuildContext context) async {
if (await _controller.canGoBack()) {
_controller.goBack();
return Future.value(false);
} else {
return Future.value(true);
}
}
startSplashScreen() async {
var duration = const Duration(seconds: 3);
return Timer(
duration,
() {
setState(() {
loading = false;
});
},
);
}
#override
void initState() {
super.initState();
startSplashScreen();
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () => _onWillPop(context),
child: Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: loading == true
? Center(
child: Text(
'APP LOGO',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
),
),
)
: SafeArea(
child: WebView(
key: UniqueKey(),
initialUrl: widget.url,
onWebViewCreated: (WebViewController webViewController) {
_controllerCompleter.complete(webViewController);
},
javascriptMode: JavascriptMode.unrestricted,
),
),
),
);
}
}
result:
use this package
Add this code before navigating to your homescreen
new SplashScreen(
seconds: 14,
navigateAfterSeconds: HomeScreen(),
title: Text('Welcome In SplashScreen'),
image: Image.asset('splash.png'),
backgroundColor: Colors.white,
photoSize: 100.0,
loaderColor: Colors.red
);
EDIT for example:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'My Website',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SplashScreen(
seconds: 5,
navigateAfterSeconds: MyHomePage(
title: 'My Website',
url: 'https://www.???.com/'),
title: Text('Welcome In SplashScreen'),
backgroundColor: Colors.white,
loaderColor: Colors.red
),
);
}
}

How to change title of main.dart AppBar in it's child programmatically?

I have an AppBar in main.dart and I want to defined it as primary on it's child, But I want to change the title of AppBar itself when I'm on child's page, how can i do that properly?
void main() => runApp(MyApp());
class MyApp extends StatelessWidget{
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter App",
theme: ThemeData(
primaryColor: Colors.cyan,
brightness: Brightness.dark
),
home: Scaffold(
appBar: AppBar(
title: Text("Main Dart"),
),
body: HomeScreen(),
),
routes: <String, WidgetBuilder>{
'/homeScreen': (buildContext)=>HomeScreen(),
'/second': (buildContext)=>Second()
},
);
}
}
//HomeScreen or Second Widget on different dart file
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
//here I want to change the title of Main Dart to HomeScreen
return Container(
child: Center(
child: FlatButton(
child: new Text("Home screen"),
onPressed: (){
Route route = MaterialPageRoute(builder: (context) => Second());
Navigator.push(context, route);
},
),
),
);
}
}
or I need to put Scaffold(appBar:AppBar(...), ...) in every screen? it is the best approach?
Have a BLoC for app properties in app_properties_bloc.dart
final appBloc = AppPropertiesBloc();
class AppPropertiesBloc{
StreamController<String> _title = StreamController<String>();
Stream<String> get titleStream => _title.stream;
updateTitle(String newTitle){
_title.sink.add(newTitle);
}
dispose() {
_title.close();
}
}
Use stream builder in AppBar like this:
AppBar(
title: StreamBuilder<Object>(
stream: appBloc.titleStream,
initialData: "Main Dart",
builder: (context, snapshot) {
return Text(snapshot.data);
}
),
),
Use this to update title on button's onPressed()
onPressed: () {
appBloc.updateTitle('new title');
},
Just in case you are changing only the title of Scaffold then this will work.
I am creating a DefaultScaffold with the title each screen provides. Here the code will show the MainPage and two other pages which have the same AppBar with changed titles.
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(initialRoute: 'home', routes: <String, WidgetBuilder>{
'home': (context) => SOMain(),
'/secondPage': (context) => DefaultScaffold("Second Screen", SOSecond()),
'/thirdPage': (context) => DefaultScaffold("Third Screen", SOThird()),
});
}
}
class DefaultScaffold extends StatelessWidget {
String title;
Widget body;
DefaultScaffold(this.title, this.body);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: body,
);
}
}
class SOMain extends StatelessWidget {
#override
Widget build(BuildContext context) {
return DefaultScaffold(
"Main Screen",
Center(
child: RaisedButton(
child: Text("Go to second screen"),
onPressed: () {
Navigator.pushNamed(context, '/secondPage');
}),
),
);
}
}
class SOSecond extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: RaisedButton(
child: Text("Go the 3rd screen"),
onPressed: () => Navigator.pushNamed(context, "/thirdPage"),
),
);
}
}
class SOThird extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(child: Text("You are on last screen"));
}
}
Note: This is a simple workaround and may not be the best way to do this.
You can accomplish updating the state of the parent from a child by using a callback function.
Parent Class:
import 'package:flutter/material.dart';
class Parent extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return ParentState();
}
}
class ParentState extends State<Parent> {
String title = "Old Title";
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(title),
),
body: DaysFragmentView(onTitleSelect: (String value) {
setTitle(value);
}
),
);
}
void setTitle(String value) {
setState(() {
title = value;
});
}
}
Child Class
typedef TitleCallback = void Function(Title color);
class DaysFragmentView extends StatelessWidget {
const DaysFragmentView({this.onTitleSelect});
final TitleCallback onTitleSelect;
#override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
RaisedButton(
child: Text('One'),
onPressed: () {
onTitleSelect("TITLE ONE");
},
),
RaisedButton(
child: Text('Two'),
onPressed: () {
onTitleSelect("TITLE TWO");
},
)
],
);
}
}
Reference:
call-method-in-one-stateful-widget-from-another-stateful-widget-flutter
working-with-callback-in-flutter
Using ValueListenableBuilder is an option.
Use an instance variable
String appTitle;
Then set the app bar as in the following block:
appBar: AppBar(
ValueListenableBuilder<String>(
valueListenable: appTitle,
builder: (context, value, child) {
return Text(appTitle.value);
},
),
After that you can simply set appTitle.value in the other class. The title will be changed too because it listens to that value.
appTitle.value = "Home Screen";
Some answer here are too complicated. Here is a full working example using app bar update from child with scafold widget.
You can run the example in dart pad
import 'package:flutter/material.dart';
void main() {
runApp(const MyHomePage(title: 'init title'));
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final ValueNotifier<String?> _appBarTitleNotifier = ValueNotifier<String?>(null);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: ValueListenableBuilder<String?>(
builder: (BuildContext context, String? value, Widget? child) {
return Text(value ?? widget.title);
},
valueListenable: _appBarTitleNotifier,
),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ChildDemoTitleBar(titleNotifier: _appBarTitleNotifier)
],
),
),
),
);
}
}
class ChildDemoTitleBar extends StatefulWidget {
final ValueNotifier<String?> titleNotifier;
const ChildDemoTitleBar({Key? key, required this.titleNotifier})
: super(key: key);
#override
State<ChildDemoTitleBar> createState() => _ChildDemoTitleBarState();
}
class _ChildDemoTitleBarState extends State<ChildDemoTitleBar> {
int _counter = 0;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 20),
child: InkWell(
onTap: () {
_counter++;
widget.titleNotifier.value = "title updated $_counter";
},
child: const Text("tap to update title")));
}
}

New route [webview] not displaying in full height

I am navigating the app screen to webview after pressing a row on listview. I have created two routes and it is navigating properly to the webview from listview.
But the height of webview is not matching to the height of device screen, i.e, it is showing the previous route (listview) when I Hot Reload the app, on the below of screen where the webview is not covering.
Below is my main.dart file.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:connectivity/connectivity.dart';
import 'package:toast/toast.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
void main() => runApp(new MyApp());
bool isData = false;
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Shop App',
theme
: new ThemeData(
primaryColor: Color.fromRGBO(58, 66, 86, 1.0), fontFamily: 'Raleway'),
home: MyHomePage(title: 'Shop App'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<bool> inputs = new List<bool>();
List list = List();
var isLoading = false;
var connectivityResult;
_fetchJSON() async {
setState(() {
isLoading = true;
});
var response = await http.get(
'http://indiagovt.org/android/flutter.php',
headers: {"Accept": "Application/json"},
);
if(response.statusCode == 200) {
list = json.decode(response.body) as List;
setState(() {
isLoading = false;
});
} else {
print('Something went wrong');
}
}
#override
void initState() {
super.initState();
setState(() {
_fetchJSON();
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Color.fromRGBO(58, 66, 86, 1.0),
appBar: new AppBar(
title: new Text('Shop App'),
),
body: isLoading ? Center (
child: CircularProgressIndicator(),
):
new ListView.builder(
itemCount: list.length,
itemBuilder: (BuildContext context, int index){
return new Card(
child: new Container(
padding: new EdgeInsets.all(10.0),
child: new Column(
children: <Widget>[
new ListTile(
title: new Text(list [index]['title']),
subtitle: new Text(list [index]['descr']),
leading: CircleAvatar(
child: Image.network(
list [index]['icon'],
),
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => webView(url: list[index]['link'], title: list[index]['name']),//goes to the next page & passes value of url and title to it
),
);
},
)
],
),
),
);
}
),
);
}
}
class webView extends StatelessWidget {
final String url;
final String title;
webView({Key key, #required this.url, #required this.title}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color.fromRGBO(58, 66, 86, 1.0),
appBar: AppBar(
title: Text(title),
),
body: new MaterialApp(
routes: {
"/": (_) => new WebviewScaffold(
url: url,
appBar: new AppBar(
),
withJavascript: true,
withLocalStorage: true,
)
},
)
);
}
}
App Screenshots:
WebView Screenshot:
Please help me to fix this issue.

setState doesn't update the interface

I'm trying to learn flutter but his has been in my way for over a week, I'm not able to get setState to work properly.
In this case I want to press a button and change its icon and properties, basically having another element but I just can't get it to work.
Here's my code for the widget:
import 'package:flutter/material.dart';
class UserButton extends StatefulWidget {
#override
_UserButtonState createState() => _UserButtonState();
}
class _UserButtonState extends State<UserButton> {
#override
Widget build(BuildContext context) {
bool loggedin = false;
return Container(
child: loggedin
? IconButton(
onPressed: () {
setState(() {
loggedin = false;
});
},
icon: Icon(Icons.person),
)
: IconButton(
onPressed: () {
setState(() {
loggedin = true;
});
},
icon: Icon(Icons.person_outline),
tooltip: "Login",
));
}
}
And here is the main app code:
import 'package:flutter/material.dart';
import 'package:orar/user_button.dart';
main(List<String> args) {
runApp(Home());
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme:
ThemeData(primaryColor: Colors.cyan, accentColor: Colors.cyanAccent),
home: Scaffold(
appBar: AppBar(
title: Text("test"),
actions: <Widget>[UserButton()],
),
body: ListView(
children: <Widget>[],
),
),
);
}
}
loggedin should be state variable. In your case it is local variable inside build method.
Move loggedin out of build method and it should work

Resources