I'm new in Flutter.
I have a question
How to call layouts in flutter ?
I've been create some layouts that contains a lot of widget.
It's not right if I make every code inside 1 file.
so I decide to put the code for the widgets in every 1 layouts file.
and I dont know how to call them in the home-page.dart that I create.
I mean, if I push THIS (i.e page1.dart), then the page1.dart is appear.
thought that file (page1.dart) is in other directory (not inside lib dir).
I dont know. am I should use ROUTES ?
but I dont know how.
would you like to teach me ?
..............
here are. I have TabBar like this in my home_page.dart:
import 'package:flutter/material.dart';
import 'package:coba/second.dart';
class HomePage extends StatelessWidget {
static String tag = 'home-page';
#override
Widget build(BuildContext ctxt) {
return new MaterialApp(
title: "MySampleApplication",
home: new DefaultTabController(
length: 3,
child: new Scaffold(
appBar: new AppBar(
title: new Text("Hello Flutter App"),
bottom: new TabBar(
tabs: <Widget>[
new Tab(text: "First Tab"),
new Tab(text: "Second Tab"),
new Tab(text: "Third Tab"),
],
),
),
body: new TabBarView(
children: <Widget>[
new Text("You've Selected First"),
new SecondWidget(),
new ThirdWidget(),
]
)
),
)
);
}
}
class SecondWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
second(data: 'Hello there from the first page!'),
),
}
}
class ThirdWidget extends StatelessWidget {
#override
Widget build(BuildContext ctxt) {
return new Column(
children: <Widget>[
Text('halooo'),
Container(
color: Colors.black,
width: 200,
height: 200,
)
],
);
}
}
thank you so much
You can use any name that you want (generally, we have seen xxxScreen.dart or xxxPage.dart, but it is totally up to you).
Import your "destiny" page using in "origin" page using import:
import 'package:myproject/myPageScreen.dart';
Flutter offers 3 options:
Using Navigator:
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
SecondPage(data: 'Hello there from the first page!'),
),
Using Named routes:
Declare you routes in MaterialApp:
MaterialApp(
// Start the app with the "/" named route. In our case, the app will start
// on the FirstScreen Widget
initialRoute: '/',
routes: {
// When we navigate to the "/" route, build the FirstScreen Widget
'/': (context) => FirstScreen(),
// When we navigate to the "/second" route, build the SecondScreen Widget
'/second': (context) => SecondScreen(),
},
);
And then use named route with Navigator:
onPressed: () {
Navigator.pushNamed(context, '/second');
}
Using onGenerateRoute:
Declare this property on your MaterialApp:
return MaterialApp(
// Initially display FirstPage
initialRoute: '/',
onGenerateRoute: _getRoute,
);
And create your route generator :
final args = settings.arguments;
switch (settings.name) {
case '/':
return MaterialPageRoute(builder: (_) =>
FirstPage());
case '/second':
// Validation of correct data type
if (args is String) {
return MaterialPageRoute(
builder: (_) => SecondPage(
data: args,
),
);
}
You can create your router as another file to help to organize your project.
Related
Excuse me guys, i tryin to build a new page, but with variable "nextcode" in it. so in the new page, it will show nextcode text
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Lemari(nextcode)));
},
but in the line "Widget build(String Kode) {" it must be like this "Widget build(BuildContext context) {"
class Lemari extends StatelessWidget {
#override
Widget build(String Kode) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue[900],
title: Text('this is th next page'),
),
backgroundColor: Colors.white,
body: Center(
child: Column(
children: [
Container(height: 100, width: 100, color: Colors.red, child: Text('hhe'),),
]
),
),
);
}
}
So anyone who can help me ? please :(
You don't have to change the build method parameters instead you should add a new parameter in the widget and require it
Example
const MyPageView({Key? key}) : super(key: key);
Here you can add another parameter.
Then inside the class you define that parameter.. so when you make a new MyPageView you will have to pass the newly added parameter
Bye :)
Your code should have a compiler error
In Lemari , you never declare nextcode and constructor also do not have parameter nextcode.
You can try like this, add
class Lemari extends StatelessWidget {
final String nextcode;
const Lemari({Key key, this.nextcode}) : super(key: key);
#override
Widget build(BuildContext context) {}
}
if your nextcode is String
i have an issue with the widget unmounted with dismissdirection action on flutter. When I left swipe the dismissible item with the deleted action confirmed, the error occured as following:
The following assertion was thrown while notifying status listeners for AnimationController:
This widget has been unmounted, so the State no longer has a context (and should be considered
defunct).
Consider canceling any active work during "dispose" or using the "mounted" getter to determine if
the State is still active.
The full error codes are here
My code:
home_page.dart. The homepage I use statefulwidget and redirect to ExpensesCategoryHistory() Screen.
class HomePage extends StatefulWidget {
const HomePage({Key key, this.database, this.budget}) : super(key: key);
final DatabaseService database;
final Budget budget;
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
final database = Provider.of<DatabaseService>(context, listen: false);
PersistentTabController _controller;
_controller = PersistentTabController(initialIndex: 0);
return PersistentTabView(
context,
controller: _controller,
screens: _buildScreens(),
items: _navBarsItems(),
confineInSafeArea: true,
backgroundColor: Colors.white,
handleAndroidBackButtonPress: true,
resizeToAvoidBottomInset: true,
stateManagement: true,
hideNavigationBarWhenKeyboardShows: true, // Recommended to set 'resizeToAvoidBottomInset' as true while using this argument. Default is true.
decoration: NavBarDecoration(
borderRadius: BorderRadius.circular(10.0),
colorBehindNavBar: Colors.white,
),
popAllScreensOnTapOfSelectedTab: true,
popActionScreens: PopActionScreensType.all,
itemAnimationProperties: ItemAnimationProperties( // Navigation Bar's items animation properties.
duration: Duration(milliseconds: 200),
curve: Curves.ease,
),
screenTransitionAnimation: ScreenTransitionAnimation( // Screen transition animation on change of selected tab.
animateTabTransition: true,
curve: Curves.ease,
duration: Duration(milliseconds: 200),
),
navBarStyle: NavBarStyle.style15, // Choose the nav bar style with this property.
);
}
}
List<Widget> _buildScreens() {
return [
Home(),
ExpensesCategoryHistory(),
BudgetPage(),
Container(),
Container()
];
}
Then, in the ExpensesCategoryHistory() class. So, user can select the category and prompt expenses based on the category (when the list item is tapped.) Refer Steps 4 of error occured with images
class ExpensesCategoryHistory extends StatefulWidget {
#override
_ExpensesCategoryHistoryState createState() => _ExpensesCategoryHistoryState();
}
class _ExpensesCategoryHistoryState extends State<ExpensesCategoryHistory> {
var categoryList = ["Beauty", "Entertainment", "Food & Drinks", "Groceries", "Medical", "Transport", "Others"];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: kPrimaryColor,
title: Text('Expenses History By Category'),
),
body: _buildContents(context),
floatingActionButton: FloatingActionButton(
backgroundColor: kPrimaryColor,
child: Icon(Icons.add),
onPressed: () => EditExpensesPage.show(context,
database: Provider.of<DatabaseService>(context, listen: false),
),
),
);
}
Widget _buildContents(BuildContext context) {
final database = Provider.of<DatabaseService>(context, listen: false);
return ListView.builder(
itemCount: categoryList.length,
itemBuilder: (context, index){
return ListTile(
title: Text('${categoryList[index]}'),
onTap: () {
if(mounted){
Navigator.push(
context,
MaterialPageRoute<Widget>(
builder: (context) => ExpensesHistory(Category: categoryList[index]),
),
);
}
},
);
},
);
}
}
Then, lasty the main issue is here. When user select on delete action after left swipe of item. The error code occurred and did not perform Navigator.of(context).pop(true)
ExpensesHistory class
class ExpensesHistory extends StatelessWidget {
// Declare a field that holds the Todo.
final String Category;
// In the constructor, require a Todo.
ExpensesHistory({Key key, #required this.Category}) : super(key: key);
Future<void> _delete(BuildContext context, Expense expense) async {
try {
final database = Provider.of<DatabaseService>(context, listen: false);
await database.deleteExpenses(expense);
} on PlatformException catch (e) { //handle error
PlatformExceptionAlertDialog(
title: 'Operation failed',
exception: e,
).show(context);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: kPrimaryColor,
title: Text('$Category'),
),
body: _buildContents(context),
floatingActionButton: FloatingActionButton(
backgroundColor: kPrimaryColor,
child: Icon(Icons.add),
onPressed: () => EditExpensesPage.show(context,
database: Provider.of<DatabaseService>(context, listen: false),
),
),
);
}
Widget _buildContents(BuildContext context) {
final database = Provider.of<DatabaseService>(context, listen: false);
List myExpenses = [];
return StreamBuilder<List<Expense>>(
stream: database.expensesStream(),
builder: (context, snapshot) {
return ListItemsBuilder<Expense>(
snapshot: snapshot,
itemBuilder: (context, expense) =>
Dismissible(
confirmDismiss: (DismissDirection direction) async {
return await showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("Delete Confirmation"),
content: const Text(
"Are you sure you want to delete this item?"),
actions: <Widget>[
FlatButton(
onPressed: () => Navigator.of(context).pop(true),
child: const Text("Delete"),
),
FlatButton(
onPressed: () => Navigator.of(context).pop(false),
child: const Text("Cancel"),
),
],
);
},
);
},
key: UniqueKey(),
background: slideRightBackground(),
direction: DismissDirection.endToStart,
onDismissed: (direction) => _delete(context, expense),
child: ExpensesListTile(
expense: expense,
onTap: () => ExpensesCategoryPage.show(context, expense),
category: Category,
),
),
);
},
);
}
}
Steps of error occured with images
To ExpensesCategoryHistory class, render page here
Select category Beauty here
Render Beauty category item here
Confirm Delete action on category item after left swipe of dismissible here
Selected delete, prompt error code + item not deleted
Return stay step 3
Sorry for the full codes, but I wonder if my implementation issue on flutter/dart? I have been solving for days but still same issue, even I've read couple related issues on stackoverflow. Any help is greatly appreciated !
Tested
All widgets are mounted within 3 classes after routing.
Error occurred when deleted action is tapped but widget is mounted still.
I am trying to create a flexible navigation system, that uses one page to display different things pulled from a database.
For example
If I would click the button Cars it would navigate to the fixed page (Lets call it display page) And it would pull the title and description from the database and show accordingly. So by clicking Cars, it would send the String Cars with it, so i could use it to find the desired thing from the database.
My question is, how can I send this info to the next page?
I want to use
ElevatedButton(
child: Text("Cars"),
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) => HabitPage()));
},
And send the desired item with HabitPage('cars(for example)') (I have studied C and that's how you would send variables, not sure it will work in dart.)
This is my HabitPage
class HabitPage extends StatefulWidget {
#override
_HabitPageState createState() => _HabitPageState();
}
class _HabitPageState extends State<HabitPage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar
(
title: new Text("HabitPage")
),
body: new Center(
child: new Text("HabitPage"),
),
);
}
}
ElevatedButton(
child: Text("Cars"),
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) => HabitPage(info: 'Cars'))); // Passing the info as argument
},
class HabitPage extends StatefulWidget {
HabitPage({this.info}) : super(key: key);
final String info; // Variable to receive the info as argument
#override
_HabitPageState createState() => _HabitPageState();
}
class _HabitPageState extends State<HabitPage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar
(
title: new Text("HabitPage ${widget.info}")// Showing the info passed as argument
),
body: new Center(
child: new Text("HabitPage"),
),
);
}
}
Make this changes in your code.
In the future, you will probably use Named Routes, so you will need this tutorial.
https://flutter.dev/docs/cookbook/navigation/navigate-with-arguments#1-define-the-arguments-you-need-to-pass
But for now, this is the solution
The class in question is invoked from another page with the line
onPressed: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) =>
ProPage(iD: bestRatedPros[index]["ID"])));
},
Where bestRatedPros is a list of maps with the variable iD for the following class -
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class ProPage extends StatefulWidget {
ProPage({Key key, this.iD}) : super(key: key);
final iD;
#override
_ProPageState createState() => _ProPageState(iD);
}
class _ProPageState extends State<ProPage> {
int iD;
_ProPageState(this.iD);
#override
void initState() {
super.initState();
}
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.amber,
extendBodyBehindAppBar: true,
appBar: AppBar(
iconTheme: IconThemeData(
color: Colors.white, //change your color here
),
elevation: 0,
backgroundColor: Colors.amber
),
body:
Text("EWFWEFEWEWFWEF",style: TextStyle(color: Colors.black))
);
}
}
The getDataFromBackend function and
all the variables associated with it was meant to be within the body. But Nothing shows up in the body no matter what it is. Even a simple Text widget doesn't. I'm only trying to pass the variable iD from one page to the other without complicating things. The Run log doesn't show any Errors or warnings.
Arun,
See below where your Text is:
Reason for that is that you specified:
extendBodyBehindAppBar: true,
on your Scaffold, so body is expanded and top part of it is hidden behind AppBar
I am developing an app that is counting points, after the teams have been created. After the teams are created, an AlertDialog pops up and displays the names. Then it should be possible to click on a button to open a new activity. That activity should not be connected to the previous activity. Does anybody has an idea, how this could be done?
Here is the code-snippet of the dialog activity:
import 'dart:math';
import 'package:flutter/material.dart';
import 'punktezaehler.dart';
class Team_Dialog extends StatefulWidget{
final List<String> team_namen;
Team_Dialog(this.team_namen);
#override
State<StatefulWidget> createState() => new _TeamDialogState(team_namen);
}
class _TeamDialogState extends State<Team_Dialog>{
final List<String> team_namen;
_TeamDialogState(this.team_namen);
#override
Widget build(BuildContext context) {
return new AlertDialog(
content: new SingleChildScrollView(
child: new ListBody(
children: List.generate(1, (index){
return Column(
children: <Widget>[
new Row(
children: <Widget>[
Text("Team 1: ", style: TextStyle(fontFamily: "Roboto")),
Text(team_namen[0] + " und " + team_namen[1])
],
),
new Row(
children: <Widget>[
Text("Team 2: "),
Text(team_namen[2] + " und " + team_namen[3])
],
)
],
);
})
),
),
actions: <Widget>[
new FlatButton(
color: Colors.red,
splashColor: Colors.red[900],
onPressed: (){
Navigator.of(context).pop();
},
child: new Text("Abort", style: TextStyle(color: Colors.white),)
),
new IconButton(
icon: Icon(Icons.shuffle),
onPressed: (){
shuffle(team_namen);
setState(() {
});
}
),
new FlatButton(
color: Colors.green,
splashColor: Colors.green[800],
onPressed: () => , //After click it should start new Activity
child: new Text("Start Game", style: TextStyle(color: Colors.white))
)
],
);
}
List shuffle(List items) {
var random = new Random();
for (var i = items.length - 1; i > 0; i--) {
var n = random.nextInt(i + 1);
var temp = items[i];
items[i] = items[n];
items[n] = temp;
}
return items;
}
}
It would be awesome if someone has an idea :D
Actually when you are talking about Flutter think about pages, not activities. It should be something like :
Navigator.push(context,
MaterialPageRoute(builder: (context) => SecondScreen()),);
SecondScreen is another widget with its own Widget build(BuildContext context) method where you will declare what to have on this page.
In case you want to return back, you can do it with:
Navigator.pop(context);
Source documentation
You can also use named routes for navigation. Example:
MaterialApp(
// Start the app with the "/" named route. In our case, the app will start
// on the FirstScreen Widget
initialRoute: '/',
routes: {
// When we navigate to the "/" route, build the FirstScreen Widget
'/': (context) => FirstScreen(),
// When we navigate to the "/second" route, build the SecondScreen Widget
'/second': (context) => SecondScreen(),
},
);
And something like:
Navigator.pushNamed(context, '/second');
Documentation
It's not a good practice to use Navigator.push() or Navigator.pushNamed() and then remove the back button. Because the page that you are leaving from will remain in the pages stack.
What you actually should use is Navigator.pushReplacement() if you don't want the user to be able to go back to the previous page.
And if you are doing it from a dialog, you should pop the dialog first and then push the next page.