I am working on a project in Flutter. The issue is that when I navigate to a different page, and then go back, there is an icon that I used a while ago while testing that appears on the home page's appbar. I went back into the code, and there wasn't leading within that page's appbar.
Here is a screenshot after a complete rebuild of the app.
After navigating to another page using Navigator.of(context).pushNamed('/streaks/edit/'):
And finally, navigating back to the home page using Navigator.of(context).pushNamed('/streaks/all/'):
main.dart code:
import 'package:flutter/material.dart';
import 'package:streaks/pages/all_streaks/all_streaks.dart';
import 'package:streaks/pages/edit_streak/edit_streak.dart';
void main() => runApp(StreaksApp());
class StreaksApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'streaks',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
initialRoute: '/streaks/all/',
routes: <String, WidgetBuilder>{
'/streaks/all/': (context) => AllStreaksPage(),
'/streaks/edit/': (context) => EditStreakPage(),
},
);
}
}
home page code (/streaks/all/):
import 'package:flutter/material.dart';
import 'streak_list.dart';
class AllStreaksPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('All Streaks'),
),
body: StreakList(),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.of(context).pushNamed('/streaks/edit/');
},
child: Icon(Icons.add, size: 40),
),
);
}
}
and the Edit Streak page (/streaks/edit/):
import 'package:flutter/material.dart';
import 'package:streaks/pages/edit_streak/streak_form.dart';
class EditStreakPage extends StatefulWidget {
#override
_EditStreakPageState createState() => _EditStreakPageState();
}
class _EditStreakPageState extends State<EditStreakPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.close, color: Theme.of(context).buttonColor),
onPressed: () {
Navigator.pushNamed(context, '/streaks/all/');
}),
title: Text('Edit Streak'),
),
body: StreakForm()
);
}
}
pubspec.yaml:
name: streaks
description: An app to boost your productivity with event organization.
publish_to: "none"
version: 1.0.0+1
environment:
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
sqflite:
path:
flutter_iconpicker: ^2.1.5
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
uses-material-design: true
Note: there aren't any errors logged into the debug console at any time.
Another Note: even after deleting the app and running again, there error persisted.
Please help. I was thinking it might be (a) a caching error or (b) there is a problem with stateless widgets as pages.
1st way:
In your EditStreakPage class, instead of using Navigator.pushNamed(context, '/streaks/all/'); use Navigator.pop(context)
Complete class code:
import 'package:flutter/material.dart';
import 'package:streaks/pages/edit_streak/streak_form.dart';
class EditStreakPage extends StatefulWidget {
#override
_EditStreakPageState createState() => _EditStreakPageState();
}
class _EditStreakPageState extends State<EditStreakPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.close, color: Theme.of(context).buttonColor),
onPressed: () {
Navigator.pop(context); // <-- use this intead
}),
title: Text('Edit Streak'),
),
body: StreakForm()
);
}
}
2nd way:
In your AllStreaksPage class, pass the property automaticallyImplyLeading: false to the AppBar()
Complete class code:
import 'package:flutter/material.dart';
import 'streak_list.dart';
class AllStreaksPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false; // <--- add this
title: Text('All Streaks'),
),
body: StreakList(),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.of(context).pushNamed('/streaks/edit/');
},
child: Icon(Icons.add, size: 40),
),
);
}
}
From what i understand you are saying that actions is appering when you Open YOur App -> EDitStreak Page->press the close button on top in editStreak page ..
The key reason for this is that instead of going back you are actually going to that page by navigating to it . in which the back button would lead you back to edit Streaks page .
Instead of Navigating You Should use
Navigator.of(context).pop()
and that should solve your issue , let me know in comments , if it helps
Related
I am coding a PDF on flutter using 'syncfusion_flutter_pdfviewer' library. I tried everything but always I receive the same error message:
Next code I'm trying
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
void main() {
runApp(MaterialApp(
title: 'Syncfusion PDF Viewer Demo',
home: HomePage(),
));
}
/// Represents Homepage for Navigation
class HomePage extends StatefulWidget {
#override
_HomePage createState() => _HomePage();
}
class _HomePage extends State<HomePage> {
final GlobalKey<SfPdfViewerState> _pdfViewerKey = GlobalKey();
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Syncfusion Flutter PDF Viewer'),
actions: <Widget>[
IconButton(
icon: const Icon(
Icons.bookmark,
color: Colors.white,
semanticLabel: 'Bookmark',
),
onPressed: () {
_pdfViewerKey.currentState?.openBookmarkView();
},
),
],
),
body: SfPdfViewer.network(
'https://cdn.syncfusion.com/content/PDFViewer/flutter-succinctly.pdf',
key: _pdfViewerKey,
),
);
}
}
Had a similar problem and it turned out to be a mismatch between plugin version and flutter version. (I went back and forth to a new Flutter version).
Wrote a more detailed answer here: Flutter completely broken after update (again)
Also - the syncfusion support proved very useful for this
There is a strange behavior in Flutter I faced recently that I can not explain. Consider the following code being built for WEB platform:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Hello World',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatelessWidget {
final String title;
const MyHomePage({this.title = "Home Page"});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: const Center(
child: Text(
'Hello, World!',
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (_) => DraggableScrollableSheet(
expand: false,
builder: (_, ScrollController scrollController) {
return ListView(
controller: scrollController,
children: [for (var i = 0; i < 250; i++) Text("Item: $i")],
);
},
),
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20))),
),
tooltip: "Open Sheet!",
child: const Icon(Icons.add),
),
);
}
}
It works perfectly fine and as expected when opened from mobile device: the DraggableScrollableSheet gets opened, takes 50% of the screen height, and then the ListView inside it may be scrolled along with Sheet itself, so it will take from 0% to 100% of the screen.
However, if opened in desktop browser, the DraggableScrollableSheet just refuses to be scrolled together with ListView on mouse wheel rotation. It just sticks to 50% and can only be closed and never expanded!
An I missing something? Is it a flutter bug? How do I make it work in desktop browsers as expected?
P.S. here is a slightly more complex example of the behavior in my app, hosted on GitHub pages; for ModalBottomSheet to get opened, you should touch Flutter icon in the center of St. Petersburg.
This is probably a bug, you can work around this problem using the following parameter (next to "Expand"): "initialChildSize: 1.0"
This will set the initial size to 100% DraggableScrollableSheet parameters
I've conducted a long research on the internet about this (what I think is mischievous) use of Material widget in flutter, Any flutter developer faced the No Material widget found. exception even when using cupertino design widgets.
A simple example to produce is
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class Example extends StatelessWidget {
const Example({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('Example'),
leading: IconButton(
onPressed: () {},
icon: Icon(
Icons.close,
color: Colors.black54,
),
),
),
child: Center(
child: IconButton(
onPressed: () {},
icon: Icon(
Icons.close,
color: Colors.black54,
),
),
),
);
}
}
Neither the navigationBar nor the body IconButton will work resulting in the same exception.
When facing this exception I always wrap it inside a Material to bypass it, but I think am doing it wrong.IconButton is not the only widget and I've searched a lot with no avail.
Please tell me what am I missing ? and thanks in advance.
You need to wrap your root Widget in MaterialApp() so that you can access Material components.
For example,
import 'package:flutter/material.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: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
Not sure about the Cupertino part, but (afaik) you need to wrap your app in MaterialApp() to access Material widgets and other methods etc.
For MaterialApp you have to use IconButton, for CupertinoApp you have to use CupertinoButton but instead of icon use child
I have the following example to change from dark to light mode using Getx. So far it is working. But i would also that the IconButton who change the Theme, would also change is own icon.
What im doing wrong?
import 'package:flutter/material.dart';
import 'package:get/get.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GetMaterialApp(
debugShowCheckedModeBanner: false,
title: 'Change Theme',
darkTheme: ThemeData.dark(),
themeMode: ThemeMode.system,
home: HomeScreen(),
);
}
}
// Home Screen
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
var selected = true;
return Scaffold(
appBar: AppBar(
title: Text('Change Theme'),
actions: [
IconButton(
icon: Icon(
selected ? Icons.dark_mode : Icons.light_mode,
),
onPressed: () {
Get.isDarkMode
? Get.changeTheme(ThemeData.light())
: Get.changeTheme(ThemeData.dark());
})
],
),
);
}
}
You need to wrap the icon in a GetX widget that rebuilds based on a variable that lives in a GetX class.
Create a Getx class with a function that changes the theme based on the value of the local boolean.
class ThemeController extends GetxController {
bool isDarkMode = true;
void toggleDarkMode() {
isDarkMode = !isDarkMode;
if (isDarkMode) {
Get.changeTheme(ThemeData.dark());
} else {
Get.changeTheme(ThemeData.light());
}
update();
}
Then wrap your icon in a GetBuilder<ThemeController>
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
Get.put(ThemeController());
return Scaffold(
appBar: AppBar(
title: Text('Change Theme'),
actions: [
GetBuilder<ThemeController>(
builder: (controller) => IconButton(
icon: Icon(
controller.isDarkMode ? Icons.dark_mode : Icons.light_mode,
),
onPressed: () => controller.toggleDarkMode()
],
),
);
}
}
My VsCode is outta commission because I'm traveling with painfully slow internet and I'm in the middle of a multi hour flutter upgrade. So there might be some syntax or minor formatting errors but besides that this should work.
I used the url_luncher package and it suggests handle the missing URL receiver in case of target platform can not handle the URL.
So I create a function to handle of onTap of CardTile widget and dial the phone number and if the target platform can not handle the request it shows a snake bar to inform the user in UI.
But I have two problems 1) if using an anonymous function I get a runtime error and my code would be wordly and long
Unhandled Exception: No ScaffoldMessenger widget found.
MyApp widgets require a ScaffoldMessenger widget ancestor.
The specific widget that could not find a ScaffoldMessenger ancestor was:
MyApp
The ancestors of this widget were:
[root]
Typically, the ScaffoldMessenger widget is introduced by the MaterialApp at the top of your application widget tree.
if use function name onTap of CardTile widget for example onTap : _urlLauncherFunction(context) I can not pass BuildContext context argument to the function and get a compile error
This expression has a type of 'void' so its value can't be used.
I could not figure out what did wrong so please guide and help me to solve this.
I paste the anonymous function version here
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:url_launcher/url_launcher.dart';
void main() {
runApp(MyApp());
}
final telLaunchErrorSnackBar = SnackBar(
content:
Text('Your device can not handle this url'));
final String _myPhoneNumber = '+9812345678';
//use xml scheme to trigger error otherwise it should be tel
final Uri _telUri = Uri(scheme: 'xml', path: _myPhoneNumber);
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: Column(
children: [
CircleAvatar(
backgroundImage: AssetImage('images/image.jpg'),
),
Card(
child: ListTile(
leading: Icon(
Icons.phone,
),
title: Text(
'00 123 45657',
),
onTap: () async {
String telUri = _telUri.toString();
await canLaunch(telUri)
? await launch(telUri)
: ScaffoldMessenger.of(context)
.showSnackBar(telLaunchErrorSnackBar);
},
),
),
],
),
),
),
);
}
}
When I code as this , flutter throw a error.
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
// home: MyHomePage(title: 'Flutter Demo Home Page'),
home: Scaffold(
body: SafeArea(
child: Container(
alignment: Alignment.center,
child: GestureDetector(
child: Container(
width: 100,
height: 100,
color: Colors.green,
),
onTap: (){
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('content')));
},
),
),
),
),
);
}
}
then I change
...
MaterialApp(
home:Scafford(...),
)
...
to
...
MaterialApp(
home:Home(),
)
...
class Home extends StatelessWidget {
#override
Widget build(BuildContext context){
return Scaffold(...);
}
}
It works.