Related
I have build the screen with Appbar,Tabs and TabView, the Appear has TextField, every time text changes, the control is going inside the BLoC's emit but never received at UI. Please find the code below, I appreciate your any help.
class Buildings extends StatefulWidget {
const Buildings({super.key});
#override
State<StatefulWidget> createState() => _BuildingState();
}
class _BuildingState extends State<Buildings> {
late TextEditingController _searchController;
late NearbybuildingsBloc nearbybuildingsBloc;
late AllbuildingsBloc allbuildingsBloc;
late String _searchText='';
late BuildContext allBuildingContext;
#override
void initState() {
nearbybuildingsBloc = NearbybuildingsBloc();
allbuildingsBloc = AllbuildingsBloc();
_searchController = TextEditingController();
_searchController.addListener(() {
_searchText = _searchController.text;
});
super.initState();
}
#override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<NearbybuildingsBloc>(create: (context) => nearbybuildingsBloc..add(NearbyBuildings())),
BlocProvider<AllbuildingsBloc>(create: (context) => allbuildingsBloc..add(AllBuildings()))
],
child: DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
backgroundColor: AppColor.bt_indigo,
title: TextField(
onChanged: (value) {
allbuildingsBloc.add(
SearchbuildingLoadingEvent(query: _searchText),
);
},
style: const TextStyle(color: Colors.white),
controller: _searchController,
decoration: InputDecoration(
suffixIcon: _searchText.isEmpty
? null
:IconButton(
icon: const Icon(Icons.clear),
color: Colors.white,
onPressed: () => _searchController.clear(),
),
isDense: true,
hintText: 'Building name',
hintStyle: const TextStyle(color: AppColor.border_color),
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(
width: 2,
color: AppColor.text_editor_background),
borderRadius: BorderRadius.all(
Radius.circular(10.0)),
),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(
width: 2,
color: AppColor.text_editor_background),
borderRadius: BorderRadius.all(
Radius.circular(10.0)),
),
fillColor: AppColor.text_editor_background,),
),
actions: [
NamedIcon(
text: '',
iconData: Icons.filter_list_alt,
onTap: () {
/*showDialog(
context: context,
barrierDismissible: true,
builder: (BuildContext buildContext) {
return StatefulBuilder(
builder: (buildContext, state) {
return _openFilterCategoryDialog(
filterCategories, context, state);
});
});*/
},
),
NamedIcon(
text: '',
iconData: Icons.help,
notificationCount: 1,
onTap: () {
},
)],
bottom:
_searchText.isEmpty? TabBar(
tabs: [
Tab(text: 'Near by'),
Tab(text: 'All Buildings')
],
):null,
),
body: _searchText.isEmpty?TabBarView(
children: [
// Nearby buildings
BlocBuilder<NearbybuildingsBloc, NearbybuildingsState>(
builder: (context, state) {
if( state is NearbybuildingsLoading){
return const Center(child: CircularProgressIndicator(
color: AppColor.bt_indigo,
));
}
if(state is NearbybuildingsGpsPerm){
return row.getGPS(context);
}
if (state is NearbybuildingsLoaded) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("Showing ${state.nearBuildingList.length.toString()} buildings ", style: const TextStyle(
fontSize: 13,
color: AppColor.bt_indigo,
fontFamily: 'BT Regular'),
),
Expanded(
child: ListView.builder(
itemCount: state.nearBuildingList.length,
itemBuilder: (BuildContext context, int position) {
return row.getRow(state.nearBuildingList[position], context);
}),
)
],
);
}
return const Text("Failed to load buildings");
},
),
// All buildings
BlocBuilder<AllbuildingsBloc, AllbuildingsState>(
builder: (context, state) {
if( state is AllbuildingsError){
return const Text("Failed to load buildings");
}
if (state is AllbuildingsLoaded) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("Showing ${state.all.length.toString()} buildings ", style: const TextStyle(
fontSize: 13,
color: AppColor.bt_indigo,
fontFamily: 'BT Regular'),
),
Expanded(
child: ListView.builder(
itemCount: state.all.length,
itemBuilder: (BuildContext context, int position) {
return row.getRow(state.all[position], context);
}),
)
],
);
}
return const Text("Failed to load buildings");
},
),
],
):
// All buildings
BlocBuilder<AllbuildingsBloc, AllbuildingsState>(
builder: (context, state) {
if( state is SearchbuildingLoadingState){
return const Center(child: CircularProgressIndicator(
color: AppColor.bt_indigo,
));
}
if (state is SearchBuildingLoadedState) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("Showing ${state.searchresults.length.toString()} buildings ", style: const TextStyle(
fontSize: 13,
color: AppColor.bt_indigo,
fontFamily: 'BT Regular'),
),
Expanded(
child: ListView.builder(
itemCount: state.searchresults.length,
itemBuilder: (BuildContext context, int position) {
return row.getRow(state.searchresults[position], context);
}),
)
],
);
}
return const Text("Failed to load buildings");
},
),
// This trailing comma makes auto-formatting nicer for build methods.
),
),
);
}
}
State
class SearchBuildingLoadedState extends AllbuildingsState{
List<Building> searchresults;
SearchBuildingLoadedState({required this.searchresults});
#override
List<Object> get props {
return [searchresults];
}
}
Event
class SearchbuildingLoadingEvent extends AllbuildingsEvent {
final String query;
SearchbuildingLoadingEvent({required this.query});
#override
List<Object> get props {
return [query];
}
}
BLoC
class AllbuildingsBloc extends Bloc<AllbuildingsEvent, AllbuildingsState> {
AllbuildingsBloc() : super(AllbuildingsInitial()) {
on<SearchbuildingLoadingEvent>(_onSearchBuilding);
}
Future<void> _onSearchBuilding(SearchbuildingLoadingEvent event, Emitter<AllbuildingsState> emit) async {
emit(SearchbuildingLoadingState());
if(event.query.isNotEmpty || event.query.isNotEmpty) {
final database = await $FloorAppDataBase
.databaseBuilder('bootcamp-instagram-project.db')
.build();
final buildingDao = database.buildingDao;
var getBuilding = await buildingDao.getSearchBuildings(
event.query);
if (getBuilding != null) {
emit(SearchBuildingLoadedState(searchresults: getBuilding));
} else {
emit(SearchbuildingNoDataState());
}
}else{
emit(SearchbuildingNoDataState());
}
}
}
Please check the tab bar view to have three bloc builders where you provided,
whether you can try with
changing the tab controller
DefaultTabController(
length: 3,
child: Scaffold(
and add 1 more tabbar here
TabBar(
tabs: [
Tab(text: 'Near by'),
Tab(text: 'All Buildings')
],
)
Flutter keeps firing the api request, 200+ x sometimes and this makes the app really slow. I have tried async memorizer already, but this doesn't work. Do you have any idea how I can prevent multiple api requests with this code?
I'm getting an redscreen also when the page is loading. The error says Null check operator used on a null value.
I don't understand what I'm doing wrong. Tips & ideas are welcome.
class ProfileScreen extends StatefulWidget {
// ignore: deprecated_member_use_from_same_package
final ProfileNavigationEnum profileNavigationEnum;
final String? otherUserId;
final String? profileUrl;
final String? coverUrl;
const ProfileScreen({
Key? key,
this.otherUserId,
this.profileUrl,
this.coverUrl,
this.profileNavigationEnum = ProfileNavigationEnum.FROM_FEED,
}) : super(key: key);
#override
_ProfileScreenState createState() => _ProfileScreenState();
}
class _ProfileScreenState extends State<ProfileScreen>
with SingleTickerProviderStateMixin {
ProfileCubit? _profileCubit;
UserPostCubit? userPostCubit;
UserMediaCubit? userMediaCubit;
UserLikesCubit? userLikesCubit;
TabController? tabController;
Size? size;
#override
void initState() {
_profileCubit = BlocProvider.of<ProfileCubit>(context);
tabController = TabController(length: 3, vsync: this);
userPostCubit = getIt<UserPostCubit>();
userMediaCubit = getIt<UserMediaCubit>();
userLikesCubit = getIt<UserLikesCubit>();
_profileCubit!.profileEntity.listen((event) {
userLikesCubit!.userId = event.id;
userMediaCubit!.userId = event.id;
userPostCubit!.userId = event.id;
});
super.initState();
_profileCubit!
.getUserProfile(widget.otherUserId, widget.coverUrl, widget.profileUrl);
}
double textSizePred = 0.0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: BlocConsumer<ProfileCubit, CommonUIState>(
listener: (context, state) => state.maybeWhen(
orElse: () => null,
success: (state) => ProfileListener.success(state, context),
error: (e) => ProfileListener.error(e!, context),
),
builder: (_, state) {
return state.when(
initial: () => LoadingBar(),
success: (s) => getHomeWidget(),
loading: () => LoadingBar(),
error: (e) => Center(
child: NoDataFoundScreen(
onTapButton: context.router.root.pop,
icon: AppIcons.personOption(
color: AppColors.colorPrimary, size: 40),
title: 'Profile Not found',
message: e!.contains("invalid")
? LocaleKeys
.sorry_we_cannot_find_the_page_you_are_looking_for_if_you_still_ne
.tr()
: e,
buttonText: LocaleKeys.go_back.tr(),
),
),
);
},
),
);
}
Widget getHomeWidget() {
return StreamBuilder<ProfileEntity>(
stream: _profileCubit!.profileEntity,
builder: (context, snapshot) {
return DefaultTabController(
length: 3,
child: SafeArea(
child: NestedScrollView(
headerSliverBuilder: (context, value) {
return [
SliverAppBar(
automaticallyImplyLeading: false,
leading: null,
systemOverlayStyle: SystemUiOverlayStyle.light,
elevation: 0.0,
expandedHeight: calculateHeight(
context: context,
item: snapshot.data!,
) as double?,
floating: true,
pinned: true,
actions: [
IconButton(
icon: const Icon(Icons.edit),
onPressed: () async {
await openMediaPicker(
context,
(media) async {
_profileCubit!.changeProfileEntity(
snapshot.data!
.copyWith(backgroundImage: media),
);
await _profileCubit!
.updateProfileCover(media);
},
mediaType: MediaTypeEnum.IMAGE,
allowCropping: true,
);
}).toVisibility(widget.otherUserId == null)
],
// title: Text('Profile'),
backgroundColor: Colors.white,
flexibleSpace: FlexibleSpaceBar(
collapseMode: CollapseMode.pin,
background: snapshot.data == null
? Container()
: TopAppBar(
otherUserId: snapshot.data!.id,
otherUser: widget.otherUserId != null,
profileEntity: snapshot.data,
profileNavigationEnum:
widget.profileNavigationEnum,
onSizeAborted: (size) {
setState(() {
textSizePred = size;
});
},
),
),
// posts,media,likes row
bottom: PreferredSize(
child: Stack(
children: [
Positioned.fill(
child: Container(
decoration: const BoxDecoration(
color: Colors.white,
border: Border(
bottom: BorderSide(
color: Colors.grey,
width: 0.2,
),
),
),
),
),
TabBar(
indicatorWeight: 1,
indicatorSize: TabBarIndicatorSize.label,
labelPadding: const EdgeInsets.all(0),
labelStyle: TextStyle(
fontFamily: 'CeraPro',
fontWeight: FontWeight.w500,
),
unselectedLabelStyle: TextStyle(
fontFamily: 'CeraPro',
fontWeight: FontWeight.bold,
),
tabs: [
Tab(
text: LocaleKeys.posts.tr(),
).toContainer(
alignment: Alignment.center,
decoration: const BoxDecoration(
color: Colors.white,
border: Border(
top: BorderSide(
color: Colors.grey,
width: 0.2,
),
),
),
),
Tab(
text: LocaleKeys.media.tr(),
).toContainer(
alignment: Alignment.center,
decoration: const BoxDecoration(
color: Colors.white,
border: Border(
top: BorderSide(
color: Colors.grey,
width: 0.2,
),
),
),
),
Tab(
text: LocaleKeys.likes.tr(),
).toContainer(
alignment: Alignment.center,
decoration: const BoxDecoration(
color: Colors.white,
border: Border(
top: BorderSide(
color: Colors.grey,
width: 0.2,
),
),
),
),
],
)
],
),
preferredSize: const Size(500, 56),
),
),
];
},
body: TabBarView(
children: [
/// Add the block widget here thhree times
Container(
child: RefreshIndicator(
onRefresh: () {
userPostCubit!.onRefresh();
return Future.value();
},
child: PostPaginationWidget(
isComeHome: false,
isFromProfileSearch: true,
isPrivateAccount: (value) {
_profileCubit!.isPrivateUser = value;
},
isSliverList: false,
noDataFoundScreen: NoDataFoundScreen(
buttonText: LocaleKeys.go_to_the_homepage.tr(),
title: LocaleKeys.no_posts_yet.tr(),
message: "",
onTapButton: () {
context.router.root.pop();
},
),
pagingController: userPostCubit!.pagingController,
onTapLike: userPostCubit!.likeUnlikePost,
onOptionItemTap:
(PostOptionsEnum postOptionsEnum, int index) =>
userPostCubit!.onOptionItemSelected(
context, postOptionsEnum, index),
onTapRepost: userPostCubit!.repost,
),
),
),
Container(
child: RefreshIndicator(
onRefresh: () {
userMediaCubit!.onRefresh();
return Future.value();
},
child: PostPaginationWidget(
isComeHome: false,
isPrivateAccount: (value) {
_profileCubit!.isPrivateUser = value;
},
isSliverList: false,
noDataFoundScreen: NoDataFoundScreen(
title: LocaleKeys.no_media_yet.tr(),
icon: AppIcons.imageIcon(height: 35, width: 35),
buttonText: LocaleKeys.go_to_the_homepage.tr(),
message: "",
onTapButton: () {
context.router.root.pop();
// BlocProvider.of<FeedCubit>(context).changeCurrentPage(ScreenType.home());
// context.router.root.push(Routes.createPost);
},
),
pagingController: userMediaCubit!.pagingController,
onTapLike: userMediaCubit!.likeUnlikePost,
onOptionItemTap: (PostOptionsEnum postOptionsEnum,
int index) async =>
await userMediaCubit!.onOptionItemSelected(
context, postOptionsEnum, index),
onTapRepost: userMediaCubit!.repost,
),
)),
Container(
child: RefreshIndicator(
onRefresh: () {
userLikesCubit!.onRefresh();
return Future.value();
},
child: PostPaginationWidget(
isComeHome: false,
isPrivateAccount: (value) {
_profileCubit!.isPrivateUser = value;
},
isSliverList: false,
noDataFoundScreen: NoDataFoundScreen(
title: LocaleKeys.no_likes_yet.tr(),
icon: AppIcons.likeOption(
size: 35, color: AppColors.colorPrimary),
buttonText: LocaleKeys.go_to_the_homepage.tr(),
message: LocaleKeys
.you_don_t_have_any_favorite_posts_yet_all_posts_that_you_like_wil
.tr(),
onTapButton: () {
context.router.root.pop();
// BlocProvider.of<FeedCubit>(context).changeCurrentPage(ScreenType.home());
// context.router.root.push(Routes.createPost);
},
),
pagingController: userLikesCubit!.pagingController,
onTapLike: userLikesCubit!.likeUnlikePost,
onOptionItemTap:
(PostOptionsEnum postOptionsEnum, int index) =>
userLikesCubit!.onOptionItemSelected(
context,
postOptionsEnum,
index,
),
onTapRepost: userLikesCubit!.repost,
),
)),
],
),
),
),
);
});
}
num calculateHeight({
required BuildContext context,
required ProfileEntity item,
}) {
print('INCHES: ${context.diagonalInches}');
bool isSmallInches = context.diagonalInches <= 4.7;
bool hasWebsite = item.website != null && item.website!.isNotEmpty;
final height = context.getScreenHeight;
final defaultHeight = isSmallInches ? height * .6 : height * .47;
final websiteHeight = hasWebsite ? height * .03 : 0;
final sizeBoxHeight = textSizePred != 0.0 ? 10.h : 0;
return textSizePred + defaultHeight + websiteHeight + sizeBoxHeight;
}
}
/// helps to determine from where user navigated to profile
/// so that on back press of the profile screen we can go back the correct page
/// we're using this because according to the UI we will have the keep the bottom navigation bar under the profile page
enum ProfileNavigationEnum {
FROM_BOOKMARKS,
FROM_FEED,
FROM_SEARCH,
FROM_VIEW_POST,
FROM_MY_PROFILE,
FROM_OTHER_PROFILE,
FROM_MESSAGES,
FROM_NOTIFICATION
} ```
I've saw a code snippet for my app that i wanted to usw.. my problem now is that when i'm typing a new task into the app, my app just won't show that to the screen until a hot reload of the app. But first the user can't do any hot reloads AND for user experience it's very bad. If you need more code or debug things, please ask in the comments!
Here i the code (Ig it's this part thats not updating):
tasks_data.dart
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:learnon/models/task.dart';
import 'dart:collection';
import 'package:shared_preferences/shared_preferences.dart';
int id = 0;
List<Task> _taskList = [];
class TaskData extends ChangeNotifier {
List<String>? task = [];
List<String>? boxValue = [];
List<String>? dates = [];
List<String>? uid = [];
Future getData() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
//prefs.clear();
task!.clear();
boxValue!.clear();
_taskList.clear();
task = prefs.getStringList("task");
boxValue = prefs.getStringList("check");
dates = prefs.getStringList("date");
uid = prefs.getStringList("id");
if (task == null) {
task = ["Long Press to clear tasks"];
boxValue = ["false"];
dates = ["2021-05-24 02:18:04Z"];
uid = [id.toString()];
}
for (int i = 0; i < boxValue!.length; i++) {
_taskList.add(Task(
name: task![i],
isDone: boxValue![i] == 'true',
date: DateTime.parse(dates![i]),
id: int.parse(uid![i])));
}
id = int.parse(uid!.last);
id += 2;
notifyListeners();
}
void setData() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
task!.clear();
boxValue!.clear();
dates!.clear();
uid!.clear();
for (int i = 0; i < _taskList.length; i++) {
task!.add(_taskList[i].name!);
boxValue!.add(_taskList[i].isDone.toString());
dates!.add(_taskList[i].date.toString());
uid!.add(_taskList[i].id.toString());
}
await prefs.setStringList("task", task!);
await prefs.setStringList("check", boxValue!);
await prefs.setStringList("date", dates!);
await prefs.setStringList("id", uid!);
notifyListeners();
}
UnmodifiableListView<Task> get tasks {
return UnmodifiableListView(_taskList);
}
void addTask(String t, DateTime d, int uid) {
_taskList.add(Task(name: t, date: d, id: uid));
setData();
notifyListeners();
}
int get taskCount {
return _taskList.length;
}
void updateTask(Task task) {
task.toggleDone();
setData();
notifyListeners();
}
void deleteTask(Task t) {
_taskList.remove(t);
setData();
notifyListeners();
}
}
tasksscreen.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:learnon/widgets/tasks_list.dart';
import 'package:learnon/screens/add_task_screen.dart';
import 'package:learnon/models/tasks_data.dart';
import 'package:provider/provider.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import '../widgets/app_drawer.dart';
bool theme = false;
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
class TasksScreenNew extends StatelessWidget {
static const routeName = "/tasksnew";
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<TaskData>(
create: (_) => TaskData(),
builder: (context, __) => Scaffold(
appBar: AppBar(
title: Text("Tasks"),
centerTitle: true,
),
drawer: AppDrawer(),
backgroundColor: Colors.blueAccent,
floatingActionButton: FloatingActionButton(
heroTag: null,
child: Icon(Icons.add),
backgroundColor: Colors.lightBlue,
onPressed: () {
showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (BuildContext context) => AddTaskScreen());
},
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.only(
top: 60, left: 30, right: 30, bottom: 30),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Builder(
builder: (context) => FloatingActionButton(
onPressed: () {},
backgroundColor: Colors.black,
child: Icon(
Icons.refresh,
color: Colors.blueAccent,
size: 30,
),
),
),
SizedBox(
height: 10,
),
Text(
'Tasks',
style: TextStyle(
color: Colors.white,
fontSize: 50,
fontWeight: FontWeight.bold),
),
Text(
'${Provider.of<TaskData>(context).taskCount} Task(s) übrig',
style: TextStyle(fontSize: 18, color: Colors.white),
),
],
),
),
Expanded(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 20),
child: TasksList(),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
color: Colors.black),
),
)
]),
));
}
}
// CircleAvatar(
// radius: 30,
// backgroundColor: Colors.white,
// child: Icon(
// Icons.list,
// color: Colors.blueAccent,
// size: 30,
// ),
// )
tasks_list.dart
import 'package:flutter/material.dart';
import 'package:learnon/screens/tasksscreennew.dart';
import 'package:learnon/widgets/task_tile.dart';
import 'package:provider/provider.dart';
import 'package:learnon/models/tasks_data.dart';
import 'dart:core';
class TasksList extends StatefulWidget {
#override
State<TasksList> createState() => _TasksListState();
}
class _TasksListState extends State<TasksList> {
#override
Widget build(BuildContext context) {
return Consumer<TaskData>(
builder: (context, taskData, child) {
return ListView.builder(
itemBuilder: (context, index) {
return TaskTile(
taskTitle: taskData.tasks[index].name,
isChecked: taskData.tasks[index].isDone,
timeLeft: taskData.tasks[index].date!
.difference(DateTime.now())
.inMinutes >
0
? ('${taskData.tasks[index].date!.difference(DateTime.now()).inHours.toString()} Hours left')
: 'Time Expired',
checkboxCallback: (checkBoxState) {
taskData.updateTask(taskData.tasks[index]);
},
longPressCallback: () {
if ((taskData.tasks[index].id!) != 0 ||
(taskData.tasks[index].id!) != 1) {
flutterLocalNotificationsPlugin
.cancel(taskData.tasks[index].id!);
flutterLocalNotificationsPlugin
.cancel(taskData.tasks[index].id! + 1);
}
taskData.deleteTask(taskData.tasks[index]);
},
notificationCallback: () {
flutterLocalNotificationsPlugin
.cancel(taskData.tasks[index].id!);
flutterLocalNotificationsPlugin
.cancel(taskData.tasks[index].id! + 1);
},
);
},
itemCount: taskData.taskCount,
);
},
);
}
}
task_tile.dart
import 'package:flutter/material.dart';
class TaskTile extends StatelessWidget {
final bool? isChecked;
final String? taskTitle;
final Function? checkboxCallback;
final Function longPressCallback;
final Function notificationCallback;
final String? timeLeft;
TaskTile(
{this.isChecked = false,
this.taskTitle,
this.checkboxCallback,
required this.longPressCallback,
this.timeLeft,
required this.notificationCallback()});
#override
Widget build(BuildContext context) {
return ListTile(
onLongPress: () {
longPressCallback();
},
title: Text(
taskTitle!,
style: TextStyle(
fontSize: 20,
color: (timeLeft!) == 'Time Expired'
? Colors.red
: isChecked!
? Colors.green
: null,
),
),
subtitle: Text(
isChecked! ? 'Completed' : (timeLeft!),
style: TextStyle(
color: (timeLeft!) == 'Time Expired'
? Colors.red
: isChecked!
? Colors.green
: null,
),
),
trailing: Checkbox(
activeColor: Colors.lightBlueAccent,
value: isChecked,
onChanged: (value) {
if (value == true) {
notificationCallback();
}
checkboxCallback!(value);
},
),
);
}
}
addtaskscreen.dart
// ignore_for_file: deprecated_member_use
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:learnon/models/tasks_data.dart';
import 'package:date_field/date_field.dart';
import 'package:learnon/screens/tasksscreennew.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
String? newTaskTitle;
DateTime? dateTime;
class AddTaskScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<TaskData>(
create: (_) => TaskData(),
builder: (context, __) => Container(
height: MediaQuery.of(context).viewInsets.bottom + 300,
color: Colors.black,
child: Container(
height: MediaQuery.of(context).viewInsets.bottom + 300,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 50, vertical: 30),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'Task hinzufügen',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white, fontSize: 25),
),
TextField(
// controller: myController,
autofocus: true,
textAlign: TextAlign.center,
onChanged: (value) {
newTaskTitle = value;
},
),
SizedBox(
height: 10,
),
Text(
'Abgabedatum',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white, fontSize: 25),
),
SizedBox(
height: 10,
),
DateTimeFormField(
decoration: const InputDecoration(
hintStyle: TextStyle(color: null),
errorStyle: TextStyle(color: Colors.redAccent),
border: OutlineInputBorder(),
suffixIcon: Icon(Icons.event_note),
),
mode: DateTimeFieldPickerMode.dateAndTime,
initialDatePickerMode: DatePickerMode.day,
firstDate: DateTime.now(),
autovalidateMode: AutovalidateMode.always,
validator: (e) => (e?.day ?? 0) == 1
? 'Please not the first day'
: null,
onDateSelected: (DateTime value) {
dateTime = value;
},
),
TextButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Colors.green),
),
autofocus: false,
onPressed: () async {
print(newTaskTitle);
print(dateTime);
Provider.of<TaskData>(context, listen: false)
.addTask(newTaskTitle!, dateTime!, id);
await flutterLocalNotificationsPlugin.schedule(
id++,
'Zeit abgelaufen',
newTaskTitle!,
dateTime!,
const NotificationDetails(
android: AndroidNotificationDetails(
'1', 'Zeit abgelaufen')),
androidAllowWhileIdle: true,
);
await flutterLocalNotificationsPlugin.schedule(
id++,
dateTime!.difference(DateTime.now()).inMinutes /
2 <
60
? '${dateTime!.difference(DateTime.now()).inMinutes / 2} Minuten übrig'
: '${dateTime!.difference(DateTime.now()).inHours / 2} Stunden übrig',
newTaskTitle!,
dateTime!.subtract(Duration(
minutes: dateTime!
.difference(DateTime.now())
.inMinutes ~/
2)),
const NotificationDetails(
android: AndroidNotificationDetails(
'5', 'Reminder')),
androidAllowWhileIdle: true,
);
Navigator.pop(context);
},
child: Text(
'Hinzufügen',
style: TextStyle(
color: Colors.white,
// backgroundColor: Colors.lightBlueAccent,
fontSize: 20,
),
),
)
],
),
),
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
)),
));
}
}
Since you're making your TaskData as a **ChangeNotifier, are you wrapping your widget inside a Consumer widget, and using this class inside the Consumer widget, like this:
Consumer<TaskData>(
builder: (context, taskData, child) {
return <YOUR_WIDGET_HERE>;
}
)
That way all changes you make via your service class should be reflected and trigger a rebuild on your widget?
Also are you using a MultiProvider widget, how are you providing this class?
Can anyone please tell me how do I select multiple options in checkboxlisttile.
Here I am able to click only one option. I want to set the status column in note table in database as completed when i check the particular item.
(Actually I want to select the item as completed and display it under another tab called completed. checkboxlisttile is created dynamically i.e from database. When a new note is added it is displayed in this listview.)
note_info.dart //this is the screen where notes are displayed i.e listview
import 'dart:io';
import 'package:vers2cts/models/note_model.dart';
import 'package:vers2cts/models/customer_model.dart';
import 'package:vers2cts/services/db_service.dart';
import 'package:vers2cts/utils/db_helper.dart';
import 'package:flutter/material.dart';
import 'package:sqflite/sqflite.dart';
import 'new_note.dart';
class Note_Info extends StatefulWidget{
final String appBarTitle;
final CustomerModel customer;
//Note_Info();
Note_Info(this. customer, this.appBarTitle);
#override
State<StatefulWidget> createState() {
//return Note_InfoState();
return Note_InfoState(this. customer,this.appBarTitle);
}
}
class Note_InfoState extends State<Note_Info> {
DBService dbService = DBService();
List<NoteModel> noteList;
int count = 0;
static final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
NoteModel note=NoteModel();
String appBarTitle;
CustomerModel customer=new CustomerModel();
Note_InfoState(this.customer, this.appBarTitle);
bool rememberMe = false;
DateTime _date = DateTime.now();
TextEditingController custfNameController = TextEditingController();
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
updateListView();
if (noteList == null) {
noteList = List<NoteModel>();
updateListView();
}
TextStyle titleStyle = Theme.of(context).textTheme.subhead;
var height = MediaQuery.of(context).size.height;
var name=customer.first_name+" "+customer.last_name;
custfNameController.text = name;
return DefaultTabController(
length: 4,
child: Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(
Icons.add,
),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => NewNote(customer,note)));
},
)
],
),
body: Container(
child: Column(
children: <Widget>[
TextField(controller: custfNameController,
style: TextStyle(
fontSize: 20.0, fontWeight: FontWeight.bold),
textAlign: TextAlign.center),
Padding(
padding: const EdgeInsets.all(15.0),
child: Row(children: [
ImageProfile(customer.cust_photo),
Padding(
padding: const EdgeInsets.only(left: 30.0),
child: IconButton(
icon: Icon(
Icons.call,
color: Colors.green,
size: 45,
),
onPressed: () {
},
),
),
],),
),
SizedBox(
height: 50,
child: AppBar(
bottom: TabBar(
tabs: [
Tab(
text: "All",
),
Tab(
text: "Pending",
),
Tab(
text: "Cancelled",
),
Tab(
text: "Completed",
),
],
),
),
),
// create widgets for each tab bar here
Expanded(
child: TabBarView(
children: [
// first tab bar view widget
Container(
child: getNotecheckList()
),
// second tab bar view widget
Container(
),
Container(
child: Center(
child: Text(
'Cancelled',
),
),
),
Container(
child: Center(
child: Text(
'Completed',
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 55.0,
width: 200,
child: RaisedButton(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
color: Theme
.of(context)
.primaryColorDark,
textColor: Colors.white,
child: Text('Save', textScaleFactor: 1.5,),
onPressed: () {
setState(() {
//_reset();
});
},
),
),
),
]
),
)
));
}
Widget ImageProfile(String fileName) {
return Center(
child: CircleAvatar(
radius: 80.0,
backgroundImage: fileName == null
?AssetImage('images/person_icon.jpg')
:FileImage(File(customer.cust_photo))),
);
}
Future<void> updateListView() {
final Future<Database> dbFuture = DB.init();
dbFuture.then((database) {
int cid=customer.cust_id;
Future<List<NoteModel>> noteListFuture = dbService.getCustomerNotes(cid);
noteListFuture.then((noteList) {
setState(() {
this.noteList = noteList;
this.count = noteList.length;
});
});
});
}
int _isChecked=-1;
ListView getNotecheckList() {
return ListView.builder(
itemCount: count,
itemBuilder: (BuildContext context, int position) {
return Card(
color: Colors.white,
elevation: 2.0,
child: CheckboxListTile(
title: Text(this.noteList[position].note),
subtitle: Text(this.noteList[position].actn_on),
//secondary: const Icon(Icons.web),
value: position== _isChecked,
onChanged: (bool value) {
setState(() {
_isChecked = value?position:-1;
});
},
controlAffinity: ListTileControlAffinity.leading,
),
);
},
);
}
}
new_note.dart //this is where new note is added.
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:table_calendar/table_calendar.dart';
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
import 'package:smooth_star_rating/smooth_star_rating.dart';
import 'package:intl/intl.dart';
import 'package:vers2cts/models/customer_model.dart';
import 'package:vers2cts/models/note_model.dart';
import 'package:vers2cts/services/db_service.dart';
import 'package:vers2cts/utils/form_helper.dart';
class NewNote extends StatefulWidget{
final NoteModel note;
final CustomerModel customer;
NewNote(this.customer,this. note);
//Dropdown
/*
final String label;
final Function(Color) onChanged;
final double height;
final double width;
NewNote.fordropdwn({
Key key,
this.onChanged,
this.height = 25,
this.width = 150,
this.label,
}) : super(key: key);*/
#override
State<StatefulWidget> createState() {
//return New_NoteState(this.customer);
return New_NoteState(this.customer,this.note);
}
}
class New_NoteState extends State<NewNote> with SingleTickerProviderStateMixin{
New_NoteState(this.customer,this.note);
NoteModel note=new NoteModel();
CustomerModel customer=new CustomerModel();
TextEditingController NoteController=TextEditingController();
TextEditingController custfNameController = TextEditingController();
DateTime _reminderDate = DateTime.now();
DBService dbService=new DBService();
SpeedDial _speedDial(){
return SpeedDial(
// child: Icon(Icons.add),
animatedIcon: AnimatedIcons.add_event,
animatedIconTheme: IconThemeData(size: 24.0),
backgroundColor: Colors.yellow,
curve: Curves.easeInCirc,
children: [
SpeedDialChild(
child: Icon(Icons.location_on,color: Colors.yellow,),
//backgroundColor: Theme.of(context).primaryColor,
label: 'Add Location',
//labelBackgroundColor:Theme.of(context).primaryColor,
),
SpeedDialChild(
child: Icon(Icons.keyboard_voice),
//backgroundColor: Colors.yellow,
label: 'Add voice',
//labelBackgroundColor: Colors.yellow
),
SpeedDialChild(
child: Icon(Icons.attachment_outlined,color :Colors.redAccent),
//backgroundColor:Theme.of(context).primaryColorLight,
label: 'Add File',
// labelBackgroundColor: Theme.of(context).primaryColorLight
),
SpeedDialChild(
child: Icon(Icons.image,color: Colors.lightBlue,),
//backgroundColor: Colors.yellow,
label: 'Add Image',
// labelBackgroundColor: Colors.yellow,
),
],
);
}
//for DropDownMenu
Color value=Colors.red;
final List<Color> colors = [
Colors.red,
Colors.blue,
Colors.green,
Colors.yellow,
Colors.pink,
Colors.purple,
Colors.brown,
];
//for Switch
bool isSwitched = false;
var textValue = 'Switch is OFF';
void toggleSwitch(bool value) {
if(isSwitched == false)
{
setState(() {
isSwitched = true;
note.rmnd_ind=1;
//this.note.remindOn = _reminderDate.toString();
});
}
else
{
setState(() {
isSwitched = false;
note.rmnd_ind=0;
});
}
}
#override
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
var name=customer.first_name+customer.last_name;
custfNameController.text = name;
return WillPopScope(
onWillPop: () {
// Write some code to control things, when user press Back navigation button in device navigationBar
moveToLastScreen();
},
child: Scaffold(
appBar:AppBar(),
body:ListView(
children: <Widget>[
SizedBox(
height: 2.0,
),
TextField(controller: custfNameController,
style: TextStyle(
fontSize: 20.0, fontWeight: FontWeight.bold),
textAlign: TextAlign.center),
Align(
alignment: Alignment.centerLeft,
child: Text("Add New",textAlign: TextAlign.left,
style: TextStyle(fontSize: 22,fontWeight: FontWeight.bold),),
),
SizedBox(
height: 2.0,
),
Divider(),
SizedBox(
height: 2.0,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: NoteController,
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide: const BorderSide(width: 2.0),)),
keyboardType: TextInputType.multiline,
minLines: 5,//Normal textInputField will be displayed
maxLines: 5, // when user presses enter it will adapt to it
onChanged: (value) {
this.note.note = value;
},
),
),
TableCalendar(
selectedDayPredicate: (day) {
return isSameDay(_reminderDate, day);
},
onDaySelected: (selectedDay, focusedDay) {
setState(() {
String _reminderDate = DateFormat('dd-MM-yyyy').format(selectedDay);
note.actn_on=_reminderDate.toString();
});
},// Set initial date
focusedDay: DateTime.now(),
firstDay: DateTime.utc(2010, 10, 16),
lastDay: DateTime.utc(2030, 3, 14),),
SizedBox(
height: height*0.03,
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(//mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text("Remind me",style: TextStyle(fontSize: 20),),
Padding(
padding: const EdgeInsets.only(left:80.0),
child: Container(
child: Switch(
onChanged: toggleSwitch,
value: isSwitched,
//activeColor: Colors.blue,
//activeTrackColor: Colors.yellow,
//inactiveThumbColor: Colors.redAccent,
//inactiveTrackColor: Colors.orange,
),
),
),
],),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(mainAxisAlignment: MainAxisAlignment.start,
children:<Widget>[
Text("Priority",style: TextStyle(fontSize: 20.0),),
Padding(
padding: const EdgeInsets.only(left:20.0),
child: Container(
child: SmoothStarRating(
size: height=50.0,
allowHalfRating: false,
onRated: (value) {
this.note.prty=value;
print("rating value -> $value");
},
),
),
)]),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text("Color",style: TextStyle(fontSize: 20),),
Padding(
padding: const EdgeInsets.only(left:80.0),
child: Container(
child: DropdownButton<Color>(
value: value,
//hint: Text(widget.label ?? ''),
onChanged: (color) {
setState(() => value = color);
//widget.onChanged(color);
},
items: colors.map((e) => DropdownMenuItem(
value: e,
child: Container(
// width: 60.0,
//height: 10.0,
width: 60.0,
// height: widget.height,
color: e,
),
),
)
.toList(),
),
),
),
],),
),
SizedBox(
height: height*0.08,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 55.0,
width: 200,
child: RaisedButton(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
color: Theme.of(context).primaryColorDark,
textColor: Colors.white,
child: Text('Save',textScaleFactor: 1.5,),
onPressed: (){
setState(() {
_save();
});
},
),
),
),
],
),
floatingActionButton:_speedDial(),
));
}
void moveToLastScreen() {
Navigator.pop(context, true);
}
void _save() async {
moveToLastScreen();
note.cust_id=customer.cust_id;
print(customer.cust_id);
print(note.cust_id);
int result;
if (note.note_id != null) { // Case 1: Update operation
result = await dbService.updateNote(note);
} else { // Case 2: Insert Operation
result = await dbService.insertNote(note);
}
if (result != 0) { // Success
FormHelper.showAlertDialog(context,'Status', 'Note Saved Successfully');
} else { // Failure
FormHelper.showAlertDialog(context,'Status', 'Problem Saving Note');
}
}
}
db_service.dart
import 'package:vers2cts/models/customer_model.dart';
import 'package:vers2cts/models/languages_model.dart';
import 'package:vers2cts/models/note_model.dart';
import 'package:vers2cts/models/user_model.dart';
import 'package:vers2cts/utils/db_helper.dart';
class DBService {
Future<int> insertNote(NoteModel note) async {
await DB.init();
var result = await DB.insert(NoteModel.table, note);
return result;
}
Future<List<NoteModel>> getCustomerNotes(int customer) async {
await DB.init();
var res = await DB.rawQuery("note WHERE cust_id = '$customer'");
int count = res.length;
List<NoteModel> notelist = List<NoteModel>();
// For loop to create a 'Note List' from a 'Map List'
for (int i = 0; i < count; i++) {
notelist.add(NoteModel.fromMap(res[i]));
}
return notelist;
}
}
note_model.dart
import 'model.dart';
class NoteModel extends Model {
static String table = 'note';
bool isSelected=false;
int note_id;
int cust_id;
String note;
String actn_on;
int rmnd_ind;
double prty;
String colr;
String sts;
int id;
String cre_date;
String cre_by;
String mod_date;
String mod_by;
int txn_id;
int delete_ind;
NoteModel({
this.note_id,
this.cust_id,
this.note,
this.actn_on,
this.rmnd_ind,
this.prty,
this.colr,
this.sts,
this.id,
this.cre_date,
this.cre_by,
this.mod_date,
this.mod_by,
this.txn_id,
this.delete_ind
});
static NoteModel fromMap(Map<String, dynamic> map) {
return NoteModel(
note_id: map["note_id"],
cust_id: map['cust_id'],
note: map['note'].toString(),
actn_on: map['actn_on'].toString(),
rmnd_ind: map['rmnd_ind'],
prty: map['prty'],
colr: map['colr'].toString(),
sts: map['sts'].toString(),
id: map['id'],
cre_date: map['cre_date'].toString(),
cre_by: map['cre_by'].toString(),
mod_date: map['mod_date'].toString(),
mod_by: map['mod_by'].toString(),
txn_id: map['txn_id'],
delete_ind: map['delete_ind'],
);
}
Map<String, dynamic> toMap() {
Map<String, dynamic> map = {
'note_id': note_id,
'cust_id': cust_id,
'note':note,
'actn_on': actn_on,
'rmnd_ind': rmnd_ind,
'prty': prty,
'colr': colr,
'sts':sts,
'id': id,
'cre_date': cre_date,
'cre_by': cre_by,
'mod_date':mod_date,
'mod_by':mod_by,
'txn_id':txn_id,
'delete_ind': delete_ind
};
if (note_id != null) {
map['note_id'] = note_id;
}
return map;
}
}
db_helper.dart
import 'dart:async';
import 'package:vers2cts/models/model.dart';
import 'package:path/path.dart' as p;
import 'package:sqflite/sqflite.dart';
abstract class DB {
static Database _db;
static int get _version => 1;
static Future<Database> init() async {
if (_db != null) {
return _db;
}
try {
var databasesPath = await getDatabasesPath();
String _path = p.join(databasesPath, 'CTS.db');
_db = await openDatabase(_path, version: _version, onCreate: onCreate);
print('db location:'+_path);
} catch (ex) {
print(ex);
}
}
static void onCreate(Database db, int version) async {
await db.execute(
'CREATE TABLE note (note_id INTEGER PRIMARY KEY,cust_id INTEGER, '
'note TEXT, '
'actn_on TEXT, rmnd_ind INTEGER, prty REAL, colr TEXT,'
'sts TEXT,'
'id INTEGER, cre_date TEXT,cre_by TEXT, mod_date TEXT,mod_by TEXT, txn_id INTEGER, delete_ind INTEGER)');
}
static Future<List<Map<String, dynamic>>> query(String table) async =>
_db.query(table);
static Future<int> insert(String table, Model model) async =>
await _db.insert(table, model.toMap());
static Future<Batch> batch() async => _db.batch();
static Future<List<Map<String, dynamic>>> rawQuery(String table) async =>
_db.query(table);
}
You need to store what all values are selected from user and then play with it.
For example -
var selectedIndexes = [];
ListView getNotecheckList() {
return ListView.builder(
itemCount: count,
itemBuilder: (_, int index) {
return Card(
color: Colors.white,
elevation: 2.0,
child: CheckboxListTile(
title: Text(this.noteList[position].note),
subtitle: Text(this.noteList[position].actn_on),
value: selectedIndexes.contains(index),
onChanged: (_) {
if (selectedIndexes.contains(index)) {
selectedIndexes.remove(index); // unselect
} else {
selectedIndexes.add(index); // select
}
},
controlAffinity: ListTileControlAffinity.leading,
),
);
},
);
}
store only index or whole array and play around
Output :-
Code :-
import 'package:flutter/material.dart';
class CheckBoxExample extends StatefulWidget {
const CheckBoxExample({Key? key}) : super(key: key);
#override
State<CheckBoxExample> createState() => _CheckBoxExampleState();
}
class _CheckBoxExampleState extends State<CheckBoxExample> {
List multipleSelected = [];
List checkListItems = [
{
"id": 0,
"value": false,
"title": "Sunday",
},
{
"id": 1,
"value": false,
"title": "Monday",
},
{
"id": 2,
"value": false,
"title": "Tuesday",
},
{
"id": 3,
"value": false,
"title": "Wednesday",
},
{
"id": 4,
"value": false,
"title": "Thursday",
},
{
"id": 5,
"value": false,
"title": "Friday",
},
{
"id": 6,
"value": false,
"title": "Saturday",
},
];
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 64.0),
child: Column(
children: [
Column(
children: List.generate(
checkListItems.length,
(index) => CheckboxListTile(
controlAffinity: ListTileControlAffinity.leading,
contentPadding: EdgeInsets.zero,
dense: true,
title: Text(
checkListItems[index]["title"],
style: const TextStyle(
fontSize: 16.0,
color: Colors.black,
),
),
value: checkListItems[index]["value"],
onChanged: (value) {
setState(() {
checkListItems[index]["value"] = value;
if (multipleSelected.contains(checkListItems[index])) {
multipleSelected.remove(checkListItems[index]);
} else {
multipleSelected.add(checkListItems[index]);
}
});
},
),
),
),
const SizedBox(height: 64.0),
Text(
multipleSelected.isEmpty ? "" : multipleSelected.toString(),
style: const TextStyle(
fontSize: 22.0,
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
],
),
),
);
}
}
I am new to flutter. I have a question about scaffold in my project.
I have a home screen that I use to display the BottomNavigation widget. I guess that I also use if as a container to display all of the other pages/screens in so that the BottomNavigation will stay visible. Here is the code below:
class Home_Screen extends StatefulWidget {
static const String id = 'home_screen';
#override
_Home_ScreenState createState() => _Home_ScreenState();
}
// ignore: camel_case_types
class _Home_ScreenState extends State<Home_Screen> {
PageController _pageController = PageController();
List<Widget> _screens = [
AgentDashboardScreen(),
TransactionDetailScreen(),
AgentProfileScreen(),
];
int _selectedIndex = 0;
void _onPageChanged(int index) {
setState(() {
_selectedIndex = index;
});
}
void _itemTapped(int selectedIndex) {
if (selectedIndex == 3) {
Navigator.of(context).pushAndRemoveUntil(
// the new route
MaterialPageRoute(
builder: (BuildContext context) => WelcomeScreen(),
),
(Route route) => false,
);
} else {
_pageController.jumpToPage(selectedIndex);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: PageView(
controller: _pageController,
children: _screens,
onPageChanged: _onPageChanged,
physics: NeverScrollableScrollPhysics(),
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
onTap: _itemTapped,
items: [
BottomNavigationBarItem(
icon: Icon(
Icons.home,
color: _selectedIndex == 0 ? Colors.blueAccent : Colors.grey,
),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(
Icons.account_balance,
color: _selectedIndex == 1 ? Colors.blueAccent : Colors.grey,
),
label: 'Add Tran',
),
BottomNavigationBarItem(
icon: Icon(
Icons.person,
color: _selectedIndex == 2 ? Colors.blueAccent : Colors.grey,
),
label: 'Profile',
),
BottomNavigationBarItem(
icon: Icon(
Icons.album_outlined,
color: _selectedIndex == 3 ? Colors.blueAccent : Colors.grey,
),
label: 'Logout',
),
],
),
);
}
}
In one of the screens that I can navigate to from the BottomNavigator I am having issues with a large white space above the keyboard. I have read that having a scaffold inside another scaffold can cause this.
So, when I navigate to the next page do I have a scaffold inside another scaffold? Here is a snippet from the second page.
class TransactionDetailScreen extends StatefulWidget {
static const String id = 'transaction_detail_screen';
final QueryDocumentSnapshot trxns;
//final Trxns trxns;
//final QuerySnapshot queryTrxns = trxns;
TransactionDetailScreen([this.trxns]);
#override
_TransactionDetailScreenState createState() =>
_TransactionDetailScreenState();
}
class _TransactionDetailScreenState extends State<TransactionDetailScreen> {
String _trxnStatus = 'Listed';
#override
Widget build(BuildContext context) {
// Get the stream of transactions created in main.dart
final trxnProvider = Provider.of<TrxnProvider>(context);
return Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset('assets/images/Appbar_logo.png',
fit: BoxFit.cover, height: 56),
],
),
),
backgroundColor: Colors.white,
body: SingleChildScrollView(
reverse: true,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
Text(
'Transaction Details',
style: TextStyle(
fontSize: 30,
),
),
SizedBox(
height: 8.0,
),
TextField(
autofocus: true,
keyboardType: TextInputType.text,
controller: clientFNameController,
textAlign: TextAlign.center,
onChanged: (value) {
trxnProvider.changeclientFName(value);
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Client First Name',
labelText: 'Client First Name'),
),
RoundedButton(
title: 'Save',
colour: Colors.blueAccent,
onPressed: () async {
setState(() {
showSpinner = true;
});
try {
trxnProvider.saveTrxn();
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => AgentDashboardScreen(),
),
);
setState(() {
showSpinner = false;
});
} catch (e) {
// todo: add better error handling
print(e);
}
},
),
SizedBox(
height: 8.0,
),
(widget != null)
? RoundedButton(
title: 'Delete',
colour: Colors.red,
onPressed: () async {
setState(() {
showSpinner = true;
});
try {
trxnProvider.deleteTrxn(widget.trxns['trxnId)']);
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => AgentDashboardScreen(),
),
);
setState(() {
showSpinner = false;
});
} catch (e) {
// todo: add better error handling
print(e);
}
},
)
: Container(),
],
),
),
),
);
}
}
The keyboard works/looks as expected (no white space above) if the textboxes are empty. Am I doing this correctly or should I do it differently?
Thanks