How to prevent keyboard moving up an other widget in a stack? (flutter) - flutter

I've got a new transaction screen with several textfields and a container at the bottom for shortcuts:
And when i trigger a textfield the grey container moves up as well:
Here is my code for the screen:
//import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
//import 'package:flutter/services.dart';
import '../items/icon_picket_item.dart';
import '../items/select_transaction_item.dart';
import '../providers/user_transactions.dart';
import '../providers/icon_auswahl.dart';
import '../providers/account_type.dart';
import '../providers/user_settings/single_multiple_acc.dart';
import 'package:provider/provider.dart';
import '../storag/locale.dart';
import '../storag/foundation.dart';
import '../my_icons.dart';
class NewTransactionScreen extends StatefulWidget {
static const routeName = '/new-transaction';
#override
_NewTransactionScreenState createState() => _NewTransactionScreenState();
}
class _NewTransactionScreenState extends State<NewTransactionScreen> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
final _titleController = TextEditingController(text: '');
final _amountController = TextEditingController(text: '-10.00');
final _accountController = TextEditingController();
final _notesController = TextEditingController();
final _repeatController = TextEditingController();
DateTime _selectedDate;
Color _correct = Colors.white54;
final data = [];
void _colorCorrect() {
final enteredTitle = _titleController.text;
final enteredAmount = _amountController.text;
final enteredAccount = _accountController.text;
final enteredRepeat = _repeatController.text;
Color color;
if (enteredTitle.isEmpty ||
enteredAmount.isEmpty ||
enteredAccount.isEmpty ||
enteredRepeat.isEmpty) {
color = Colors.white54;
} else {
color = Colors.white;
}
setState(() {
_correct = color;
});
}
void _submitData(String choiceId, NewTransactions transactions, iconData,
GeldKonto kontoss) {
//onSubmitted gives you a string
if (_amountController.text.isEmpty) {
return;
}
final enteredTitle = _titleController.text;
final enteredAmount = _amountController.text;
final enteredAccount = _accountController.text;
final enteredNotes = _notesController.text;
final enteredRepeat = _repeatController.text;
Icon enteredIcon = iconData.taken;
if (enteredTitle.isEmpty ||
enteredAmount.isEmpty ||
enteredAccount.isEmpty ||
enteredRepeat.isEmpty) {
return; //means code stops here and addTx doesnt run
} else {
transactions.addNewtransaction(
xTitle: enteredTitle,
xAmount: double.parse(enteredAmount) <= 0
? double.parse(enteredAmount) * (-1)
: double.parse(enteredAmount),
xchosenDate: _selectedDate == null ? DateTime.now() : _selectedDate,
xAccountType: enteredAccount,
xNotes: enteredNotes,
xRepeat: enteredRepeat,
xIcon: enteredIcon,
xId: DateTime.now().toString(),
xchoiceId: choiceId);
}
Navigator.of(context).pop(context);
// .pop closes modalsheet , you have the property contexyt cause of extends state
}
Container _buildTransactionRow(
{Text typedText,
Function onPress,
comparisonStuff,
Icon icon,
double iconSpace,
double iconAfterSpace}) {
final mediaQuery = MediaQuery.of(context);
return Container(
// padding: EdgeInsets.symmetric(vertical: 15, horizontal: 15),
child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
SizedBox(height: 1, width: iconSpace),
icon,
SizedBox(height: 1, width: iconAfterSpace), //25
SizedBox(
width: mediaQuery.size.width * 0.75,
child: GestureDetector(
onTap: onPress,
child: Column(
//crossAxisAlignment: CrossAxisAlignment.,
children: <Widget>[
SizedBox(height: 17, width: 1),
SizedBox(
width: mediaQuery.size.width * 0.75,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
SizedBox(
height: 1,
width: 4,
),
typedText
],
),
),
SizedBox(height: 10, width: mediaQuery.size.width * 0.04),
SizedBox(
height: 1,
width: mediaQuery.size.width * 0.75,
child: const Divider(
color: Colors.white54,
thickness: 1,
),
),
],
),
),
),
],
),
);
}
Widget _buildAppBar(String pageTitle, NewTransactions transactions,
GeldKonto kontoss, String choiceId) {
return AppBar(
automaticallyImplyLeading: false,
leading: isIos == true
? IconButton(
icon: Icon(CupertinoIcons.back, size: 30, color: Colors.white),
onPressed: () => Navigator.of(context).pop(context),
)
: IconButton(
icon: Icon(Icons.arrow_back, size: 30, color: Colors.white),
onPressed: () => Navigator.of(context).pop(context),
),
centerTitle: true,
title: Text(
pageTitle,
style: const TextStyle(
fontSize: 25,
color: Colors.white,
fontWeight: FontWeight.w400,
),
textAlign: TextAlign.end,
),
actions: <Widget>[
Consumer<IconAuswahl>(
builder: (ctx, iconData, child) => IconButton(
padding: EdgeInsetsDirectional.only(
start: 15,
end: 25,
top: 5,
bottom: 0,
),
icon: Icon(
MyIcon.correct,
size: 45,
color: _correct,
),
onPressed: () =>
_submitData(choiceId, transactions, iconData, kontoss),
),
),
],
backgroundColor: Color(0xffb00374a),
);
}
Widget _buildColumn(
BuildContext context, AppBar appBar, local, String choiceId) {
final mediaQuery = MediaQuery.of(context);
return Stack(children: <Widget>[
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: [Colors.black, Color(0xffb00374a)],
),
),
),
Positioned(
bottom: 0,
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * 0.08,
color: Colors.grey),
),
SingleChildScrollView(
child: Container(
height: (mediaQuery.size.height -
appBar.preferredSize.height -
mediaQuery.padding.top ) * 1.05 ,
padding: EdgeInsets.only(
top: 10,
left: 20,
right: 10,
bottom:0,
//
// so that the whole thing always move +10
),
child: Consumer<SinlgeOrMultiple>(
builder: (_, data, __) => data.multipleAcc == true
? Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
// CupertinoTextField(
// ),
_buildTransactionRow(
comparisonStuff: _selectedDate,
typedText: Text(
_selectedDate == null
? 'Bankkonto'
: 'Mein Ausgewähltes Zeug',
style: Theme.of(context).textTheme.title),
icon: const Icon(MyIcon.account, size: 38),
iconSpace: 3,
iconAfterSpace: 20,
onPress: () {}),
Row(children: <Widget>[
SizedBox(width: 3.5),
choiceId == '0'
? const Icon(
MyIcon.paying,
color: Colors.white,
size: 25,
)
: const Icon(
MyIcon.earning,
color: Colors.white,
size: 43,
),
const SizedBox(width: 33),
SelectTransactionItem(
choiceId == '0' //id of new outcome
? '-${oCcyy.format(0)}'
: '${oCcyy.format(0)}',
_amountController,
false,
_colorCorrect),
]),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
IconPicked(_scaffoldKey, choiceId),
const SizedBox(
width:
14),
SelectTransactionItem(
'Titel',
_titleController,
true,
_colorCorrect),
],
),
_buildTransactionRow(
comparisonStuff: _selectedDate,
typedText: Text(
_selectedDate == null
? 'Jede 2 Woche'
: 'Ausgewählter Stuff',
style: Theme.of(context).textTheme.title),
icon: const Icon(MyIcon.runningtime, size: 40),
iconSpace: 0,
iconAfterSpace: 20,
onPress: () {}),
_buildTransactionRow(
comparisonStuff: _selectedDate,
typedText: Text(
_selectedDate == null
? '${DateFormat.yMd(local).format(DateTime.now())}'
: '${DateFormat.yMMMd().format(_selectedDate)}',
style: Theme.of(context).textTheme.title),
icon: const Icon(MyIcon.calender, size: 39),
iconSpace: 3,
iconAfterSpace: 18,
onPress: () {
showModalBottomSheet(
context: context,
builder: (BuildContext builder) {
return SizedBox(
height: MediaQuery.of(context)
.copyWith()
.size
.height /
3,
child: CupertinoDatePicker(
//backgroundColor: Color(0xffb00374a),
initialDateTime: DateTime.now(),
onDateTimeChanged:
(DateTime pickedDate) {
if (pickedDate == null) {
return;
}
setState(() {
_selectedDate = pickedDate;
});
},
// use24hFormat: true,
maximumDate: DateTime.now(),
minimumYear: 2010,
maximumYear: 2020,
//minuteInterval: 1,
mode: CupertinoDatePickerMode.date,
),
);
});
},
),
Row(
children: <Widget>[
const SizedBox(width: 3.5),
const Icon(
MyIcon.notes,
color: Colors.white,
size: 37,
),
const SizedBox(width: 20),
SelectTransactionItem('Notizen', _notesController,
false, _colorCorrect),
],
),
Container(
width: 0.1,
height: MediaQuery.of(context).size.height * 0.08,
color: Colors.transparent),
])
: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Row(children: <Widget>[
const SizedBox(width: 3.5),
choiceId == '0'
? const Icon(
MyIcon.paying,
color: Colors.white,
size: 25,
)
: const Icon(
MyIcon.earning,
color: Colors.white,
size: 43,
),
const SizedBox(width: 33),
SelectTransactionItem(
choiceId == '0' //id of new outcome
? '-${oCcyy.format(0)}'
: '${oCcyy.format(0)}',
_amountController,
false,
_colorCorrect),
]),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
IconPicked(_scaffoldKey, choiceId),
const SizedBox(
width:
14),
SelectTransactionItem(
'Titel',
_titleController,
true,
_colorCorrect),
],
),
_buildTransactionRow(
comparisonStuff: _selectedDate,
typedText: Text(
_selectedDate == null
? 'Jede 2 Woche'
: 'Ausgewählter Stuff',
style: Theme.of(context).textTheme.title),
icon: const Icon(MyIcon.runningtime, size: 40),
iconSpace: 0,
iconAfterSpace: 20,
onPress: () {}),
_buildTransactionRow(
comparisonStuff: _selectedDate,
typedText: Text(
_selectedDate == null
? '${DateFormat.yMd(local).format(DateTime.now())}'
: '${DateFormat.yMMMd().format(_selectedDate)}',
style: Theme.of(context).textTheme.title),
icon: const Icon(MyIcon.calender, size: 39),
iconSpace: 3,
iconAfterSpace: 18,
onPress: () {
showModalBottomSheet(
context: context,
builder: (BuildContext builder) {
return SizedBox(
height: MediaQuery.of(context)
.copyWith()
.size
.height /
3,
child: CupertinoDatePicker(
//backgroundColor: Color(0xffb00374a),
initialDateTime: DateTime.now(),
onDateTimeChanged:
(DateTime pickedDate) {
if (pickedDate == null) {
return;
}
setState(() {
_selectedDate = pickedDate;
});
},
// use24hFormat: true,
maximumDate: DateTime.now(),
minimumYear: 2010,
maximumYear: 2020,
//minuteInterval: 1,
mode: CupertinoDatePickerMode.date,
),
);
});
},
),
Row(
children: <Widget>[
const SizedBox(width: 3.5),
const Icon(
MyIcon.notes,
color: Colors.white,
size: 37,
),
const SizedBox(width: 20),
SelectTransactionItem('Notizen', _notesController,
false, _colorCorrect),
],
),
Container(
width: 0.1,
height: MediaQuery.of(context).size.height * 0.08,
color: Colors.transparent),
])),
),
),
]);
}
#override
Widget build(BuildContext context) {
var local = Localizations.localeOf(context).toString();
final routeArgs =
ModalRoute.of(context).settings.arguments as Map<String, String>;
final _pageTitle = routeArgs['pageTitle'];
final _choiceId = routeArgs['id'];
final transactions = Provider.of<NewTransactions>(context, listen: false);
final kontoss = Provider.of<GeldKonto>(context, listen: false);
final PreferredSizeWidget appBar =
_buildAppBar(_pageTitle, transactions, kontoss, _choiceId);
return
// SafeArea(
// child:
Scaffold(
key: _scaffoldKey,
appBar: appBar,
// body: Stack(
// children: <Widget>[
body: _buildColumn(context, appBar, local, _choiceId),
//),
);
}
}
It is fine when i open the upper textfield but the container overlap when opening the last textfield. I can scroll up to see the notes ,,textfield'', but it looks ugly when I open the notes ,,textfield'' and the thing is overlapping. Is there a way to move the textfield up automatically or just preventing that the Container is pushed up as well?
I tried to put the padding of the textfield column Container to + 10, but it squeezed the whole page.
padding: EdgeInsets.only(
top: 10,
left: 10,
right: 10,
bottom: MediaQuery.of(context).viewInsets.bottom +
10, // so that the whole thing always move +10
),
Do you have any advice to solve the problem?

