I was using some shared preferences to read and save lists but all I got is an error that goes as follows:
Launching lib/main.dart on iPhone 7 in debug mode...
Xcode build done. 4.1s
Tried calling: getString("t")
#0 Object.noSuchMethod (dart:core/runtime/libobject_patch.dart:50:5)
#1 ShareUtils.get
package:todolist2019/ShareUtils.dart:22
<asynchronous suspension>
#2 HomeScreenState.getTaskTitle
package:todolist2019/home.dart:38
#3 _AsyncAwaitCompleter.start (dart:async/runtime/libasync_patch.dart:49:6)
#4 HomeScreenState.getTaskTitle
package:todolist2019/home.dart:35
#5 HomeScreenState.build.<anonymous closure>
package:todolist2019/home.dart:97
#6 SliverChildBuilderDelegate.build
package:flutter/…/widgets/sliver.dart:398
Here is my code for home.dart, my home screen
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import './additem.dart';
import './ShareUtils.dart';
class HomeScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return HomeScreenState();
}
}
Timer timer;
DateTime now = DateTime.now();
String formattedTime = DateFormat('kk:mm').format(now);
String formattedDate = DateFormat('EEE d MMM').format(now);
class HomeScreenState extends State<HomeScreen> {
void changeTimeAndSetPref() {
setState(() {
DateTime now = DateTime.now();
formattedTime = DateFormat('kk:mm').format(now);
formattedDate = DateFormat('EEE d MMM').format(now);
});
}
Future getTaskTitle(index) async {
shareUtils = new ShareUtils();
shareUtils.Instance();
await shareUtils.get("title"[index]);
}
void initState() {
super.initState();
// Add listeners to this class
timer = Timer.periodic(Duration(seconds: 1), (Timer t) => changeTimeAndSetPref());
}
#override
Widget build(BuildContext context) {
// TODO: implement build
SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom]);
return Scaffold(
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => addItem()),
);
},
icon: Icon(Icons.add),
label: Text("Add Item"),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
body: Column(
children: <Widget>[
Center(
//set the correct sizes
child: Card(
child: Column(
children: <Widget>[
Text(
formattedTime,
style: TextStyle(
fontSize: 50.0,
),
),
Text(
formattedDate,
style: TextStyle(
fontSize: 35.0,
),
),
Text(
"You have impending tasks",
style: TextStyle(
fontSize: 25.0,
),
)
],
),
),
),
Expanded(
child: ListView.builder(
itemBuilder: (context, index) {
var title = getTaskTitle(index).toString();
var detail = taskTitleList[index];
EdgeInsets.all(16.0);
return ListTile(
title: Text(
title,
style: TextStyle(fontSize: 20.0),
),
subtitle: Text(
detail,
style: TextStyle(fontSize: 15.0),
),
onTap: () {
final snackBar = SnackBar(
content: Text('Item Removed'),
duration: Duration(seconds: 1),
);
setState(() {
taskTextList.removeAt(index);
taskTitleList.removeAt(index);
Scaffold.of(context).showSnackBar(snackBar);
});
},
);
},
itemCount: taskTextList.length,
),
)
],
),
);
}
}
And here is my code for additem.dart
import 'package:flutter/material.dart';
import './home.dart';
import './ShareUtils.dart';
class addItem extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return addItemState();
}
}
ShareUtils shareUtils;
var TaskTextField;
var TaskDetailField;
var taskTextList = [];
var taskTitleList = [];
var TaskIsImportant = false;
class addItemState extends State<addItem> {
#override
Widget build(BuildContext context) {
// TODO: implement build
void saveTask (key, value) async {
await shareUtils.set(key, value);
}
return Scaffold(
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomeScreen()),
);
setState(()async {
if (TaskIsImportant) {
taskTextList.add("❗$TaskTextField");
taskTitleList.add("$TaskDetailField");
saveTask("title", taskTextList);
} else {
taskTextList.add("$TaskTextField");
taskTitleList.add("$TaskDetailField");
saveTask("title", taskTextList);
}
});
},
label: Text("Add Task"),
icon: Icon(Icons.add),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
body: Flex(
direction: Axis.vertical,
children: <Widget>[
Flexible(
child: Container(
child: Column(
children: <Widget>[
Card(
child: Column(
children: <Widget>[
Center(
child: Text(
"Welcome!",
style: TextStyle(fontSize: 50.0),
),
),
Center(
child: Text(
"Enter your task below",
style: TextStyle(fontSize: 25.0),
),
),
],
),
),
Container(
child: TextField(
decoration: InputDecoration(
hintText: "Enter title of task to be added",
hintStyle: TextStyle(fontSize: 20.0)),
onChanged: (taskTextField) {
setState(() {
TaskTextField = taskTextField;
print(TaskTextField);
});
},
),
margin: EdgeInsets.all(16.0),
),
Container(
child: TextField(
decoration: InputDecoration(
hintText: "Enter detail of task to be added",
hintStyle: TextStyle(fontSize: 20.0)),
onChanged: (taskDetailField) {
setState(() {
TaskDetailField = taskDetailField;
print(TaskDetailField);
});
},
),
margin: EdgeInsets.all(16.0),
),
CheckboxListTile(
title: Text(
"Important",
style: TextStyle(fontSize: 25.0),
),
activeColor: Colors.blue,
value: TaskIsImportant,
onChanged: (val) {
setState(() {
TaskIsImportant = !TaskIsImportant;
print(TaskIsImportant);
});
},
),
],
),
),
)
],
));
}
}
I hope someone can help me with this error. I am running on Flutter 1.2.1. Thanks in advance!
PS: I have implemented the Akio's code and I still got errors but lesser. I have also added the first 6 lines of error message.
You can add "shared_preferences: ^0.4.0" at pubspec.yaml.
And Packages get.
And you make DartFile (Ex: Filename is ShareUtils
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:async';
class ShareUtils {
static ShareUtils _instance;
SharedPreferences ShareSave;
factory ShareUtils() => _instance ?? new ShareUtils._();
ShareUtils._();
void Instatce() async{
ShareSave = await SharedPreferences.getInstance();
}
Future<bool> set(key, value) async{
return ShareSave.setString(key, value);
}
Future<String> get(key) async{
return ShareSave.getString(key);
}
}
And main.dart
class MyApp extends StatelessWidget {
static ShareUtils shareUtils;
#override
Widget build(BuildContext context) {
ThemeData mainTheme = new ThemeData(
primaryColor : Color.fromRGBO(20, 42, 59, 1),
buttonColor: Color.fromRGBO(0, 132, 255, 1),
accentColor: Color.fromRGBO(31, 60, 83, 1)
);
shareUtils = new ShareUtils();
shareUtils.Instatce();
MaterialApp mainApp = new MaterialApp(
title: "Your app name",
theme: mainTheme,
home: new SplashPage(),
debugShowCheckedModeBanner: true,
routes: <String, WidgetBuilder>{
"HomePage": (BuildContext context) => new HomePage(),
},
);
return mainApp;
}
}
And you can Use this at anywhere
Before to use this, add import main.dart at header
GET:
Future NextPage() async {
MyApp.shareUtils.get("token").then((token) {
print(token);
if (token == null || token == "") {
Navigator.of(context).popAndPushNamed("RegisterPage");
} else {
Navigator.of(context).popAndPushNamed("HomePage");
}
});
}
SET:
void UserInfo(code, token) async{
await MyApp.shareUtils.set("token", token);
await MyApp.shareUtils.set("code", code);
await Navigator.of(context).pushNamed("HomePage");
}
I hope help you. Thank you
In your case MyApp.shareUtils.set("state", statelist.join("#"))
And get use statelist = token.split("#");
Related
I have a problem regarding if statement in dart, I want the user to tap the city to go to a new screen. this code work perfectly fine
class citySec extends StatelessWidget {
Widget getListView(BuildContext context) {
var listView = ListView(
children: <Widget>[
Text(
"choose ur city:",
textDirection: TextDirection.rtl,
textAlign: TextAlign.center,
),
ListTile(
leading: Icon(Icons.location_city),
title: Text("Toronto ", textDirection: TextDirection.rtl),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TorontoUniversitySection(),
),
);
},
),
],
);
return listView;
}
#override
Widget build(BuildContext context) {
return Scaffold(body: getListView(context));
}
}
Since I have a long list of cities and the previous code will make my code very long so I had to change my code. However, I faced some errors with if statements, here is what I did so far.
import 'package:flutter/material.dart';
import 'package:rate/screens/firstScreen.dart';
void main() {
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Rate',
home: Scaffold(
appBar: AppBar(
title: Text("jgfnjfnj ", textDirection: TextDirection.rtl),
),
body: ListDisplay(),
),
));
}
class ListDisplay extends StatelessWidget {
List<String> litems = ["Toronto","NewYork","London","Riyadh","Dubai","Istanbul"];
#override
Widget build (BuildContext ctxt) {
return new Scaffold(
appBar: AppBar(title: Text("Please Choose your city: ", textDirection: TextDirection.ltr,),
),
body: new ListView.builder
(
itemCount: litems.length,
itemBuilder: (BuildContext ctxt, int index) {
return new ListTile(
leading: Icon(Icons.location_city),
title: Text(litems[index], textDirection: TextDirection.rtl),
onTap: () {
// begin of all IF statements
if (litems.contains("Totonto")){
Navigator.push(
ctxt,
MaterialPageRoute(
builder: (ctxt) => TorontoUniversitySection()
),
);
}
if (litems.contains("London")){
Navigator.push(
ctxt,
MaterialPageRoute(
builder: (ctxt) => LondonUniversitySection()
),
);
}
// end of all If statements
},
);
}
)
);
}
}
for example, when I press Toronto it will take me to LondonUniversitySection()
That is because in your if statements, you check whether your list contains Toronto/London and not if currently pressed one is Toronto/London. Changing litems.contains("x") to litems[index] == "x" will do the trick. Here's edited fragment:
return new ListTile(
leading: Icon(Icons.location_city),
title: Text(litems[index], textDirection: TextDirection.rtl),
onTap: () {
if (litems[index] == "Toronto") {
Navigator.push(
ctxt,
MaterialPageRoute(builder: (ctxt) => TorontoUniversitySection()),
);
} else if (litems[index] == "London") {
Navigator.push(
ctxt,
MaterialPageRoute(builder: (ctxt) => LondonUniversitySection()));
}
},
);
Also, I recommend using a switch or else-if for that, not a bunch of ifs.
Try onTap: litems.contains("Totonto")?
Navigator.push( ctxt, MaterialPageRoute( builder: (ctxt) => TorontoUniversitySection() ), )
: null
class _RegisterBodyState extends State<RegisterBody> {
FocusNode myFocusNode = new FocusNode();
FocusNode myFocusNode2 = new FocusNode();
void initState() {
super.initState();
myFocusNode = FocusNode();
myFocusNode2 = FocusNode();
}
#override
void dispose() {
// Clean up the focus node when the Form is disposed.
myFocusNode.dispose();
myFocusNode2.dispose();
super.dispose();
}
Color color;
#override
Widget build(BuildContext context) {
return Center(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"Register",
style: TextStyle(
color: Theme.of(context).primaryColor,
fontSize: 70.0,
fontWeight: FontWeight.bold,
),
),
Form(
child: Column(
children: [
TextFormField(
onTap: () {
setState(() {
color = Colors.red;
});
},
autofocus: true,
focusNode: myFocusNode,
decoration: InputDecoration(
icon: Icon(
Icons.supervised_user_circle,
size: 40.0,
),
labelText: "User Name",
labelStyle: TextStyle(
color:
myFocusNode.hasFocus ?color : Colors.yellow),
),
),
TextFormField(
focusNode: myFocusNode2,
onTap: () {
setState(() {
color = Colors.black;
});
},
autofocus: false,
decoration: InputDecoration(
icon: Icon(
Icons.supervised_user_circle,
size: 40.0,
),
labelText: "User Name",
labelStyle: TextStyle(
color: myFocusNode2.hasFocus ? color : Colors.teal,
),
),
),
],
))
],
),
),
);
}
}
I'm having trouble passing the data that's been filled in a textformfields and selected in a dropdown menu.
I'm trying to use the Map function to pass down String values so that I can also pass down all types of values in the future (ex. int, bool, double etc.), however it's not working so I need someone to check it out.
main.dart
import 'package:flutter/material.dart';
import 'package:workoutapp/auth/auth.dart';
import 'package:workoutapp/auth/root_page.dart';
import 'package:workoutapp/inheritedWigets/auth_provider.dart';
void main(List<String> args) {
runApp(
WorkoutManager(),
);
}
class WorkoutManager extends StatelessWidget {
#override
Widget build(BuildContext context) {
return AuthProvider(
auth: Auth(),
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Workout Manager',
home: RootPage(),
theme: ThemeData(
primaryColor: Colors.indigo,
primarySwatch: Colors.indigo,
accentColor: Colors.indigoAccent,
hintColor: Colors.indigo,
brightness: Brightness.dark,
),
),
);
}
}
HomePage
import 'package:flutter/material.dart';
import 'package:workoutapp/inheritedWigets/auth_provider.dart';
import './profile_account_page.dart';
import './routines_create_page.dart';
import '../objects/Routines/routines_manager.dart';
import '../tools/custom_drawer.dart';
class HomePage extends StatelessWidget {
final VoidCallback onSignedOut;
final List<Map<String, String>> routines;
HomePage({Key key, this.onSignedOut, this.routines}) : super(key: key);
void _signedOut(BuildContext context) async {
try {
var auth = AuthProvider.of(context).auth;
await auth.signOut();
onSignedOut();
} catch (e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Workout Manager', style: TextStyle(color: Colors.white)),
centerTitle: false,
actions: <Widget>[
FlatButton(
child: Text('Logout'),
onPressed: () {
return _signedOut(context);
},
),
IconButton(
icon: Icon(Icons.account_box),
tooltip: 'Profile Account',
color: Colors.white,
onPressed: () {
return Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return ProfileAccountPage();
}));
},
),
],
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return RoutinesPageCreate();
}));
},
),
body: RoutinesManager(),
drawer: CustomDrawer(),
);
}
}
RoutineManager
import 'package:flutter/material.dart';
import 'package:workoutapp/objects/routines/routines.dart';
class RoutinesManager extends StatefulWidget {
final Map<String, String> startingRoutine;
RoutinesManager({this.startingRoutine});
#override
_RoutinesManagerState createState() => _RoutinesManagerState();
}
class _RoutinesManagerState extends State<RoutinesManager> {
List<Map<String, String>> _routines = [];
#override
void initState() {
if (widget.startingRoutine != null) {
_routines.add(widget.startingRoutine);
}
super.initState();
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Expanded(
child: Routines(_routines),
)
],
);
}
}
RoutinesCreatePage
import 'package:flutter/material.dart';
import 'package:workoutapp/pages/home_page.dart';
class RoutinesPageCreate extends StatefulWidget {
#override
_RoutinesPageCreateState createState() => _RoutinesPageCreateState();
}
class _RoutinesPageCreateState extends State<RoutinesPageCreate> {
final formKey = GlobalKey<FormState>();
List<Map<String, String>> _routines = [];
String _routineName, _routineDescription;
var _routineNameController = TextEditingController();
var _routineDescriptionController = TextEditingController();
List<DropdownMenuItem<String>> _dropdownListBodyPartMenuItem = [];
List<String> _dropdownListBodyPart = [
'Chest',
'Back',
'Leg',
'Shoulder',
'Abs',
];
String _selectedBodyPart;
List<DropdownMenuItem<String>> _dropdownListDayOfWeekMenuItem = [];
List<String> _dropdownListDayOfWeek = [
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday',
];
String _selectedDayOfWeek;
void loadBodyPartData() {
_dropdownListBodyPartMenuItem = [];
_dropdownListBodyPartMenuItem = _dropdownListBodyPart.map((val) {
return DropdownMenuItem<String>(
child: Text(val),
value: val,
);
}).toList();
}
void loadDayOfWeekData() {
_dropdownListDayOfWeekMenuItem = [];
_dropdownListDayOfWeekMenuItem = _dropdownListDayOfWeek.map((val) {
return DropdownMenuItem<String>(
child: Text(val),
value: val,
);
}).toList();
}
final _scaffoldState = GlobalKey<ScaffoldState>();
void _showSnakBarReset() {
_scaffoldState.currentState.showSnackBar(
SnackBar(
backgroundColor: Theme.of(context).accentColor,
content: Text('Showing SnackBar TEST'),
),
);
}
void _showSnakBarCreateWorkoutRoutine() {
_scaffoldState.currentState.showSnackBar(
SnackBar(
backgroundColor: Theme.of(context).accentColor,
content: Text('Workout Routine has been created'),
),
);
}
void _addRoutine(Map<String, String> routine) {
setState(() {
_routines.add(routine);
});
}
#override
Widget build(BuildContext context) {
loadBodyPartData();
loadDayOfWeekData();
return Scaffold(
key: _scaffoldState,
appBar: AppBar(
title: Text('Create Routines'),
),
body: Container(
padding: EdgeInsets.all(15.0),
child: Form(
key: formKey,
child: ListView(children: buildInputs() + buildCreateButtons()),
),
),
);
}
List<Widget> buildInputs() {
TextStyle textStyle = Theme.of(context).textTheme.title;
return [
TextFormField(
controller: _routineNameController,
validator: (value) {
if (value.length > 20) {
return 'Not a valid Routine Name';
}
},
onSaved: (value) {
return _routineName = value;
},
decoration: InputDecoration(
labelStyle: textStyle,
labelText: 'Routine Name',
hintText: 'Enter the Routine Name for this day',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
))),
Padding(padding: EdgeInsets.all(7.0)),
TextFormField(
controller: _routineDescriptionController,
validator: (value) {
if (value.length > 50) {
return 'Invalid: The Description must be 50 characters or less.';
}
},
onSaved: (value) {
return _routineDescription = value;
},
decoration: InputDecoration(
labelStyle: textStyle,
labelText: 'Description',
hintText: 'Enter the description of the Routine.',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
))),
Padding(padding: const EdgeInsets.all(7.0)),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
DropdownButtonHideUnderline(
child: DropdownButton(
value: _selectedBodyPart,
items: _dropdownListBodyPartMenuItem,
hint: Text('Select Body Part', style: textStyle),
onChanged: (value) {
setState(() {
_selectedBodyPart = value;
});
})),
Padding(
padding: const EdgeInsets.all(1.0),
),
DropdownButtonHideUnderline(
child: DropdownButton(
value: _selectedDayOfWeek,
items: _dropdownListDayOfWeekMenuItem,
hint: Text('Select Day of Week', style: textStyle),
onChanged: (value) {
setState(() {
_selectedDayOfWeek = value;
});
},
),
),
Padding(
padding: const EdgeInsets.all(4.0),
)
],
),
];
}
List<Widget> buildCreateButtons() {
return [
Padding(
padding: const EdgeInsets.all(5.0),
child: Row(
children: <Widget>[
Expanded(
child: RaisedButton(
textColor: Theme.of(context).primaryColorDark,
color: Theme.of(context).accentColor,
child: Text('Create Workout Routine'),
onPressed: () {
if (formKey.currentState.validate()) {
_showSnakBarCreateWorkoutRoutine();
formKey.currentState.save();
_addRoutine({
'routineName': 'Chest Workout',
'description': 'Heavy',
'bodyPart': 'Chest',
'week': 'Monday',
});
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return HomePage();
}));
} else {
return null;
}
}),
),
Expanded(
child: RaisedButton(
textColor: Theme.of(context).primaryColorLight,
color: Theme.of(context).primaryColorDark,
child: Text('Reset'),
onPressed: () {
setState(() {
_showSnakBarReset();
formKey.currentState.reset();
_selectedBodyPart = null;
_selectedDayOfWeek = null;
});
},
),
),
],
),
),
];
}
}
Routines
import 'package:flutter/material.dart';
import 'package:workoutapp/objects/routines/routines_detail.dart';
class Routines extends StatelessWidget {
final List<Map<String, String>> routines;
Routines(this.routines);
Widget _buildRoutinesItem(BuildContext context, int index) {
TextStyle textStyle = Theme.of(context).textTheme.title;
return Expanded(
child: Card(
margin: EdgeInsets.all(5.0),
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(routines[index]['routineName'], style: textStyle)),
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(routines[index]['description'], style: textStyle)),
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(routines[index]['bodyPart'], style: textStyle)),
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(routines[index]['week'], style: textStyle)),
Padding(
padding: const EdgeInsets.all(5.0),
child: ButtonBar(
alignment: MainAxisAlignment.center,
children: <Widget>[
FlatButton(
child: Text('Details'),
onPressed: () {
return Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return RoutinesDetail(
routines[index]['routineName'],
routines[index]['description'],
routines[index]['bodyPart'],
routines[index]['week']);
}));
},
)
],
),
)
],
),
),
);
}
Widget _buildRoutinesList(context) {
TextStyle textStyle = Theme.of(context).textTheme.title;
Widget routinesCards = Container(
child: Container(
child: Center(
child: Text("No routines found, please add some.", style: textStyle),
),
),
);
if (routines.length > 0 || routines.length <= 7) {
ListView.builder(
itemBuilder: _buildRoutinesItem,
itemCount: routines.length,
);
}
return routinesCards;
}
#override
Widget build(BuildContext context) {
return _buildRoutinesList(context);
}
}
RoutineDetailPage
import 'package:flutter/material.dart';
class RoutinesDetail extends StatelessWidget {
final String routineName, description, bodyPart, week;
RoutinesDetail(this.routineName, this.description, this.bodyPart, this.week);
#override
Widget build(BuildContext context) {
TextStyle textStyle = Theme.of(context).textTheme.title;
return Scaffold(
appBar: AppBar(
title: Text(routineName),
centerTitle: true,
),
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(routineName, style: textStyle)),
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(description, style: textStyle)),
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(bodyPart, style: textStyle)),
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(week, style: textStyle)),
Container(
padding: EdgeInsets.all(5.0),
child: RaisedButton(
child: Text('Delete'),
onPressed: () {
Navigator.pop(context);
},
),
),
],
),
),
);
}
}
As you can see, I'm trying to separate the code into multiple files as much as possible, so it's more "readable" and make it easy for myself to make changes to the code whenever I have to in the future.
The problem is, it's quite spit up, I don't understand how to use the data and pass it down or up to the pages or widgets as there are multiple stateful and stateless widgets that are suppose to work together to make this app possible.
You'll notice on the HomePage file (StatelessWidget), I'm trying to show the Scaffold body argument with the RoutinesManager StatefulWidget, which is in a different file. At the same time in the HomePage file, I have a Scaffold floatingActionButton argument that will take you to the RoutinesCreatePage StatefulWidget to create a List of Cards (StatelessWidget) using the ListView.builder(). However, no Card gets created under the HomePage after the "Create Workout Routine" RaisedButton gets pressed in the RoutinesCreatePage and no data gets passed.
Can someone please help me out here as I am totally clueless. Also, I'm fairly a beginner regarding flutter/dart so a solution with a relatively easy to understand explanation would be very helpful.
Note: I do have other files that contribute to this app, however I don't think they're part of the problem so I left them out intentionally.
If more information is needed, please do let me know.
Thanks you!
it looks like you misunderstand what state in Flutter is. To explain in short, state is the internal status/data/... that belongs that that specific widget. StatefulWidget has state to determine if UI should be re-rendered on its own state change. External widgets never know about other widgets' states.
So it means, any state change happening inside RoutinesCreatePage widget, only that RoutinesCreatePage knows and reacts. Unless, you inform other widgets to know something has changed.
Alright, so talking about navigation, it works like a stack structure. HomePage trigger a push to RoutinesCreatePage, then to return, you need to pop, not another push.
Here a quick fix for your code, you can try.
HomePage
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
handleNewRoutine(); <--- this is to handle navigation and retrieve returning data from pop
},
),
Future handleNewRoutine() async {
var newRoutine = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => RoutinesPageCreate());
)
if (newRoutine == null) {
// nothing returns from RoutinesPageCreate widget
// so do nothing then
} else {
// add to routine list
// and trigger list re-rendering
setState(() {
this.routines.add(newRoutine);
});
}
}
RoutinesCreatePage: when clicking submit button, just populate all data from input fields, make object model and pop to return data to where this widget was pushed.
onPressed: () {
var newRoutine = .... // populate from UI to create new Routine model object.
Navigator.pop(context, newRoutine);
}
Also, take time to read the navigation guide from official Flutter documentation. It is very detailed on this part. https://flutter.io/docs/cookbook/navigation/returning-data
Some additional comments to your code:
in RoutinesCreatePage you don't need to know application level state, I mean _routines variable is unnecessary. You only need one object to store new routine to pop back to HomePage.
in Routines, this method Widget _buildRoutinesList(context) having unused ListView creation.
if (routines.length > 0 || routines.length <= 7) {
ListView.builder(
itemBuilder: _buildRoutinesItem,
itemCount: routines.length,
);
}
File:homepage.dart
class _HomePageState extends State<HomePage> {
var _scaffoldBody;
var _scaffoldTitle;
#override
initState() {
_scaffoldTitle=new Text("Wall");
_scaffoldBody=new Center(child:CircularProgressIndicator());
}
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: new Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('Drawer Header'),
decoration: BoxDecoration(
color:Theme.of(context).accentColor,
),
),
ListTile(
title: Text('Home'),
onTap: () {
setState(() {
_scaffoldTitle=new Text("Home");
_scaffoldBody=new Text("Home Page");
});
Navigator.pop(context);
},
),
ListTile(
title: Text('MenuItem1'),
onTap: () {
setState(() {
_scaffoldTitle=new Text("1st Menu");
_scaffoldBody=new TestPage("Page 1");
});
Navigator.pop(context);
},
),
ListTile(
title: Text('MenuItem2'),
onTap: () {
setState(() {
_scaffoldTitle=new Text("2nd Item");
_scaffoldBody=new TestPage("Page 2");
});
Navigator.pop(context);
},
),
],
),
),
appBar: new AppBar(
title: _scaffoldTitle,
elevation: 2.0,
actions: <Widget>[
],
),
body:_scaffoldBody,
);
}
file: TestPage.dart
import 'package:flutter/material.dart';
class TestPage extends StatefulWidget{
final String rollNumber;
TestPage(this.rollNumber);
#override
TestPageState createState() => new TestPageState(rollNumber);
}
class TestPageState extends State<TestPage>{
String rollNumber;
TestPageState(this.rollNumber);
#override
Widget build(BuildContext context) {
return new Text(rollNumber);
}
}
Output:
When I chose : "Home" from drawer it shows "Home Page"
Then I chose : "MenuItem1" it showed "Page 1"
Then I chose : "MenuItem2" it showed same "Page 1" (unexpected)
Then I chose : "Home" it showed "Home Page"
Then I chose : "MenuItem2" it showed correctly as "Page 2"
Then I chose : "MenuItem1" it showed "Page 2" (unexpected)
unable to solve this.Stuck!! Any solutions are appreciated. Thanks in advance!!
Update your TestPart.dart as follow:
import 'package:flutter/material.dart';
class TestPage extends StatefulWidget{
final String rollNumber;
TestPage(this.rollNumber);
#override
TestPageState createState() => new TestPageState();
}
class TestPageState extends State<TestPage>{
#override
Widget build(BuildContext context) {
return new Text(widget.rollNumber);
}
}
My StudentPage Class
import 'package:flutter/material.dart';
import 'package:firebase_database/firebase_database.dart';
import 'calendar_utils.dart';
import 'dart:async';
final mainReference = FirebaseDatabase.instance.reference();
class StudentPage extends StatefulWidget{
final String rollNumber;
StudentPage(this.rollNumber);
#override
StudentPageState createState() => new StudentPageState(rollNumber);
}
class StudentPageState extends State<StudentPage>{
final String currentRoll,currentYear="2018-19";
StudentPageState(this.currentRoll);
List<String> academicMonth=["June","July","August","September","October","November","December",
"January","February","March","April","May"];
int firstHalfYear=2018,secondHalfYear=2019;
List<Widget> _monthListArray=[new ListTile(title:new Text("Academic Year",style: new TextStyle(fontWeight: FontWeight.bold,fontSize: 20.0),),)];
List<Widget> _listView;
int _no_of_working=0;
int _no_of_present=0;
#override
void initState() {
// TODO: implement initState
_listView=[new Center(
child: new CircularProgressIndicator(),
)];
_loadMonths();
}
#override
Widget build(BuildContext context) {
return new RefreshIndicator(child: new ListView(
children: _listView,
), onRefresh: _loadMonths);
}
Future<Null> _loadMonths() async {
_listView.clear();
await mainReference.child("XXXX").child("attendance").child(
widget.rollNumber).child(currentYear).once().then((
DataSnapshot dataSnapshot) {
try {
int monthIndex=5; //monthIndex starts from June
for(var month in academicMonth){
debugPrint("Month:"+month);
monthIndex=(monthIndex+1)%12; //month index cycles throughout 1-12
if(monthIndex==0) monthIndex=12;
List<Widget> _daysList=[];
_monthListArray.add(new Padding(padding: EdgeInsets.all(16.0),child: new Text(month+" "+(monthIndex<6?secondHalfYear:firstHalfYear).toString(),style: new TextStyle(color: Colors.black87,fontWeight: FontWeight.bold,fontSize: 20.0),),)); //initializing the month
_monthListArray.add(new Padding(padding: EdgeInsets.only(top: 10.0,bottom: 10.0),child:
new Row(children: <Widget>[
new Expanded(
child: new Center(child: new Text("S",style: new TextStyle(fontWeight: FontWeight.bold),),),
),
new Expanded(
child: new Center(child: new Text("M",style: new TextStyle(fontWeight: FontWeight.bold),),),
),
new Expanded(
child: new Center(child: new Text("T",style: new TextStyle(fontWeight: FontWeight.bold),),),
),
new Expanded(
child: new Center(child: new Text("W",style: new TextStyle(fontWeight: FontWeight.bold),),),
),
new Expanded(
child: new Center(child: new Text("T",style: new TextStyle(fontWeight: FontWeight.bold),),),
),
new Expanded(
child: new Center(child: new Text("F",style: new TextStyle(fontWeight: FontWeight.bold),),),
),
new Expanded(
child: new Center(child: new Text("S",style: new TextStyle(fontWeight: FontWeight.bold),),),
),
],),));
debugPrint(monthIndex.toString());
int freeSpace=CalendarUtils(1,monthIndex,monthIndex<6?secondHalfYear:firstHalfYear).getDayFromDate();
debugPrint("FreeSpace---"+freeSpace.toString());
if(freeSpace!=0){
for (var i = 0; i < freeSpace; i++) {
_daysList.add(new Text(""));
}
}
debugPrint(monthIndex.toString());
var year=monthIndex<6?secondHalfYear:firstHalfYear;
debugPrint("Year"+year.toString());
debugPrint("Forloop limit:"+CalendarUtils(1,monthIndex,monthIndex<6?firstHalfYear:secondHalfYear).numberOfDays().toString());
for(var day=1;day<=CalendarUtils(1,monthIndex,monthIndex<6?secondHalfYear:firstHalfYear).numberOfDays();day++){
try {
//debugPrint(day.toString()+":"+dataSnapshot.value[month][day].toString());
if (CalendarUtils(day, monthIndex,
monthIndex < 6 ? secondHalfYear: firstHalfYear)
.getDayFromDate() != 0){
if (dataSnapshot.value[month][day].toString() == "1") {
_no_of_working++;
_no_of_present++;
_daysList.add(
new Padding(padding: EdgeInsets.only(left: 10.0,right: 10.0,top: 2.0,bottom: 2.0),
child: new Container(
alignment: Alignment.center,
width: 30.0,
height: 30.0,
decoration: new BoxDecoration(
borderRadius: new BorderRadius.all(new Radius.circular(50.0)),
color: Colors.green),
child: new Text(
day.toString(),
style: new TextStyle(color: Colors.white),
),
),
)
);
}
else if (dataSnapshot.value[month][day].toString() == "0"){
_no_of_working++;
_daysList.add(
new Padding(padding: EdgeInsets.only(left: 10.0,right: 10.0,top: 2.0,bottom: 2.0),
child: new Container(
alignment: Alignment.center,
width: 30.0,
height: 30.0,
decoration: new BoxDecoration(
borderRadius: new BorderRadius.all(new Radius.circular(50.0)),
color: Colors.redAccent),
child: new Text(
day.toString(),
style: new TextStyle(color: Colors.white),
),
),
)
);
}
else {
_daysList.add(
new Padding(padding: EdgeInsets.only(left: 10.0,right: 10.0,top: 2.0,bottom: 2.0),
child: new Container(
alignment: Alignment.center,
width: 30.0,
height: 30.0,
decoration: new BoxDecoration(
borderRadius: new BorderRadius.all(new Radius.circular(50.0)),
),
child: new Text(
day.toString(),
style: new TextStyle(color: Colors.black),
),
),
)
);
}
}else {
_daysList.add(
new Center(child: new Text(day.toString(), style:
new TextStyle(color: Colors.black45),)));
}
}catch (e){
_daysList.add(new Center(child:new Text(day.toString(),style:
new TextStyle(color: Colors.black),) ));
}
}
Widget _daysGrid=new GridView.count(crossAxisCount: 7,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
childAspectRatio: 1.5,
children: _daysList,
);
_monthListArray.add(_daysGrid);
}
}catch(e){}
_monthListArray.add(new Text((_no_of_present/_no_of_working).toString()));
});
this.setState((){
_listView=_monthListArray;
});
}
}
My HomePage.dart
import 'package:flutter/material.dart';
import 'package:smart_school_parent/TestPage.dart';
import 'package:smart_school_parent/attendance.dart';
import 'package:smart_school_parent/post.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:smart_school_parent/auth.dart';
import 'dart:async';
class HomePage extends StatefulWidget {
final BaseAuth auth;
final VoidCallback onSignOut;
HomePage({Key key, this.auth, this.onSignOut}) : super(key: key);
#override
_HomePageState createState() => new _HomePageState(this.auth);
}
class _HomePageState extends State<HomePage> {
final mainReference = FirebaseDatabase.instance.reference();
List<PostData> post_list = new List();
var _scaffoldBody;
var _loading;
var _currentYear;
var _scaffoldTitle;
List<Widget> _childrenList=[new Text("Profiles",textAlign: TextAlign.left,style: new TextStyle(fontWeight: FontWeight.bold),)];
BaseAuth auth;
_HomePageState(this.auth);
#override
initState() {
//_children=updateChildren();
_updateChildren();
getList();
_loading=true ;
_scaffoldTitle=new Text("Wall");
_scaffoldBody=new Center(child:CircularProgressIndicator());
}
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: new Drawer(
child: ListView(
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('XXXXx'),
decoration: BoxDecoration(
color:Theme.of(context).accentColor,
),
),
ListTile(
title: Text('Wall'),
onTap: () {
setState(() {
_scaffoldTitle=new Text("Wall");
_scaffoldBody=new RefreshIndicator(child: _loadWall(), onRefresh: getList);
});
Navigator.pop(context);
},
),
Column(
children: _childrenList,
),
],
),
),
appBar: new AppBar(
title: _scaffoldTitle,
elevation: 2.0,
actions: <Widget>[
],
),
body:_scaffoldBody,
);
}
Future <Null> getList() async {
await mainReference.child("NISE-Coimbatore").child("posts").once().then((DataSnapshot dataSnapshot) {
this.setState(() {
post_list.clear();
if(dataSnapshot.value!=null){
for (var value in dataSnapshot.value.values) {
post_list.add(new PostData.fromJson(value));
//debugPrint(value.toString());
}
}else{
this.setState((){
});
}
});
});
setState(() {
_scaffoldBody=new RefreshIndicator(child: _loadWall(), onRefresh: getList);
});
}
Widget _loadWall(){
return Stack(
children: <Widget>[
new ListView.builder(itemBuilder: (BuildContext context,int index){
return new Post(post_list[index].image,post_list[index].title,post_list[index].content);
},
itemCount: post_list == null ? 0 : post_list.length,)
],
);
}
_updateChildren() async {
_currentYear= await mainReference.child("attendance").child("currentYear").once();
await auth.currentUser().then((String userId) async{
mainReference.child("NISE-Coimbatore").child("parents").child(userId).child('children').once().then((DataSnapshot dataSnapshot){
for (var value in dataSnapshot.value){
this.setState((){
_childrenList.add(
new Padding(
padding: EdgeInsets.only(left: 25.0),
child: ListTile(
title: Text(value.toString()),
onTap: () {
super.setState(() {
_scaffoldTitle=new Text(value.toString());
this._scaffoldBody=new StudentPage(value.toString());
});
Navigator.pop(context);
},
),
),
);
});
//debugPrint("Childrrncount::"+value.toString());
}
});
});
}
}
class PostData{
String title;
String content;
String image;
PostData(this.title, this.content, this.image);
PostData.fromJson(var value) {
this.title = value['title'];
this.content = value['content'];
this.image = value['image'];
}
}
_childrenList has two elements. The datasnapshot.values has [15505,15501] two roll numbers
Both rollnumbers from firebase appear on the drawer box and on tap it is expected to show StudentPage(15501.tostring()) or StudentPage(15505.tostring())
it works as expected if select "Wall" from drawer and then any of the "rollNumbers"
it is not working if i switch from one of the rollNumbers to other rollNumber in the drawer.
Similar to my first post. Only the _scaffoldTitle changes accordingly.
Imagine I have a long piece of text like this: HELLO THIS IS MY LONG SENTENCE . I want the word LONG to ripple (ink splash) when I tap it.
Let's say I have this code:
new RichText(
text: new TextSpan(
text: 'HELLO THIS IS MY ',
style: DefaultTextStyle.of(context).style,
children: <TextSpan>[
new TextSpan(text: 'LONG', style: new TextStyle(fontWeight: FontWeight.bold)),
new TextSpan(text: ' SENTENCE'),
],
),
)
Thanks!
If you want a generic solution to place widgets over portions of text, see this gist.
You can use the following code to have the ripple constrained to a specific section of the text:
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart:ui' show TextBox;
import 'dart:math';
void main() {
runApp(new MaterialApp(
home: new Material(
child: new Center(
child: new Demo(),
),
),
));
}
class Demo extends StatelessWidget {
final TextSelection textSelection =
const TextSelection(baseOffset: 17, extentOffset: 21);
final GlobalKey _textKey = new GlobalKey();
#override
Widget build(context) => new Stack(
children: <Widget>[
new RichText(
key: _textKey,
text: new TextSpan(
text: 'HELLO THIS IS MY ',
style: DefaultTextStyle.of(context).style,
children: <TextSpan>[
new TextSpan(
text: 'LONG',
style: new TextStyle(fontWeight: FontWeight.bold)),
new TextSpan(text: ' SENTENCE'),
],
),
),
new Positioned.fill(
child: new LayoutBuilder(
builder: (context, _) => new Stack(
children: <Widget>[
new Positioned.fromRect(
rect: _getSelectionRect(),
child: new InkWell(
onTap: () => {}, // needed to show the ripple
),
),
],
),
),
),
],
);
Rect _getSelectionRect() =>
(_textKey.currentContext.findRenderObject() as RenderParagraph)
.getBoxesForSelection(textSelection)
.fold(
null,
(Rect previous, TextBox textBox) => new Rect.fromLTRB(
min(previous?.left ?? textBox.left, textBox.left),
min(previous?.top ?? textBox.top, textBox.top),
max(previous?.right ?? textBox.right, textBox.right),
max(previous?.bottom ?? textBox.bottom, textBox.bottom),
),
) ??
Rect.zero;
}
You can accomplish this effect by adapting the code in ink_well.dart.
In this example I configured the rectCallback to expand to the containing card, but you could provide a smaller rectangle with the splash be centered around the point of the tap.
import 'package:flutter/material.dart';
import 'package:flutter/gestures.dart';
import 'dart:collection';
void main() {
runApp(new MaterialApp(home: new DemoApp()));
}
class DemoText extends StatefulWidget {
#override
DemoTextState createState() => new DemoTextState();
}
class DemoTextState<T extends InkResponse> extends State<T>
with AutomaticKeepAliveClientMixin {
Set<InkSplash> _splashes;
InkSplash _currentSplash;
#override
bool get wantKeepAlive => (_splashes != null && _splashes.isNotEmpty);
void _handleTapDown(TapDownDetails details) {
final RenderBox referenceBox = context.findRenderObject();
InkSplash splash;
splash = new InkSplash(
controller: Material.of(context),
referenceBox: referenceBox,
containedInkWell: true,
rectCallback: () => referenceBox.paintBounds,
position: referenceBox.globalToLocal(details.globalPosition),
color: Theme.of(context).splashColor,
onRemoved: () {
if (_splashes != null) {
assert(_splashes.contains(splash));
_splashes.remove(splash);
if (_currentSplash == splash) _currentSplash = null;
updateKeepAlive();
} // else we're probably in deactivate()
});
_splashes ??= new HashSet<InkSplash>();
_splashes.add(splash);
_currentSplash = splash;
updateKeepAlive();
}
void _handleTap(BuildContext context) {
_currentSplash?.confirm();
_currentSplash = null;
Feedback.forTap(context);
}
void _handleTapCancel() {
_currentSplash?.cancel();
_currentSplash = null;
}
#override
void deactivate() {
if (_splashes != null) {
final Set<InkSplash> splashes = _splashes;
_splashes = null;
for (InkSplash splash in splashes) splash.dispose();
_currentSplash = null;
}
assert(_currentSplash == null);
super.deactivate();
}
Widget build(BuildContext context) {
return new Padding(
padding: new EdgeInsets.all(20.0),
child: new RichText(
text: new TextSpan(
text: 'HELLO THIS IS MY ',
style: DefaultTextStyle.of(context).style,
children: <TextSpan>[
new TextSpan(
recognizer: new TapGestureRecognizer()
..onTapCancel = _handleTapCancel
..onTapDown = _handleTapDown
..onTap = () => _handleTap(context),
text: 'LONG',
style: new TextStyle(fontWeight: FontWeight.bold),
),
new TextSpan(text: ' SENTENCE'),
],
),
),
);
}
}
class DemoApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new Container(
height: 150.0,
width: 150.0,
child: new Card(
child: new DemoText(),
),
),
),
);
}
}
By 2019, we can use this:
RichText(
textAlign: TextAlign.center,
text: TextSpan(
style: textTheme.bodyText2,
text: "HELLO THIS IS MY",
children: [
WidgetSpan(
child: InkWell(
onTap: () {},
child: Text(
"SENTENCE",
style: TextStyle(color: colorScheme.primary),
),
),
),
],
),
),
Basically, I want to have a screen/view that will open when the user opens up the app for the first time. This will be a login screen type of thing.
Use Shared Preferences Package. You can read it with FutureBuilder, and you can check if there is a bool named welcome for example. This is the implementation I have in my code:
return new FutureBuilder<SharedPreferences>(
future: SharedPreferences.getInstance(),
builder:
(BuildContext context, AsyncSnapshot<SharedPreferences> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return new LoadingScreen();
default:
if (!snapshot.hasError) {
#ToDo("Return a welcome screen")
return snapshot.data.getBool("welcome") != null
? new MainView()
: new LoadingScreen();
} else {
return new ErrorScreen(error: snapshot.error);
}
}
},
);
Above code work fine but for beginners I make it little bit simple
main.dart
import 'package:flutter/material.dart';
import 'package:healthtic/IntroScreen.dart';
import 'package:healthtic/user_preferences.dart';
import 'login.dart';
import 'profile.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return MyAppState();
}
}
class MyAppState extends State<MyApp> {
// This widget is the root of your application.
bool isLoggedIn = false;
MyAppState() {
MySharedPreferences.instance
.getBooleanValue("isfirstRun")
.then((value) => setState(() {
isLoggedIn = value;
}));
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
//if true return intro screen for first time Else go to login Screen
home: isLoggedIn ? Login() : IntroScreen());
}
}
then share preferences
MySharedPreferences
import 'package:shared_preferences/shared_preferences.dart';
class MySharedPreferences {
MySharedPreferences._privateConstructor();
static final MySharedPreferences instance =
MySharedPreferences._privateConstructor();
setBooleanValue(String key, bool value) async {
SharedPreferences myPrefs = await SharedPreferences.getInstance();
myPrefs.setBool(key, value);
}
Future<bool> getBooleanValue(String key) async {
SharedPreferences myPrefs = await SharedPreferences.getInstance();
return myPrefs.getBool(key) ?? false;
}
}
then create two dart files IntroScreen and Login
Intro Screen will apear just once when user run application for first time usless the app is removed or caches are cleard
IntroScreen
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:healthtic/SliderModel.dart';
import 'package:healthtic/login.dart';
import 'package:healthtic/user_preferences.dart';
import 'package:shared_preferences/shared_preferences.dart';
class IntroScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "Healthtic",
home: IntorHome(),
debugShowCheckedModeBanner: false,
);
}
}
class IntorHome extends StatefulWidget {
#override
_IntorHomeState createState() => _IntorHomeState();
}
class _IntorHomeState extends State<IntorHome> {
List<SliderModel> slides=new List<SliderModel>();
int currentIndex=0;
PageController pageController=new PageController(initialPage: 0);
#override
void initState() {
// TODO: implement initState
super.initState();
slides=getSlides();
}
Widget pageIndexIndicator(bool isCurrentPage) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 2.0),
height: isCurrentPage ? 10.0 : 6.0,
width: isCurrentPage ? 10.0 :6.0,
decoration: BoxDecoration(
color: isCurrentPage ? Colors.grey : Colors.grey[300],
borderRadius: BorderRadius.circular(12)
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: PageView.builder(
controller: pageController,
onPageChanged: (val){
setState(() {
currentIndex=val;
});
},
itemCount: slides.length,
itemBuilder: (context,index){
return SliderTile(
ImageAssetPath: slides[index].getImageAssetPath(),
title: slides[index].getTile(),
desc: slides[index].getDesc(),
);
}),
bottomSheet: currentIndex != slides.length-1 ? Container(
height: Platform.isIOS ? 70:60,
padding: EdgeInsets.symmetric(horizontal: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
GestureDetector(
onTap: (){
pageController.animateToPage(slides.length-1, duration: Duration(
microseconds: 400,
), curve: Curves.linear);
},
child: Text("Skip")
),
Row(
children: <Widget>[
for(int i=0;i<slides.length;i++) currentIndex == i ?pageIndexIndicator(true): pageIndexIndicator(false)
],
),
GestureDetector(
onTap: (){
pageController.animateToPage(currentIndex+1, duration: Duration(
microseconds: 400
), curve: Curves.linear);
},
child: Text("Next")
),
],
),
) : Container(
alignment: Alignment.center,
width: MediaQuery.of(context).size.width,
height: Platform.isIOS ? 70:60,
color: Colors.blue,
child:
RaisedButton(
child: Text("Get Started Now",style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w300
),
),
onPressed: (){
MySharedPreferences.instance
.setBooleanValue("isfirstRun", true);
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (_) => Login()),
);
},
),
),
);
}
}
class SliderTile extends StatelessWidget {
String ImageAssetPath, title, desc;
SliderTile({this.ImageAssetPath, this.title, this.desc});
#override
Widget build(BuildContext context) {
return Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset(ImageAssetPath),
SizedBox(height: 20,),
Text(title),
SizedBox(height: 12,),
Text(desc),
],
)
,
);
}
}
final step Login
import 'package:flutter/material.dart';
import 'package:healthtic/user_preferences.dart';
import 'profile.dart';
class Login extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return LoginState();
}
}
class LoginState extends State<Login> {
TextEditingController controllerEmail = new TextEditingController();
TextEditingController controllerUserName = new TextEditingController();
TextEditingController controllerPassword = new TextEditingController();
#override
Widget build(BuildContext context) {
final formKey = GlobalKey<FormState>();
// TODO: implement build
return SafeArea(
child: Scaffold(
body: SingleChildScrollView(
child: Container(
margin: EdgeInsets.all(25),
child: Form(
key: formKey,
autovalidate: false,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text("Email Id:", style: TextStyle(fontSize: 18)),
SizedBox(width: 20),
Expanded(
child: TextFormField(
controller: controllerEmail,
decoration: InputDecoration(
hintText: "Please enter email",
),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value.trim().isEmpty) {
return "Email Id is Required";
}
},
),
)
],
),
SizedBox(height: 60),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text("UserName:", style: TextStyle(fontSize: 18)),
SizedBox(width: 20),
Expanded(
child: TextFormField(
decoration: InputDecoration(
hintText: "Please enter username",
),
validator: (value) {
if (value.trim().isEmpty) {
return "UserName is Required";
}
},
controller: controllerUserName),
)
],
),
SizedBox(height: 60),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text("Password:", style: TextStyle(fontSize: 18)),
SizedBox(width: 20),
Expanded(
child: TextFormField(
decoration: InputDecoration(
hintText: "Please enter password",
),
obscureText: true,
validator: (value) {
if (value.trim().isEmpty) {
return "Password is Required";
}
},
controller: controllerPassword),
)
],
),
SizedBox(height: 100),
SizedBox(
width: 150,
height: 50,
child: RaisedButton(
color: Colors.grey,
child: Text("Submit",
style: TextStyle(color: Colors.white, fontSize: 18)),
onPressed: () {
if(formKey.currentState.validate()) {
var getEmail = controllerEmail.text;
var getUserName = controllerUserName.text;
var getPassword = controllerPassword.text;
MySharedPreferences.instance
.setBooleanValue("loggedin", true);
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (_) => Profile()),
);
}
},
),
)
],
),
),
),
)),
);
}
}
Can be possible with this pakage : https://pub.dev/packages/is_first_run
Usage :
bool firstRun = await IsFirstRun.isFirstRun();