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, but opacity doesn't work at all.
My approach
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.white.withOpacity(0.5),
child: Center(
child: SpinKitDualRing(
color: Colors.pinkAccent,
size: 45.0,
controller: AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1200),
),
),
),
)
I'm using here flutter_spinkit package as a spinner.
Full code
// ignore_for_file: prefer_const_constructors
// ignore: use_key_in_widget_constructors
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:splash_screen_view/SplashScreenView.dart';
void main(){
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor: Color(0xff1e2229)
));
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
Widget spalshfirst = SplashScreenView(
navigateRoute: WebViewClass(),
duration: 3000,
imageSize: 80,
imageSrc: 'assets/splash.png',
text: "Food Delivery",
textType: TextType.TyperAnimatedText,
textStyle: TextStyle(
fontSize: 25.0,
),
colors: const [
Colors.purple,
Colors.blue,
Colors.yellow,
Colors.red,
],
backgroundColor: Colors.white,
);
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: spalshfirst
)
);
}
}
class WebViewClass extends StatefulWidget {
WebViewState createState() => WebViewState();
}
class WebViewState extends State<WebViewClass> with TickerProviderStateMixin{
late 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
void initState() {
super.initState();
// Enable hybrid composition.
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
}
bool isLoading = false;
final key = UniqueKey();
int position = 0;
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () => _goBack(context),
child: Scaffold(
resizeToAvoidBottomInset: false,
appBar: null,
body: SafeArea(
child: IndexedStack(
index: position,
children: [
WebView(
initialUrl: 'https://google.com',
javascriptMode: JavascriptMode.unrestricted,
key: key,
onPageStarted: (value) {
setState(() {
position = 1;
});
},
onPageFinished: (value) {
setState(() {
position = 0;
});
},
onWebViewCreated: (WebViewController webViewController) {
_controllerCompleter.future
.then((value) => _controller = value);
_controllerCompleter.complete(webViewController);
},
),
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.white.withOpacity(0.5),
child: Center(
child: SpinKitDualRing(
color: Colors.pinkAccent,
size: 45.0,
controller: AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1200),
),
),
),
)
],
),
),
),
);
}
Future<bool> _goBack(BuildContext context) async {
if (await _controller.canGoBack()) {
_controller.goBack();
return Future.value(false);
} else {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Do you want to exit from Foodrive?'),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('No'),
),
TextButton(
onPressed: () {
SystemNavigator.pop();
},
child: Text('Yes'),
),
],
));
return Future.value(true);
}
}
}
Since the container is containing only the spinner, and not the background widget, settings its opacity won't work,
I'd suggest using the Stack widget with the Opacity widget
Something like this (just a reference point):
return Stack(children: [
Opacity(opacity: 0.5, child: resetOfTheWidgetTree),
Container(child: spinWidgetHere),
]);
Related
I created the named routes in my main but its not navigating.
Inside the mainbutton widget i'm passing the navigator it accepts three parameters all of them are required...
import 'package:flutter/material.dart';
import 'package:texty/screens/welcome_screen.dart';
import 'package:texty/screens/login_screen.dart';
import 'package:texty/screens/registration_screen.dart';
import 'package:texty/screens/chat_screen.dart';
void main() => runApp(FlashChat());
class FlashChat extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: WelcomeScreen.id,
routes: {
WelcomeScreen.id: (context) => WelcomeScreen(),
ChatScreen.Id: (context) => ChatScreen(),
LoginScreen.Id: (context) => LoginScreen(),
RegistrationScreen.Id: (context) => RegistrationScreen(),
},
);
}
}
my welcome screen ->
import 'package:flutter/material.dart';
import 'package:texty/widgets/mainbutton.dart';
import 'login_screen.dart';
import 'registration_screen.dart';
import 'package:animated_text_kit/animated_text_kit.dart';
class WelcomeScreen extends StatefulWidget {
static const String id = 'welcome_screen';
#override
_WelcomeScreenState createState() => _WelcomeScreenState();
}
class _WelcomeScreenState extends State<WelcomeScreen>
with SingleTickerProviderStateMixin {
late AnimationController controller;
late Animation animation;
#override
void initState() {
super.initState();
controller =
AnimationController(duration: Duration(seconds: 1), vsync: this);
animation = ColorTween(begin: Colors.blueGrey, end: Colors.white)
.animate(controller);
controller.forward();
controller.addListener(() {
setState(() {});
});
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: animation.value,
body: Padding(
padding: EdgeInsets.symmetric(horizontal: 24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Row(
children: <Widget>[
Hero(
tag: 'logo',
child: Container(
child: Image.asset('images/logo.png'),
height: 60.0,
),
),
TypewriterAnimatedTextKit(
text: ['Texxty '],
textStyle: TextStyle(
fontSize: 45.0,
fontWeight: FontWeight.w900,
),
),
],
),
SizedBox(
height: 48.0,
),
mainButton(
title: 'Log In',
colour: Colors.lightBlueAccent,
onPressed: () {
Navigator.pushNamed(context, LoginScreen.Id);
},
),
mainButton(
title: 'Register',
colour: Colors.blueAccent,
onPressed: () {
Navigator.pushNamed(context, RegistrationScreen.Id);
},
),
],
),
),
);
}
}
try an other Option
instead of naming the pages
Navigator.push(
context,
MaterialPageRoute(builder: (context) => LoginScreen()),
);
I'm building my first web app using Flutter Webview in which I embedded a bottom Navigation bar that further has 4 Icons.
Each Icon has its Own Class and by pressing on it launches a different Webview for each tab like the below example:
But the problem that I am facing right above is that you can see each tab cannot be pressed more than once at a time. What I'm looking for is to reopen the same tab like a hyperlink in html instead of once only.
Also, I have no idea how to refresh webview page when hitting the refresh icon no matter what page or tab I'm
main.dart
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:splash_screen_view/SplashScreenView.dart';
import 'pages/home_page.dart';
import 'pages/profile.dart';
import 'pages/cart.dart';
void main(){
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor: Color(0xff1e2229)
));
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
Widget spalshfirst = SplashScreenView(
navigateRoute: WebViewClass(),
duration: 3000,
imageSize: 80,
imageSrc: 'assets/splash.png',
text: "Food Delivery",
textType: TextType.TyperAnimatedText,
textStyle: TextStyle(
fontSize: 25.0,
),
colors: const [
Colors.purple,
Colors.blue,
Colors.yellow,
Colors.red,
],
backgroundColor: Colors.white,
);
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: spalshfirst
)
);
}
}
class WebViewClass extends StatefulWidget {
WebViewState createState() => WebViewState();
}
class WebViewState extends State<WebViewClass> with TickerProviderStateMixin{
#override
void initState() {
super.initState();
// Enable hybrid composition.
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
}
int currentIndex = 0;
#override
Widget build(BuildContext context) {
//Including Dart Webview pages
final screens = [
HomeClass(),
Center(child: Text('refresh')),
ProfileClass(),
CartClass()
];
return Scaffold(
resizeToAvoidBottomInset: true,
appBar: null,
body: SafeArea(
child: screens[currentIndex]
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: currentIndex,
selectedItemColor: Colors.white,
unselectedItemColor: Colors.white60,
onTap: (index) => setState(() => currentIndex = index),
items: const [
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.home),
label: 'Home',
backgroundColor: Colors.pink
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.refresh),
label: 'Refresh',
backgroundColor: Colors.pink
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.profile_circled),
label: 'Profile',
backgroundColor: Colors.pink
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.cart),
label: 'Cart',
backgroundColor: Colors.pink
)
],
) ,
);
}
}
Webview HomeClass() refrence
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class HomeClass extends StatefulWidget {
Homestate createState() => Homestate();
}
class Homestate extends State<HomeClass> with TickerProviderStateMixin{
late 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);
}
}
bool isLoading = false;
final key = UniqueKey();
int position = 0;
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () => _goBack(context),
child: Scaffold(
appBar: null,
body: IndexedStack(
index: position,
children: [
WebView(
initialUrl: 'https://google.com',
javascriptMode: JavascriptMode.unrestricted,
key: key,
onPageStarted: (value) {
setState(() {
position = 1;
});
},
onPageFinished: (value) {
setState(() {
position = 0;
});
},
onWebViewCreated: (WebViewController webViewController) {
_controllerCompleter.future.then((value) => _controller = value);
_controllerCompleter.complete(webViewController);
},
),
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.white.withOpacity(0.5),
child: Center(
child: SpinKitDualRing(
color: Colors.pinkAccent,
size: 45.0,
controller: AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1200),
),
),
),
)
],
))
);
}
//Go back coding
Future<bool> _goBack(BuildContext context) async {
if (await _controller.canGoBack()) {
_controller.goBack();
return Future.value(false);
} else {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Do you want to exit from Foodrive?'),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('No'),
),
TextButton(
onPressed: () {
SystemNavigator.pop();
},
child: const Text('Yes'),
),
],
));
return Future.value(true);
}
}
}
I found a solution after paid someone for this answer. In this solution developer added 2 new packages import 'package:get/get.dart'; and import 'package:testing/pages/navigation_controller.dart';
dependencies
dependencies:
flutter:
sdk: flutter
webview_flutter: ^2.3.0
flutter_spinkit: ^5.1.0
splash_screen_view: ^3.0.0
flutter_icons: ^1.1.0
pull_to_refresh: ^2.0.0
get:
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.4
main.dart
// ignore_for_file: prefer_const_constructors
// ignore: use_key_in_widget_constructors
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:testing/pages/navigation_controller.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:splash_screen_view/SplashScreenView.dart';
import 'initial_bindings.dart';
import 'pages/home_page.dart';
import 'pages/profile.dart';
import 'pages/cart.dart';
void main() {
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(statusBarColor: Color(0xff1e2229)));
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
Widget spalshfirst = SplashScreenView(
navigateRoute: WebViewClass(),
duration: 3000,
imageSize: 80,
imageSrc: 'assets/splash.png',
text: "Food Delivery",
textType: TextType.TyperAnimatedText,
textStyle: TextStyle(
fontSize: 25.0,
),
colors: const [
Colors.purple,
Colors.blue,
Colors.yellow,
Colors.red,
],
backgroundColor: Colors.white,
);
return GetMaterialApp(
initialBinding: InitialBindings(),
debugShowCheckedModeBanner: false,
home: Scaffold(body: spalshfirst));
}
}
class WebViewClass extends StatefulWidget {
WebViewState createState() => WebViewState();
}
class WebViewState extends State<WebViewClass> with TickerProviderStateMixin {
#override
void initState() {
super.initState();
// Enable hybrid composition.
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
}
int currentIndex = 0;
#override
Widget build(BuildContext context) {
//Including Dart Webview pages
final screens = [
HomeClass(),
// Center(child: Text('refresh')),
ProfileClass(),
CartClass()
];
return Scaffold(
resizeToAvoidBottomInset: true,
appBar: null,
body: SafeArea(child: screens[currentIndex]),
bottomNavigationBar: BottomNavigationBar(
backgroundColor: Colors.pink,
currentIndex: currentIndex,
selectedItemColor: Colors.white,
unselectedItemColor: Colors.white60,
onTap: (index) {
setState(() => currentIndex = index);
Get.find<NavigationController>().controller.value?.reload();
},
items: const [
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.home),
label: 'Home',
backgroundColor: Colors.pink),
// BottomNavigationBarItem(
// icon: Icon(CupertinoIcons.refresh),
// label: 'Refresh',
// backgroundColor: Colors.pink),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.profile_circled),
label: 'Profile',
backgroundColor: Colors.red),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.cart),
label: 'Cart',
backgroundColor: Colors.pink)
],
),
);
}
}
initial_bindings.dart
import 'package:get/get.dart';
import 'package:webview_flutter/webview_flutter.dart';
class NavigationController extends GetxController {
Rx<WebViewController?> controller = null.obs;
}
Home_page.dart same code for(profile.dart and cart.dart)
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:testing/pages/navigation_controller.dart';
import 'package:webview_flutter/webview_flutter.dart';
class HomeClass extends StatefulWidget {
Homestate createState() => Homestate();
}
class Homestate extends State<HomeClass> with TickerProviderStateMixin {
late WebViewController _controller;
final Completer<WebViewController> _controllerCompleter =
Completer<WebViewController>();
final RefreshController _refreshController =
RefreshController(initialRefresh: false);
late AnimationController animController;
#override
void initState() {
super.initState();
animController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1200),
);
}
#override
void dispose() {
animController.dispose();
super.dispose();
}
//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);
}
}
bool isLoading = false;
final key = UniqueKey();
int position = 0;
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () => _goBack(context),
child: Scaffold(
appBar: null,
body: SmartRefresher(
controller: _refreshController,
enablePullDown: true,
onRefresh: () {
Get.find<NavigationController>().controller.value?.reload();
_refreshController.refreshCompleted();
},
child: IndexedStack(
index: position,
children: [
WebView(
initialUrl: 'https://canada.ca',
javascriptMode: JavascriptMode.unrestricted,
key: key,
onPageStarted: (value) {
setState(() {
position = 1;
});
},
onPageFinished: (value) {
setState(() {
position = 0;
});
},
onWebViewCreated: (WebViewController webViewController) {
_controllerCompleter.future
.then((value) => _controller = value);
_controllerCompleter.complete(webViewController);
Get.find<NavigationController>().controller =
webViewController.obs;
},
),
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.white.withOpacity(0.5),
child: Center(
child: SpinKitDualRing(
color: Colors.pinkAccent,
size: 45.0,
controller: animController,
),
),
)
],
),
),
),
);
}
//Go back coding
Future<bool> _goBack(BuildContext context) async {
if (await _controller.canGoBack()) {
_controller.goBack();
return Future.value(false);
} else {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Do you want to exit from Foodrive?'),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('No'),
),
TextButton(
onPressed: () {
SystemNavigator.pop();
},
child: const Text('Yes'),
),
],
));
return Future.value(true);
}
}
}
I am a newbie in flutter and this is my first real use app.
This is what i want to achieve my app is going to be used to detect number-plates automatically when the camera would be pointed on the numberplate, for the text detection part i am going to use flutter ml kit. How should i write the start image stream method if i want the output of 10 images in the File data type which I would then add to my ImagePathList.
I did do research on this, but i did not find anything related to what i wanted to achieve, there are a few blog posts using this but they have not explained it properly so i turned to stack overflow.
I want the functionality to be like this
This is what my camera_screen looks like
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:firebase_ml_vision/firebase_ml_vision.dart';
import 'package:flutter/services.dart';
import 'package:npgroups/npgroups.dart';
import 'package:society_app/screens/result_screen.dart';
import 'package:society_app/widgets/common_drawer.dart';
import 'package:camera/camera.dart';
import 'dart:async';
import 'package:numeric_keyboard/numeric_keyboard.dart';
class CameraScreen extends StatefulWidget {
final CameraDescription camera;
static String id = 'camera_screen';
CameraScreen({required this.camera});
#override
_CameraScreenState createState() => _CameraScreenState();
}
class _CameraScreenState extends State<CameraScreen> {
Widget buildButton(String buttonText){
return Container(
height: MediaQuery.of(context).size.height * 0.1 * 0.85,
color: Colors.blueAccent,
child: FlatButton(
onPressed: () {},
child: Text(
buttonText,
style: TextStyle(
fontSize: 30.0,
fontWeight: FontWeight.normal,
color: Colors.white
),
)
),
);
}
late CameraController _controller;
late Future<void> _initializeControllerFuture;
late Npgroups _npgroups;
List imagePathList = [];
List<String?> detectedWordList = [];
static const MethodChannel _channel = const MethodChannel('tflite');
String? resultText;
late int imageHeight;
late int imageWidth;
bool? get isPaused => null;
#override
void initState() {
// TODO: implement initState
super.initState();
_controller = CameraController(
// Get a specific camera from the list of available cameras.
widget.camera,
// Define the resolution to use.
ResolutionPreset.medium,
);
_initializeControllerFuture = _controller.initialize();
initPlatformState();
}
Future<void> initPlatformState() async {
_npgroups = Npgroups(listenToNumplate);
await _npgroups.startListening();
}
#override
void dispose() {
// Dispose of the controller when the widget is disposed.
_controller.dispose();
super.dispose();
}
Future getNumberPlate(image) async {
FirebaseVisionImage mlImage = FirebaseVisionImage.fromFile(image);
TextRecognizer recognizeText = FirebaseVision.instance.textRecognizer();
VisionText readText = await recognizeText.processImage(mlImage);
for (TextBlock block in readText.blocks) {
for (TextLine line in block.lines) {
for (TextElement word in line.elements) {
resultText = word.text;
_npgroups.processNumberplate(resultText!);
}
}
}
if (resultText == null) {
print('null');
} else {
detectedWordList.add(resultText);
}
}
listenToNumplate(String numplate) {
//Consume the numplate
}
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: CommonDrawer(),
appBar: AppBar(
title: Text(
'Camera'
),
),
body: FutureBuilder<void>(
future: _initializeControllerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
children: [
AspectRatio(aspectRatio: _controller.value.aspectRatio - 0.2,
child: CameraPreview(_controller)),
Positioned(
bottom: 10,
left: 5,
child: Row(
children: [
VehicleButton(icon: Icons.motorcycle_outlined,),
SizedBox(width: 35),
VehicleButton(icon: Icons.directions_car,)
],
),
)
],
),
Row(
children: [
Container(
width: MediaQuery.of(context).size.width * .99,
child: Table(
children: [
TableRow(
children: [
buildButton('1'),
buildButton('2'),
buildButton('3')
]
),
TableRow(
children: [
buildButton('4'),
buildButton('5'),
buildButton('6')
]
),
TableRow(
children: [
buildButton('7'),
buildButton('8'),
buildButton('9')
]
),
TableRow(
children: [
buildButton('↻'),
buildButton('0'),
buildButton('⌫')
]
),
],
),
)
],
)
],
);
} else {
// Otherwise, display a loading indicator.
return const Center(child: CircularProgressIndicator());
}
},
),
);
}
}
class VehicleButton extends StatelessWidget {
final IconData icon;
VehicleButton({required this.icon});
#override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 17, horizontal: 50),
child: Icon(
icon,
color: Colors.white,
size: 45,
),
),
style: ButtonStyle(
shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)))
),
);
}
}
Blockquote
You can do something like that
#override
void initState() {
super.initState();
controller = CameraController(widget.cameras[0], ResolutionPreset.medium,
enableAudio: false);
controller.initialize().then((_) async {
if (!mounted) {
return;
}
setState(() {});
await controller.startImageStream((CameraImage availableImage) async {
_scanText(availableImage);
});
}
**main.dart**
import 'package:flutter/material.dart';
import 'package:world_time/pages/choose_location.dart';
import 'package:world_time/pages/home.dart';
import 'package:world_time/pages/loading.dart';
void main() => runApp(MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => Loading(),
'/home': (context) => Home(),
'/location': (context) => ChooseLocation(),
},
));
**home.dart**
import 'package:flutter/material.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
Map data = {};
#override
Widget build(BuildContext context) {
data = data.isNotEmpty ? data : ModalRoute.of(context).settings.arguments;
print(data);
// set background
String bgImage = data['isDaytime'] ? 'day.png' : 'night.png';
Color bgColor = data['isDaytime'] ? Colors.blue : Colors.indigo[700];
return Scaffold(
backgroundColor: bgColor,
body: SafeArea(
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/$bgImage'),
fit: BoxFit.cover,
),
),
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 120.0, 0, 0),
child: Column(
children: <Widget>[
FlatButton.icon(
onPressed: () async {
dynamic result =
await Navigator.pushNamed(context, '/location');
setState(() {
data = {
'time': result['time'],
'result': result['location'],
'isDaytime': result['isDaytime'],
'flag': result['flag'],
};
});
},
icon: Icon(
Icons.edit_location,
color: Colors.grey[300],
),
label: Text(
'Edit Location',
style: TextStyle(
color: Colors.grey[300],
),
),
),
SizedBox(height: 20.0),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
data['location'] ?? '',
style: TextStyle(
fontSize: 38.0,
letterSpacing: 2.0,
color: Colors.white,
),
),
],
),
SizedBox(height: 20.0),
Text(
data['time'] ?? '',
style: TextStyle(
fontSize: 66.0,
color: Colors.white,
),
),
],
),
),
),
),
);
}
}
**choose_location.dart**
import 'package:flutter/material.dart';
import 'package:world_time/services/world_time.dart';
class ChooseLocation extends StatefulWidget {
#override
_ChooseLocationState createState() => _ChooseLocationState();
}
class _ChooseLocationState extends State<ChooseLocation> {
List<WorldTime> locations = [
WorldTime(url: 'Europe/London', location: 'London', flag: 'uk.png'),
WorldTime(url: 'Europe/Berlin', location: 'Athens', flag: 'greece.png'),
WorldTime(url: 'Africa/Cairo', location: 'Cairo', flag: 'egypt.png'),
WorldTime(url: 'Africa/Nairobi', location: 'Nairobi', flag: 'kenya.png'),
WorldTime(url: 'America/Chicago', location: 'Chicago', flag: 'usa.png'),
WorldTime(url: 'America/New_York', location: 'New York', flag: 'usa.png'),
WorldTime(url: 'Asia/Seoul', location: 'Seoul', flag: 'south_korea.png'),
WorldTime(url: 'Asia/Jakarta', location: 'Jakarta', flag: 'indonesia.png'),
];
void updateTime(index) async {
WorldTime instance = locations[index];
await instance.getTime();
// navigate to home screen
Navigator.pop(context, {
'location': instance.location,
'flag': instance.flag,
'time': instance.time,
'isDaytime': instance.isDaytime,
});
}
#override
Widget build(BuildContext context) {
print('build function ran');
return Scaffold(
backgroundColor: Colors.grey[200],
appBar: AppBar(
backgroundColor: Colors.blue[900],
title: Text('Choose a Location'),
centerTitle: true,
elevation: 0,
),
body: ListView.builder(
itemCount: locations.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 1.0, horizontal: 4.0),
child: Card(
child: ListTile(
onTap: () {
updateTime(index);
},
title: Text(locations[index].location),
leading: CircleAvatar(
backgroundImage:
AssetImage('assets/${locations[index].flag}'),
),
),
),
);
},
),
);
}
}
**loading.dart**
import 'package:flutter/material.dart';
import 'package:world_time/services/world_time.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
class Loading extends StatefulWidget {
#override
_LoadingState createState() => _LoadingState();
}
class _LoadingState extends State<Loading> {
void setupWorldTime() async {
WorldTime instance = WorldTime(
location: 'Berlin', flag: 'germany.png', url: 'Europe/Berlin');
await instance.getTime();
Navigator.pushReplacementNamed(context, '/home', arguments: {
'location': instance.location,
'flag': instance.flag,
'time': instance.time,
'isDaytime': instance.isDaytime,
});
}
#override
void initState() {
super.initState();
setupWorldTime();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blue[900],
body: Center(
child: SpinKitFadingCircle(
color: Colors.white,
size: 50.0,
),
),
);
}
}
**world_time.dart**
import 'package:http/http.dart';
import 'dart:convert';
import 'package:intl/intl.dart';
class WorldTime {
String location; // location name for the UI
String time; //the time in that location
String flag; //url to an asset flag icon
String url; //location url for api endpoint
bool isDaytime; //true or false if daytime or not
WorldTime({this.location, this.flag, this.url});
Future<void> getTime() async {
//make the request
Response response =
await get(Uri.parse('https://worldtimeapi.org/api/timezone/$url'));
Map data = jsonDecode(response.body);
//print(data);
//get properties from data
String datetime = data['datetime'];
String offset = data['utc_offset'].substring(1, 3);
//print(datetime);
//print(offset);
//create DateTime object
DateTime now = DateTime.parse(datetime);
now = now.add(Duration(hours: int.parse(offset)));
//set the time property
isDaytime = now.hour > 6 && now.hour < 20 ? true : false;
time = DateFormat.jm().format(now);
}
}
WorldTime instance =
WorldTime(location: 'Berlin', flag: 'germany.png', url: 'Europe/Berlin');
Here are my codes for building a World time app on flutter
No error message seen on the output, but when a new city or location is selected, It displays only the time on the device without displaying the corresponding city for the current time displayed on the screen. Please how can I fix this without blowing up my codes. Thanks
On your flatbutton onpressed you have set the location key to 'result' change it to 'location'.
FlatButton.icon(
onPressed: () async {
dynamic result =
await Navigator.pushNamed(context, '/location');
setState(() {
data = {
'time': result['time'],
// Change This
>>> 'result': result['location'], <<<
// To This
>>> 'location': result['location'], <<<
'isDaytime': result['isDaytime'],
'flag': result['flag'],
};
});
},
I'm using Flutter for first time for one of my projects which is a Newspaper App.
The problem takes place when I try to navigate from main.dart to newsfeed_for_other_category.dart using MaterialPageRoute from my Drawer. In that screen it shows the news but with a black background. But in the screen newsfeed_screen.dart which is called in the body in my main.dart it shows perfectly.
I'm posting the codes below.
main.dart
import 'package:flutter/material.dart';
import './SizeConfig.dart';
import './screens/newsfeed_screen.dart';
import 'package:curved_navigation_bar/curved_navigation_bar.dart';
import 'factory/widget_factory.dart';
import 'widgets/top_news_widget.dart';
import 'package:splashscreen/splashscreen.dart';
import './widgets/drawer.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Newspaper App',
theme: ThemeData(
primarySwatch: Colors.blue,
//backgroundColor: Colors.lightGreenAccent,
),
home: MyHomePage(title: 'The Business Standard'),
routes: <String, WidgetBuilder> {
'/screen1': (BuildContext context) => new NewsFeedScreen(216, 5, "Top News"),
'/screen2' : (BuildContext context) => new NewsFeedScreen(4, 7, "National"),
'/screen3' : (BuildContext context) => new NewsFeedScreen(13, 70, "International"),
/*'/screen4' : (BuildContext context) => new Screen4()*/
},
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>(debugLabel: '_MainScreenKey');
Widget build(BuildContext context) {
return SplashScreen(
seconds: 3,
navigateAfterSeconds: AfterSplash(),
title: Text(
'The Business Standard',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20.0
),
),
image: Image.asset(
'assets/TBS_logo.jpg',
),
backgroundColor: Colors.white,
styleTextUnderTheLoader: TextStyle(),
photoSize: 100.0,
onClick: ()=>print("Flutter Egypt"),
loaderColor: Colors.red
);
}
}
class AfterSplash extends StatefulWidget {
#override
_AfterSplashState createState() => _AfterSplashState();
}
class _AfterSplashState extends State<AfterSplash> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>(debugLabel: '_MainScreenKey');
#override
Widget build(BuildContext context) {
SizeConfig().init(context);
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
backgroundColor: Colors.white,
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Image.asset(
'assets/TBS.png',
fit: BoxFit.cover,
height: 45,
)
],
),
leading: IconButton(
icon: Icon(Icons.dehaze),
color: Colors.black,
onPressed: () => _scaffoldKey.currentState.openDrawer(),
),
),
drawer: SideDrawer(),
body: NewsFeedScreen(22, 71, "Sports"),
bottomNavigationBar: CurvedNavigationBar(
backgroundColor: const Color(0xFF2b4849),
items: <Widget>[
Icon(Icons.bookmark, size: 30,),
Icon(Icons.perm_identity, size: 30,),
Icon(Icons.settings, size: 30,),
],
onTap: (index) {
if(index == 2) {
_scaffoldKey.currentState.showSnackBar(const SnackBar(
content: const Text('Will open Settings menu')));
} else if(index == 0) {
_scaffoldKey.currentState.showSnackBar(const SnackBar(
content: const Text('Implement Bookmark function')));
} else {
_scaffoldKey.currentState.showSnackBar(const SnackBar(
content: const Text('Will show User profile and information')));
}
},
),
);
}
}
newsfeed_for_other_category.dart, the page to which I'm navigating and this is where the black background shows up.
import 'package:flutter/material.dart';
import '../SizeConfig.dart';
import '../widgets/headlines.dart';
import '../widgets/secondary_headlines.dart';
import '../widgets/listed_news.dart';
import '../models/NewsPost.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:developer';
import '../screens/newsPost_details.dart';
import '../screens/newsfeed_for_specific_category.dart';
import 'package:flutter_swiper/flutter_swiper.dart';
import '../transition_animation_routes/ScaleTransitionRoute.dart';
import '../widgets/top_news_widget.dart';
class NewsfeedForOtherCategory extends StatefulWidget {
int categoryId;
int childrenCategoryId;
String categoryName;
NewsfeedForOtherCategory(this.categoryId, this.childrenCategoryId, this.categoryName);
#override
_NewsfeedForOtherCategoryState createState() => _NewsfeedForOtherCategoryState(this.categoryId, this.childrenCategoryId, this.categoryName);
}
class _NewsfeedForOtherCategoryState extends State<NewsfeedForOtherCategory> {
int categoryId;
int childrenCategoryId;
String categoryName;
_NewsfeedForOtherCategoryState(this.categoryId, this.childrenCategoryId, this.categoryName);
bool _isRequestSent = false;
List<NewsPost> newsPostList = [];
#override
Widget build(BuildContext context) {
SizeConfig().init(context);
if(!_isRequestSent) {
_sendRequest();
}
return Container(
alignment: Alignment.center,
child: !_isRequestSent
? CircularProgressIndicator()
: Container(
child: ListView.builder(
itemCount: newsPostList.length,
scrollDirection: Axis.vertical,
itemBuilder: (BuildContext context, int index) {
return _getNewsPostWidgets(index);
}
),
),
);
}
void _sendRequest() async {
String url = "https://tbsnews.net/json/category/news/"+this.categoryId.toString()+"/"+this.childrenCategoryId.toString()+"";
http.Response response = await http.get(url);
List<dynamic> decode = json.decode(response.body);
log('response: $response');
List results = decode[0]['items'];
for (var jsonObject in results) {
var post = NewsPost.getNewsPostFromAPI(jsonObject);
newsPostList.add(post);
print(post);
}
setState(() => _isRequestSent = true);
}
Widget _getNewsPostWidgets(int index) {
var newsPost = newsPostList[index];
if(index < this.newsPostList.length) {
if(index == 0) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
ScaleTransitionRoute(
page: NewsPostDetails(newsPostList, index)
)
);
},
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(10, 0, 0, 0),
//constraints: BoxConstraints(minWidth: double.infinity, maxWidth: double.infinity),
constraints: BoxConstraints.expand(
width: double.infinity,
height: 40
),
color: const Color(0xFF2b4849),
child: Text(
this.categoryName,
style: TextStyle(
fontSize: 33,
color: Colors.white
),
),
),
BlockHeadline(newsPost)
],
)
);
}
else {
return GestureDetector(
onTap: () {
Navigator.push(
context,
ScaleTransitionRoute(
page: NewsPostDetails(newsPostList, index)
)
);
},
child: ListedNews(newsPost),
);
}
}
else {
return Container(
color: const Color(0xFF2b4849),
child: index == 3 ? FlatButton(
child: Text(
"Load More",
style: TextStyle(
color: Colors.white
),
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => NewsFeedForSpecificCategory(newsPostList)
)
);
},
) : Container(),
);
}
}
openNewsPostDetails(List<NewsPost> newsPostList, int index) {
Navigator.push(
context,
ScaleTransitionRoute(
page: NewsPostDetails(newsPostList, index)
)
);
}
}
drawer.dart
import 'package:flutter/material.dart';
import '../SizeConfig.dart';
import '../screens/newsfeed_for_other_category.dart';
class SideDrawer extends StatelessWidget {
#override
Widget build(BuildContext context) {
SizeConfig().init(context);
return SizedBox(
width: SizeConfig.safeBlockHorizontal*50,
child: Theme(
data: Theme.of(context).copyWith(canvasColor: const Color(0xFF2b4849)),
child: Drawer(
child: ListView(
children: <Widget>[
ListTile(
title: Text(
'Top News',
style: TextStyle(
fontSize: 20,
color: Colors.white
),
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => NewsfeedForOtherCategory(216, 5, "Top News")
)
);
},
),
],
),
),
),
);
}
}
In my home screen which is newsfeed_screen.dart called in the body of AfterSplashState widget in main.dart it looks like below, this is what it should look like.
But in the screen NewsfeedForOtherCategory to which I navigate using drawer looks like below with the black background.
I have tried using Navigator.of(context, rootNavigator: true).pushNamed('/route') and pushReplacementNamed() also instead of MaterialPageRoute. But of no use.
Here is a related question that I found, I tried the solutions they gave, but did not work for me.
Also to mention, the page I'm navigating to does not have MaterialApp widget, only the main.dart has it. So there should not be an issue.
I'm using a Ubuntu 16.04 machine.
Some clue from you would be priceless. Thanks a lot for your time.
NewsfeedForOtherCategory page is black because it doesn't have Material container.
You can simply wrap it with Material widget or Scaffold(which has some additional features like drawer, floating action button).
And from your screenshot I can see some widgets are overflowed by notification bar. You can use SafeArea inside Material or inside body of the Scaffold to overcome this.
Wrap the main Container in NewsfeedForOtherCategory with a scaffold and you have your solution.
...
return Scaffold(
body: Container(
alignment: Alignment.center,
child: !_isRequestSent
? CircularProgressIndicator()
: Container(
child: ListView.builder(
itemCount: newsPostList.length,
scrollDirection: Axis.vertical,
itemBuilder: (BuildContext context, int index) {
return _getNewsPostWidgets(index);
}
),
),
);
);
...
In the build function of your NewsfeedForOtherCategory widget,
try wrapping what you have there in a Scaffold.
Like:
return Scaffold(
body: Container(
alignment: Alignment.center,
child: !_isRequestSent
? CircularProgressIndicator()
: Container(
child: ListView.builder(
itemCount: newsPostList.length,
scrollDirection: Axis.vertical,
itemBuilder: (BuildContext context, int index) {
return _getNewsPostWidgets(index);
}),
),
),
),
when we navigate between two screen both screen parent should be scafold
if you don't want to use scaffold u can use container color property also
Try wrapping your container in scaffold in NewsfeedForOtherCategory screen Like this
...
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
),
);
}
...
Or u can set container color white like this
...
#override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child:
//enter code here
);
}
...