Try adding resizeToAvoidBottomInset: false to your scaffold

Try wrapping Scaffold widget with a Stack and then put the Container widget after Scaffod

If you need to hide some widgets when keyboard is visible, you can use this package: https://pub.dev/packages/flutter_keyboard_visibility
Example:
KeyboardVisibilityBuilder(builder: (context, isKeyboardVisible) {
return isKeyboardVisible
? const SizedBox()
: const MyButton();
}),
I don't like using resizeToAvoidBottomPadding: false, because, when you have a text field, it doesn't allow to move the text field to the top of keyboard.

Related

_CastError (Null check operator used on a null value) when using get.dart method

import 'package:calendar_app/consts/routes.dart';
import 'package:calendar_app/controller/task_controller.dart';
import 'package:calendar_app/models/task.dart';
import 'package:calendar_app/services/notification_service.dart';
import 'package:calendar_app/widgets/button.dart';
import 'package:calendar_app/widgets/task_tile.dart';
import 'package:date_picker_timeline/date_picker_timeline.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:intl/intl.dart';
import 'dart:developer' as devtools show log;
import 'package:get/get.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
DateTime _selectDate = DateTime.now();
final _taskController = Get.put(TaskController());
var notif;
#override
void initState() {
super.initState();
notif = Notif();
notif.initializeNotification();
notif.requestIOSPermissions();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color.fromARGB(255, 202, 202, 202),
body: Column(
children: [
Container(
margin: const EdgeInsets.fromLTRB(20, 50, 20, 0),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
// Date
DateFormat.yMMMMd().format(DateTime.now()),
style: const TextStyle(
fontSize: 20,
),
),
const SizedBox(
height: 10,
),
const Text(
// Today
'Today',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
),
),
],
),
MyButton(
// Add Task
label: '+ Add Task',
onPressed: () async {
await Navigator.of(context).pushNamed(
addTaskRoute,
// (route) => false,
);
},
),
],
),
const SizedBox(
height: 20,
),
DatePicker(
// Calendar
DateTime.now(),
height: 100,
width: 80,
initialSelectedDate: DateTime.now(),
selectionColor: const Color.fromARGB(255, 12, 103, 179),
selectedTextColor: Colors.white,
dateTextStyle: const TextStyle(
fontSize: 35,
color: Colors.grey,
),
dayTextStyle: const TextStyle(
fontSize: 15,
color: Colors.grey,
),
monthTextStyle: const TextStyle(
fontSize: 15,
color: Colors.grey,
),
onDateChange: (date) {},
),
const SizedBox(
height: 20,
),
],
),
),
_showTasks(),
],
),
);
}
_showTasks() {
return Expanded(
child: Obx(
() {
return ListView.builder(
itemCount: _taskController.taskList.length,
itemBuilder: (_, index) {
devtools.log(_taskController.taskList.length.toString());
return AnimationConfiguration.staggeredList(
position: index,
child: SlideAnimation(
child: FadeInAnimation(
child: Row(
children: [
GestureDetector(
onTap: () {
devtools.log('tapped');
_showBottomSheet(
context,
_taskController.taskList[index],
);
},
child: TaskTile(
_taskController.taskList[index],
),
)
],
),
),
),
);
},
);
},
),
);
}
_showBottomSheet(BuildContext context, Task task) {
Get.bottomSheet(
Container(
padding: const EdgeInsets.only(top: 3),
height: task.isCompleted == 1
? MediaQuery.of(context).size.height * 0.25
: MediaQuery.of(context).size.height * 0.35,
color: Colors.white,
),
);
}
_bottomSheetButton({
required String label,
required Function()? onTap,
required Color color,
bool isClose = false,
required BuildContext context,
}) {
return GestureDetector(
onTap: onTap,
child: Container(
margin: const EdgeInsets.symmetric(vertical: 4),
height: 55,
width: MediaQuery.of(context).size.width * 0.9,
decoration: BoxDecoration(
border: Border.all(
width: 2,
color: isClose == true ? Colors.red : color,
),
borderRadius: BorderRadius.circular(20),
color: isClose == true ? Colors.red : color,
),
),
);
}
}
When I'm clicking on container it throwing an exception saying:
_CastError (Null check operator used on a null value)
I didn't use any null operators in here
Is this a problem with Get.bottomsheet method or what?<br?
Exception showing _showBottomSheet has something wrong I mean null operator or whatever
Can you please help me go through this?
in your method _showBottomSheet, Task is required variable.
_taskController.taskList[index] -> this is probably null, you should debug this.
In your method, you can set Task as optional, like this: Task? task, and call your method like this:
_showBottomSheet(
context,
_taskController.taskList?[index],
);
and then:
_showBottomSheet(BuildContext context, Task? task) {
Get.bottomSheet(
Container(
padding: const EdgeInsets.only(top: 3),
height: task?.isCompleted == 1
? MediaQuery.of(context).size.height * 0.25
: MediaQuery.of(context).size.height * 0.35,
color: Colors.white,
),
);
}

Image should be upload only that column which is clicked not in all and also explode blank image box

The image should be uploaded only to that column which is clicked not in all.
I write a code where I have columns in Gridviw and each column has the property to upload the image. The image will be uploaded on that column which is clicked but in my code when I click any column to upload an image it uploads in all columns. so I want to upload an image on a particular column that I click.
also when I upload an image and add a new column it adds a new box with an image, not blank box.
so please help me to do this.
Here is my code:-
import 'package:flutter/material.dart';
import 'package:/utils/widget_functions.dart';
import 'package:******/custom/BorderIcon.dart';
import 'package:******/screens/Relation.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:image_picker/image_picker.dart';
import 'package:http/http.dart' as http;
import 'dart:io';
class Photos extends StatefulWidget {
var usrid;
Photos({Key? key, #required this.usrid}) : super(key: key);
#override
_Photos createState() => _Photos();
}
class _Photos extends State<Photos>{
PickedFile? _imageFile;
final String uploadUrl = 'https://api.imgur.com/3/upload';
final ImagePicker _picker = ImagePicker();
Future<String?> uploadImage(filepath, url) async {
var request = http.MultipartRequest('POST', Uri.parse(url));
request.files.add(await http.MultipartFile.fromPath('image', filepath));
var res = await request.send();
return res.reasonPhrase;
}
Future<void> retriveLostData() async {
final LostData response = await _picker.getLostData();
if (response.isEmpty) {
return;
}
if (response.file != null) {
setState(() {
_imageFile = response.file;
});
} else {
print('Retrieve error ${response.exception?.code}');
}
}
int counter = 0;
//List<Widget> _list = List<Widget>();
List<Widget> _list = <Widget> [];
List<PickedFile?> _images = [];
#override
void initState() {
for (int i = 0; i < 2; i++) {
Widget child = _newItem(i);
_list.add(child);
};
}
void on_Clicked() {
Widget child = _newItem(counter);
setState(
() => _list.add(child),
);
}
Widget _previewImage(int i) {
final _imageFile = this._imageFile;
if (_imageFile != null) {
return
SizedBox(
//width: 300,
height: 100,
child: Center(child:
ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Image.file(
File(
_imageFile.path,
),
height: 80,
)
),
),
);
} else {
return InkWell(
onTap: () => _pickImage(i),
child: SizedBox(
//width: 300,
height: 100,
child: Center(child:
Icon(
Icons.image,
color: Color(0xffcccccc),
size: 60,
),
),
),
);
}
}
Widget _newItem(int i) {
Key key = new Key('item_${i}');
Column child = Column(
key: key,
children: [
Stack(
children: [
Card(
elevation: 0,
shape: RoundedRectangleBorder(
side: BorderSide(
color: Color(0xffa1a1a1),
),
borderRadius: BorderRadius.all(Radius.circular(12)),
),
child: _previewImage(i),
),
Positioned(
top: 9,
right: 9,
child: InkWell(
onTap: () => _removeItem(i),
child: SvgPicture.asset(
width: 20,
'assets/images/close.svg',
height: 20,
),
),
)
]
),
]
);
counter++;
return child;
}
void _removeItem(int i) {
print("====remove $i");
print('===Removing $i');
setState(() => _list.removeAt(i));
}
void _pickImage( int i ) async {
try {
final pickedFile = await _picker.getImage(source: ImageSource.gallery);
setState(() {
_imageFile = pickedFile;
_images.add(pickedFile);
});
} catch (e) {
//print("Image picker error ${e!}");
print("Image picker error");
}
}
#override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
final ThemeData themeData = Theme.of(context);
final double padding = 25;
final sidePadding = EdgeInsets.symmetric(horizontal: padding);
var regID = widget.usrid;
return Theme(
data: ThemeData().copyWith(
dividerColor: Colors.transparent,
backgroundColor: Colors.transparent
),
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
elevation: 0,
leading: Builder(
builder: (BuildContext context) {
return Padding(padding: EdgeInsets.fromLTRB(15, 0, 0, 0),
child: IconButton(
icon: const Icon(
Icons.arrow_back_ios_outlined,
color: Colors.black,
),
onPressed: () { Navigator.pop(context); },
),
);
},
),
),
backgroundColor: Colors.white,
body: SingleChildScrollView(
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
//colors: const [Color.fromRGBO(132,105,211,1), Color.fromRGBO(93,181,233,1), Color.fromRGBO(86,129,233,1)],
colors: [Colors.white, Colors.white]
),
),
width: size.width,
height: size.height,
child: Stack(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
addVerticalSpace(10),
Padding(
padding: sidePadding,
child: const Text(
'Add Your Photos',
style: TextStyle(
color: Colors.black,
fontSize: 20,
),),
),
addVerticalSpace(30),
Expanded(
child: Padding(
padding: sidePadding,
child: Column(
children: [
Expanded(
child: GridView(
//padding: const EdgeInsets.all(8.0),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 10.0,
mainAxisSpacing: 15,
//childAspectRatio: 2/1,
),
// children: List.generate(_list.length, (index) {
// //generating tiles with people from list
// return _newItem(index);
// },
// ),
children: List.generate(_list.length + 1,
(index) => index == _list.length ?
InkWell(
onTap: () => on_Clicked(),
child: Column(
children: [
Stack(
children: const [
Card(
elevation: 0,
color: Color(0xff8f9df2),
shape: RoundedRectangleBorder(
side: BorderSide(
color: Color(0xff8f9df2),
),
borderRadius: BorderRadius.all(Radius.circular(12)),
),
child: SizedBox(
//width: 300,
height: 100,
child: Center(child:
Icon(
Icons.add,
color: Colors.white,
size: 80.0,
),
),
),
)
]
),
]
),
) :
_newItem(index)),
)
)
],
),
)
),
],
),
],
)
),
),
persistentFooterButtons:[
Padding(
padding: EdgeInsets.fromLTRB(18, 0, 18, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children:[
ElevatedButton.icon( // <-- ElevatedButton
onPressed: () {
Navigator.pop(context);
},
icon: const Icon(
Icons.arrow_back_ios_outlined,
size: 15.0,
color:Colors.white,
),
label: const Text(
'Back',
style: TextStyle(
fontSize: 20,
),
),
style: ElevatedButton.styleFrom(
primary: Color(0xffFDA766),
minimumSize: const Size(100, 49),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0),)
),
),
Directionality(
textDirection: TextDirection.rtl,
child: ElevatedButton.icon( // <-- ElevatedButton
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Relation(usrid:regID)),
);
},
icon: const Icon(
Icons.arrow_back_ios_outlined,
size: 15.0,
color:Colors.white,
),
label: const Text(
'Next',
style: TextStyle(
fontSize: 20,
),
),
style: ElevatedButton.styleFrom(
primary: Color(0xffFDA766),
minimumSize: const Size(100, 49),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0),)
),
),
),
]
),
),
]
),
);
}
}
And here is my output:- this is the output image before image upload
After image upload:- and this image after upload where it uploads all two columns
Please help me with how I solve this.

only when use iphone simulator

I have this error:
The following FileSystemException was thrown resolving an image codec:
Cannot open file, path = '/Users/todo/Library/Developer/CoreSimulator/Devices/82205CEC-3D83-4A29-BF17-01C5B0515F71/data/Containers/Data/Application/035B9913-BEC5-46BA-84A5-8C1FE3C4E671/tmp/image_picker_B8D488A3-2790-4D53-A5D8-52E57E2C4108-76094-000003172DF085D2.jpg' (OS Error: No such file or directory, errno = 2)
When the exception was thrown, this was the stack
only when use iphone simulator while android emulator no problem
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../app/utility.dart';
import '../db/aql_db.dart';
import '../globals.dart';
import '../menu_page.dart';
import '../model/aql_model.dart';
import '../widget/input_text.dart';
import 'dart:io';
import 'package:http/http.dart' as http;
var _current = resultsFld[0];
class AqlPg extends StatefulWidget {
const AqlPg({Key? key}) : super(key: key);
#override
State<AqlPg> createState() => _AqlPgState();
}
class _AqlPgState extends State<AqlPg> {
final List<TextEditingController> _criticalController = [];
final List<TextEditingController> _majorController = [];
final List<TextEditingController> _minorController = [];
final List<TextEditingController> _imgCommintControllers = [];
final _irController = TextEditingController();
bool clickedCentreFAB =
false; //boolean used to handle container animation which expands from the FAB
int selectedIndex =
0; //to handle which item is currently selected in the bottom app bar
//call this method on click of each bottom app bar item to update the screen
void updateTabSelection(int index, String buttonText) {
setState(() {
selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
//
_irController.text = aqltbl.ir ?? '';
String _current = aqltbl.result ?? resultsFld[0];
//
return Scaffold(
body: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
//---- stack for FloatingActionButton
Stack(
children: <Widget>[
//this is the code for the widget container that comes from behind the floating action button (FAB)
Align(
alignment: FractionalOffset.bottomCenter,
child: AnimatedContainer(
child: const Text(
'Hello',
style: TextStyle(fontSize: 18, color: whiteColor),
),
duration: const Duration(milliseconds: 250),
//if clickedCentreFAB == true, the first parameter is used. If it's false, the second.
height: clickedCentreFAB
? MediaQuery.of(context).size.height
: 10.0,
width: clickedCentreFAB
? MediaQuery.of(context).size.height
: 10.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(
clickedCentreFAB ? 0.0 : 300.0),
color: Colors.blue),
),
),
],
),
// --- Top Page Title
const SizedBox(
height: 50,
),
const Center(
child: Text(
'Aql page',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: medBlueColor),
),
),
Text(
'Shipment no:$shipmentId',
style: const TextStyle(color: medBlueColor),
),
//--- input container
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
Container(
height: 270,
width: 300,
margin: const EdgeInsets.only(top: 5),
child: ListView.builder(
itemCount: (aqltbl.aql ?? []).length,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
//here
var _aqlList = aqltbl.aql![index];
//
if (aqltbl.aql!.length > _criticalController.length) {
_criticalController.add(TextEditingController());
_majorController.add(TextEditingController());
_minorController.add(TextEditingController());
}
//
_criticalController[index].text =
_aqlList.critical ?? '';
_majorController[index].text = _aqlList.major ?? '';
_minorController[index].text = _aqlList.minor ?? '';
//
return Column(
children: [
Container(
height: 260,
width: 200,
margin: const EdgeInsets.only(left: 10),
padding: const EdgeInsets.all(10),
// ignore: prefer_const_constructors
decoration: BoxDecoration(
color: lightBlue,
borderRadius: BorderRadius.circular(10),
),
child: Column(
children: [
Text(
(_aqlList.name ?? '').toString(),
style: const TextStyle(
color: medBlueColor,
fontSize: 13,
),
),
// ignore: prefer_const_constructors
MyInputField(
title: 'critical',
hint: 'write critical ',
borderColor: borderColor,
textColor: textColor,
hintColor: hintColor,
controller: _criticalController[index],
onSubmit: (value) {
setState(() {
aqltbl.aql![index].critical = value;
_save();
});
},
),
MyInputField(
title: 'majority',
hint: 'write majority ',
borderColor: borderColor,
textColor: textColor,
hintColor: hintColor,
controller: _majorController[index],
onSubmit: (value) {
setState(() {
aqltbl.aql![index].major = value;
_save();
});
},
),
MyInputField(
title: 'minority',
hint: 'write minority ',
borderColor: borderColor,
textColor: textColor,
hintColor: hintColor,
controller: _minorController[index],
onSubmit: (value) {
setState(() {
aqltbl.aql![index].minor = value;
_save();
});
},
),
],
),
),
],
);
}),
),
Container(
height: 270,
width: 300,
margin: const EdgeInsets.only(right: 10, left: 20),
padding: const EdgeInsets.only(
left: 10, bottom: 3, right: 10, top: 5),
decoration: const BoxDecoration(
color: lightBlue,
),
child: Column(
children: [
const Text(
'Summery results',
style: TextStyle(color: medBlueColor),
),
Container(
margin: const EdgeInsets.only(top: 10, bottom: 5),
alignment: Alignment.centerLeft,
child: const Text(
'Results',
style: TextStyle(color: medBlueColor),
),
),
Container(
padding: const EdgeInsets.only(right: 5, left: 5),
decoration: BoxDecoration(
color: whiteColor,
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: borderColor,
)),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
focusColor: whiteColor,
value: aqltbl.result,
hint: const Text('select result'),
isExpanded: true,
iconSize: 36,
icon: const Icon(Icons.arrow_drop_down),
items: resultsFld.map((res) {
return DropdownMenuItem<String>(
value: res,
child: Text(
res,
style: const TextStyle(
fontFamily: 'tajawal',
fontSize: 15,
color: medBlueColor),
),
);
}).toList(),
onChanged: (val) {
setState(() {
aqltbl.result = val;
});
_save();
},
),
),
),
// aqltbl.result = selRes;
MyInputField(
width: 300,
title: 'information remarks (ir)',
hint: '',
maxLines: 3,
borderColor: borderColor,
textColor: textColor,
hintColor: hintColor,
controller: _irController,
onSubmit: (value) {
aqltbl.ir = value;
_save();
},
),
],
),
),
],
),
),
//Images Container
Container(
height: 400,
padding: const EdgeInsets.all(0),
margin: const EdgeInsets.only(bottom: 10, left: 10),
decoration: const BoxDecoration(color: lightGrey),
child: (aqltbl.images ?? []).isEmpty
? Column(
children: [
Image.asset(
'images/empty-photo.jpg',
height: 300,
),
Container(
margin: const EdgeInsets.only(top: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text('Click'),
Text(
'Camera button',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(' to add new photo'),
],
)),
],
)
: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: (aqltbl.images ?? []).length,
itemBuilder: (context, imgIndex) {
String? _image =
(aqltbl.images ?? [])[imgIndex].name.toString();
inspect('aql image file');
File(_image).exists() == true
? inspect('image exist')
: inspect('not exist: ' + _image);
inspect('_image: ' + _image);
if (aqltbl.images!.length >
_imgCommintControllers.length) {
_imgCommintControllers.add(TextEditingController());
}
_imgCommintControllers[imgIndex].text =
aqltbl.images![imgIndex].imgComment!;
inspect(_imgCommintControllers.length);
return Container(
margin: const EdgeInsets.only(left: 5),
height: 300,
child: Column(
children: [
Stack(
children: [
Image.file(
File(_image),
height: 300,
),
Container(
decoration: const BoxDecoration(
color: medBlueColor,
),
child: IconButton(
onPressed: () {
inspect('clear');
String imgName =
aqltbl.images![imgIndex].name ??
'';
aqltbl.images!.removeAt(imgIndex);
// aqltbl.images!.removeWhere(
// (item) => item.name == imgName);
_imgCommintControllers
.removeAt(imgIndex);
setState(() {});
},
color: whiteColor,
icon: const Icon(Icons.clear)),
)
],
),
MyInputField(
title: 'Write remarks about image',
hint: '',
controller: _imgCommintControllers[imgIndex],
onSubmit: (value) {
aqltbl.images![imgIndex].imgComment = value;
aqltbl.images![imgIndex].name = _image;
_save();
},
),
],
));
}),
),
],
),
),
// --- FloatingActionButton
floatingActionButtonLocation: FloatingActionButtonLocation
.centerDocked, //specify the location of the FAB
floatingActionButton: FloatingActionButton(
backgroundColor: medBlueColor,
onPressed: () {
inspect(aqltbl);
setState(() {
clickedCentreFAB =
!clickedCentreFAB; //to update the animated container
});
},
tooltip: "Centre FAB",
child: Container(
margin: const EdgeInsets.all(15.0),
child: const Icon(Icons.send),
),
elevation: 4.0,
),
// --- bottom action bar
bottomNavigationBar: BottomAppBar(
child: Container(
margin: const EdgeInsets.only(left: 12.0, right: 12.0),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
//to leave space in between the bottom app bar items and below the FAB
IconButton(
//update the bottom app bar view each time an item is clicked
onPressed: () {
// updateTabSelection(0, "Home");
Get.to(const MainMenu());
},
iconSize: 27.0,
icon: Image.asset(
'images/logo.png',
color: medBlueColor,
),
),
const SizedBox(
width: 50.0,
),
IconButton(
onPressed: () async {
// updateTabSelection(2, "Incoming");
await _takeImage('gallery');
},
iconSize: 27.0,
icon: const Icon(
Icons.image_outlined,
color: medBlueColor,
),
),
IconButton(
onPressed: () async {
// updateTabSelection(1, "Outgoing");
await _takeImage('camera');
},
iconSize: 27.0,
icon: const Icon(
Icons.camera_alt,
color: medBlueColor,
),
),
],
),
),
//to add a space between the FAB and BottomAppBar
shape: const CircularNotchedRectangle(),
//color of the BottomAppBar
color: Colors.white,
),
);
}
_save() {
inspect('submit');
saveAql(shipmentId, aqltbl);
box.write('aql'+shipmentId.toString(), aqltbl);
}
_takeImage(method) async {
String _imgPath = await imageFromDevice(method);
if (_imgPath != empty) {
ImagesModel imgMdl = ImagesModel();
imgMdl.name = _imgPath;
imgMdl.imgComment = '';
if (aqltbl.images != null) {
// _saveLocaly(close: 0);
setState(() {
aqltbl.images!.add(imgMdl);
_save();
});
}
}
}
Future _sendAqlToServer() async {
try {
var response = await http.post(urlSendProductPhoto, body: {
'aql': json.encode(aqltbl).toString(),
'id': shipmentId.toString(),
});
if (response.statusCode == 200) {
Get.snackbar('Success', 'Image successfully uploaded');
return response.body;
} else {
Get.snackbar('Fail', 'Image not uploaded');
inspect('Request failed with status: ${response.statusCode}.');
return 'empty';
}
} catch (socketException) {
Get.snackbar('warning', 'Image not uploaded');
return 'empty';
}
}
}
Try following the path that it is saying it cannot find in your computer, I had a similar issue, I tried opening an Iphone 12 instead of an Iphone 13 and it worked out the issue, my problem was I inadvertently deleted a few files I shouldn't have.

Flutter give a Container a dynamic height (ExpansionTile)

I am trying to implement a review page for products.
I trying to show the products images in a expansionTile (see second image).
Under the expansionTile I add my buttons.
My problem:
To show the expansionTile list I must give the container a fix height.
But if I have less images in my list the screen show a white space (second image).
How can I make the container height dynamic to hide the white space?
Here my example:
If I add some pictures my screen looks like this.
How I can hide the white space between list and buttons?
Here my Code:
Container(
height: MediaQuery.of(context).size.height * 0.5,
width: MediaQuery.of(context).size.width * 0.8,
child: ListView(
children: [
ExpansionTile(
title: Text('Pictures'),
onExpansionChanged: (value) {
setState(
() {},
);
},
children: List<Widget>.generate(
_imageList.length,
(index) => ListTile(
title: Text(_imageList[0]
.path
.split('/')
.last
.length >
25
? _imageList[0]
.path
.split('/')
.last
.substring(0, 25) +
'...'
: _imageList[index].path.split('/').last),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
IconButton(
icon: Icon(
Icons.delete_outline,
size: 20.0,
color: _selected![index]
? Colors.red
: Colors.red,
),
onPressed: () {
setState(() {
_selected![index] =
!_selected![index];
_imageList.removeAt(index);
});
},
),
],
),
),
),
),
],
),
)
Here my full code:
class ReviewPage1 extends StatefulWidget {
//passed paramter
final String _productID;
ReviewPage1(this._productID, {Key? key}) : super(key: key);
#override
_ReviewPage1 createState() => _ReviewPage1(_productID);
}
class _ReviewPage1 extends State<ReviewPage1> {
///passed paramter
final String _productID;
_ReviewPage1(this._productID);
//controller
final TextEditingController _controllerReviewTitle = TextEditingController();
final TextEditingController _controllerReviewDescription =
TextEditingController();
//image
List<File> _imageList = [];
var _image;
var imagePicker;
//list tile color
List<bool>? _selected = [];
//stars
var rating = 1;
#override
void initState() {
super.initState();
imagePicker = new ImagePicker();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: customSubAppBar("Create Review", context),
body: SingleChildScrollView(
child: Center(
child: Container(
width: MediaQuery.of(context).size.width * 0.8,
child: Column(
children: [
//size box
customSizedBox(
MediaQuery.of(context).size.height * 0.05,
MediaQuery.of(context).size.width * 0,
null,
),
//text
Row(
children: [
customText(
'Rate your expreince',
Colors.black,
20,
FontWeight.bold,
null,
),
],
),
//size box
customSizedBox(
MediaQuery.of(context).size.height * 0.02,
MediaQuery.of(context).size.width * 0,
null,
),
//stars rating
Row(
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: List.generate(4, (index) {
return GestureDetector(
onTap: () {
setState(() {
// Toggle light when tapped.
print('star at index: ' + index.toString());
rating = index + 1;
});
},
child: Padding(
padding: const EdgeInsets.only(right: 8),
child: Icon(
//index < rating ? Icons.star : Icons.star_border,
Icons.star,
size: 30,
color: index < rating
? Theme.of(context).primaryColor
: Colors.black.withOpacity(0.5),
)));
}),
),
Spacer(),
],
),
//size box
customSizedBox(
MediaQuery.of(context).size.height * 0.08,
MediaQuery.of(context).size.width * 0,
null,
),
//text
Row(
children: [
customText(
'Review Title',
Colors.black,
20,
FontWeight.bold,
null,
),
],
),
//textfield review title
customDefaultTextField(
50,
1,
TextInputType.text,
_controllerReviewTitle,
1,
false,
Colors.black87,
Theme.of(context).primaryColor,
false,
Theme.of(context).primaryColor,
0,
0,
Theme.of(context).primaryColor,
0,
0,
'Title *',
'Enter Your Title',
Colors.black12,
2,
0,
Theme.of(context).primaryColor,
2,
0,
null,
0,
0,
0,
0,
),
//size box
customSizedBox(
MediaQuery.of(context).size.height * 0.08,
MediaQuery.of(context).size.width * 0,
null,
),
//text
Row(
children: [
customText(
'Write Review',
Colors.black,
20,
FontWeight.bold,
null,
),
],
),
//textfield review description
customDefaultTextField(
50,
1,
TextInputType.text,
_controllerReviewDescription,
1,
false,
Colors.black87,
Theme.of(context).primaryColor,
false,
Theme.of(context).primaryColor,
0,
0,
Theme.of(context).primaryColor,
0,
0,
'Write your Expreinces *',
'Enter your Expreinces',
Colors.black12,
2,
0,
Theme.of(context).primaryColor,
2,
0,
null,
0,
0,
0,
0,
),
//size box
customSizedBox(
MediaQuery.of(context).size.height * 0.08,
MediaQuery.of(context).size.width * 0,
null,
),
//text
Row(
children: [
customText(
'Enter your picture',
Colors.black,
20,
FontWeight.bold,
null,
),
],
),
//size box
customSizedBox(
MediaQuery.of(context).size.height * 0.03,
MediaQuery.of(context).size.width * 0,
null,
),
//take image
GestureDetector(
onTap: () async {
var source = ImageSource.camera;
XFile? image = await imagePicker.pickImage(
source: source,
imageQuality: 50,
preferredCameraDevice: CameraDevice.front);
setState(
() {
_image = File(image!.path);
_imageList.add(_image);
_selected!.add(false);
},
);
},
child: Stack(
children: [
//icon
Container(
width: MediaQuery.of(context).size.width * 0.8,
height: MediaQuery.of(context).size.height * 0.1,
decoration: BoxDecoration(
color:
Theme.of(context).primaryColor.withOpacity(0.8),
borderRadius: BorderRadius.all(Radius.circular(8))),
child: Center(
child: customIcon(
Icons.camera_alt_rounded, Colors.black87, 30)),
),
//border
Container(
width: MediaQuery.of(context).size.width * 0.8,
height: MediaQuery.of(context).size.height * 0.1,
child: DashedRect(
color: Colors.black87,
strokeWidth: 2.0,
gap: 10.0,
),
),
],
),
),
//size box
customSizedBox(
MediaQuery.of(context).size.height * 0.03,
MediaQuery.of(context).size.width * 0,
null,
),
//show images
_imageList.length != 0
? //IntrinsicHeight(
Container(
height: MediaQuery.of(context).size.height * 0.5,
width: MediaQuery.of(context).size.width * 0.8,
child: ListView(
children: [
ExpansionTile(
title: Text('Pictures'),
onExpansionChanged: (value) {
setState(
() {},
);
},
children: List<Widget>.generate(
_imageList.length,
(index) => ListTile(
title: Text(_imageList[0]
.path
.split('/')
.last
.length >
25
? _imageList[0]
.path
.split('/')
.last
.substring(0, 25) +
'...'
: _imageList[index].path.split('/').last),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
IconButton(
icon: Icon(
Icons.delete_outline,
size: 20.0,
color: _selected![index]
? Colors.red
: Colors.red,
),
onPressed: () {
setState(() {
_selected![index] =
!_selected![index];
_imageList.removeAt(index);
});
},
),
],
),
),
),
),
],
),
)
//)
: Container(),
//text cancel
Container(
width: MediaQuery.of(context).size.width * 0.8,
child: TextButton(
child: Text(
'Send Review',
style: TextStyle(
color: Colors.white, fontWeight: FontWeight.bold),
),
style: TextButton.styleFrom(
primary: Colors.black,
backgroundColor: Colors.greenAccent[400],
onSurface: Colors.grey,
),
onPressed: () {
if (_checkInputValuesEmpty(
context, _controllerReviewTitle.text, 'title') &&
_checkInputValuesEmpty(
context,
_controllerReviewDescription.text,
'description')) {
final String _userID =
FirebaseAuth.instance.currentUser!.uid;
_uploadFile(_userID, _productID, context, _imageList);
}
},
),
),
//size box
customSizedBox(
MediaQuery.of(context).size.height * 0.01,
MediaQuery.of(context).size.width * 0,
null,
),
//text send review
Container(
width: MediaQuery.of(context).size.width * 0.8,
child: TextButton(
child: Text(
'Cancel',
style: TextStyle(
color: Colors.white, fontWeight: FontWeight.bold),
),
style: TextButton.styleFrom(
primary: Colors.black,
backgroundColor: Color.fromRGBO(170, 170, 170, 1),
onSurface: Colors.grey,
),
onPressed: () async {},
),
),
],
),
),
),
),
//sidebar
drawer: CustomSideBar(context),
);
}
//upload review images
Future _uploadFile(_userID, _productID, context, _imageList) async {
var downloadURLs = [];
for (var image in _imageList) {
String url;
String postId = DateTime.now().millisecondsSinceEpoch.toString();
String fileName = 'reviewImage_${_productID}_${postId}';
Reference ref = FirebaseStorage.instance
.ref()
.child("images/review/review_images/" + _productID + '/' + _userID)
.child(fileName);
await ref.putFile(image);
url = fileName;
downloadURLs.add(url);
}
//upload review data
_addReviewData(_productID, downloadURLs, _userID);
}
//add review data in db
_addReviewData(_productID, downloadURLs, _userID) async {
final String _userID = FirebaseAuth.instance.currentUser!.uid;
FirebaseFirestore.instance
.collection('review')
.doc('productID_' + _productID)
.collection("userID_" + _userID)
.doc('review_data')
.set({
'stars': rating,
'title': _controllerReviewTitle.text,
'description': _controllerReviewDescription.text,
'image_url': downloadURLs,
});
//Navigator.of(context).pushReplacement(
// MaterialPageRoute(builder: (context) => VerifyRegisterEmail()));
}
}
_checkInputValuesEmpty(context, text, field) {
if (text.toString().length == 0) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Enter text in field ${field}'),
));
return false;
} else {
return true;
}
}
Can I give the container a dynamic height which has always the same height how the listview with my image names?
try find this place and add after Colum mainAxisAlignment: MainAxisAlignment.start,
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: customSubAppBar("Create Review", context),
body: SingleChildScrollView(
child: Center(
child: Container(
width: MediaQuery.of(context).size.width * 0.8,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,

how can make listview builder to a reorderable listview in flutter (a priority task app (todo app))

how can i convert listview to reorderedableListview to make a priority task app
this is my application design output
i see many solutions but in most of them i found error
Here is initstate code
class _TodoListScreenState extends State<TodoListScreen> {
late List<Task> taskList = [];
#override
void initState() {
super.initState();
_updateTaskList();
}
_updateTaskList() async {
print('--------->update');
this.taskList = await DatabaseHelper.instance.getTaskList();
print(taskList);
setState(() {});
}
this is method where listtile created
Widget _buildTask(Task task) {
return Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 25.0),
child: ListTile(
title: Text(
task.title!,
style: TextStyle(
fontSize: 18.0,
decoration: task.status == 0
? TextDecoration.none
: TextDecoration.lineThrough,
),
),
subtitle: Text(
'${DateFormat.yMMMEd().format(task.date!)} • ${task.priority}',
style: TextStyle(
fontSize: 18.0,
decoration: task.status == 0
? TextDecoration.none
: TextDecoration.lineThrough,
),
),
trailing: Checkbox(
onChanged: (value) {
task.status = value! ? 1 : 0;
DatabaseHelper.instance.updateTask(task);
_updateTaskList();
},
value: task.status == 1 ? true : false,
activeColor: Theme.of(context).primaryColor,
),
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddTask(
task: task,
updateTaskList: () {
_updateTaskList();
},
),
),
),
),
),
Divider(),
],
);
}
this is method build
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
backgroundColor: Theme.of(context).primaryColor,
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddTask(updateTaskList: _updateTaskList),
),
),
),
in this body tag i want to create reorderable listview
body: ListView.builder(
padding: EdgeInsets.symmetric(vertical: 80.0),
itemCount: taskList.length + 1,
itemBuilder: (BuildContext context, int index) {
if (index == 0) {
return Padding(
padding:
const EdgeInsets.symmetric(horizontal: 40.0, vertical: 20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"My Tasks",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 40.0,
color: Colors.black),
),
SizedBox(height: 15.0),
Text(
'${taskList.length} of ${taskList.where((Task task) => task.status == 1).toList().length} task complete ',
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 20.0,
color: Colors.grey,
),
),
],
),
);
} else {
return _buildTask(taskList[index - 1]);
}
},
),
);
}
}
this is whole code i want to change
There is a widget like ReorderableListView and library like Reorderables are available that you can use.
Updated
Sample Code:
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:reorderables/reorderables.dart';
class ReorderablesImagesPage extends StatefulWidget {
ReorderablesImagesPage({
Key key,
this.title,
#required this.size,
}) : super(key: key);
final String title;
final double size;
#override
State<StatefulWidget> createState() => _ReorderablesImagesPageState();
}
class _ReorderablesImagesPageState extends State<ReorderablesImagesPage> {
List<Widget> _tiles;
int maxImageCount = 30;
double iconSize;
final int itemCount = 3;
final double spacing = 8.0;
final double runSpacing = 8.0;
final double padding = 8.0;
#override
void initState() {
super.initState();
iconSize = ((widget.size - (itemCount - 1) * spacing - 2 * padding) / 3)
.floor()
.toDouble();
_tiles = <Widget>[
Container(
child: Image.network('https://picsum.photos/250?random=1'),
width: iconSize,
height: iconSize,
),
Container(
child: Image.network('https://picsum.photos/250?random=2'),
width: iconSize,
height: iconSize,
),
Container(
child: Image.network('https://picsum.photos/250?random=3'),
width: iconSize,
height: iconSize,
),
Container(
child: Image.network('https://picsum.photos/250?random=4'),
width: iconSize,
height: iconSize,
),
Container(
child: Image.network('https://picsum.photos/250?random=5'),
width: iconSize,
height: iconSize,
),
Container(
child: Image.network('https://picsum.photos/250?random=6'),
width: iconSize,
height: iconSize,
),
Container(
child: Image.network('https://picsum.photos/250?random=7'),
width: iconSize,
height: iconSize,
),
Container(
child: Image.network('https://picsum.photos/250?random=8'),
width: iconSize,
height: iconSize,
),
Container(
child: Image.network('https://picsum.photos/250?random=9'),
width: iconSize,
height: iconSize,
),
];
}
#override
Widget build(BuildContext context) {
void _onReorder(int oldIndex, int newIndex) {
setState(() {
Widget row = _tiles.removeAt(oldIndex);
_tiles.insert(newIndex, row);
});
}
var wrap = ReorderableWrap(
minMainAxisCount: itemCount,
maxMainAxisCount: itemCount,
spacing: spacing,
runSpacing: runSpacing,
padding: EdgeInsets.all(padding),
children: _tiles,
onReorder: _onReorder,
onNoReorder: (int index) {
//this callback is optional
debugPrint(
'${DateTime.now().toString().substring(5, 22)} reorder cancelled. index:$index');
},
onReorderStarted: (int index) {
//this callback is optional
debugPrint(
'${DateTime.now().toString().substring(5, 22)} reorder started: index:$index');
});
var column = Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: SingleChildScrollView(
child: wrap,
),
),
ButtonBar(
buttonPadding: EdgeInsets.all(16),
alignment: MainAxisAlignment.end,
children: <Widget>[
if (_tiles.length > 0)
IconButton(
iconSize: 50,
icon: Icon(Icons.remove_circle),
color: Colors.teal,
padding: const EdgeInsets.all(0.0),
onPressed: () {
setState(() {
_tiles.removeAt(0);
});
},
),
if (_tiles.length < maxImageCount)
IconButton(
iconSize: 50,
icon: Icon(Icons.add_circle),
color: Colors.deepOrange,
padding: const EdgeInsets.all(0.0),
onPressed: () {
var rand = Random();
var newTile = Container(
child: Image.network(
'https://picsum.photos/250?random=${rand.nextInt(100)}'),
width: iconSize,
height: iconSize,
);
setState(() {
_tiles.add(newTile);
});
},
),
],
),
],
);
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: column,
);
}
}