I've implemented a date selection in my flutter app. The selected date then gets displayed, but as soon as the focus changes, the selected DateTime object becomes null without any reason.
To store the DateTime and some other variables I've created an object which is stored as a final variable in the StatefulWidget class. This object also includes Strings which don't change when the DateTime becomes null.
import 'package:flutter/material.dart';
import 'package:smartyne/core/assignment.dart';
class AssignmentPage extends StatefulWidget {
final bool editMode;
final Assignment assignment;
AssignmentPage(this.assignment, this.editMode);
#override
_AssignmentPageState createState() => _AssignmentPageState();
}
class _AssignmentPageState extends State<AssignmentPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
...
body: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
TextField(
decoration: InputDecoration(
border: OutlineInputBorder(), labelText: "Title"),
onChanged: (value) {
widget.assignment.title = value;
setState(() {});
},
),
...
SizedBox(
height: 16.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
MaterialButton(
child: Text(widget.assignment.deadlineAsString),
onPressed: () {
_showDatePicker();
},
),
...
],
)
],
),
));
}
void _showDatePicker() async {
final DateTime newDeadline = await showDatePicker(
context: context,
initialDate: widget.assignment.deadline == null ? DateTime.now() : widget.assignment.deadline,
firstDate: DateTime(1900),
lastDate: DateTime(2099)
);
if (newDeadline != null && newDeadline != widget.assignment.deadline) {
setState(() {
widget.assignment.deadline = newDeadline;
});
}
}
}
As shown above, the DateTime gets selected by a DatePicker and the result is then stored in the assignment object. But when you click on the TextField for the title, it suddenly turns null.
Example gif: https://gph.is/g/aKn7yqq
Use the declared variable inside state class like below
import 'package:flutter/material.dart';
import 'package:smartyne/core/assignment.dart';
class AssignmentPage extends StatefulWidget {
#override
_AssignmentPageState createState() => _AssignmentPageState();
}
class _AssignmentPageState extends State<AssignmentPage> {
final bool editMode;
final Assignment assignment;
#override
Widget build(BuildContext context) {
return new Container();
//access it like
//Text(assignment.deadlineAsString),
//instead of
//Text(widget.assignment.deadlineAsString),
}
Related
I'm trying to get and display 2 variable values from another dart file, ("int myId" and "String myMenu") , these variables are updated with every "onTap" widget, my code works, but only if i do a "hot reload", i think that i need to put a "setstate" somewhere, but i'm having difficulty to implement it.
I think the problem is there, my widget text returns "null" to me, but if I hit the menu button and do a "hot reload", it's ok.
displayText.dart
import 'package:flutter/material.dart';
import './menu.dart';
class display extends StatefulWidget {
int myId;
String myMenu;
display(this.myId, this.myMenu);
#override
_displayState createState() => _displayState();
}
class _displayState extends State<display> {
Future myVarUsed() async {
//Each press on the button return the value
setState(() {
print('myIdDsiplay: ${widget.myId}'); // null
print('myMenuDisplay : ${widget.myMenu}'); // null
});
}
#override
void initState() {
super.initState();
myVarUsed();
}
#override
Widget build(BuildContext context) {
return Container(
color: Colors.blue,
height: 250,
width: 250,
child: Row(
children: [
Text('My ID is : ${widget.myId}'),
Text('My menu is : ${widget.myMenu}'),
],
),
);
}
}
This file contains the menu inside a scrollbar, each button return the ID and the name (of the button) and store it in 2 variable ("int myId" and "String myMenu") that i want to pass.
menu.dart
import 'package:flutter/material.dart';
import './mylist.dart';
import './displayText.dart';
class Menu extends StatefulWidget {
static int myId;
static String myMenu;
#override
_MenuState createState() => _MenuState();
}
class _MenuState extends State<Menu> {
Container scrollList() {
final PageController controller = PageController(initialPage: 1, keepPage: true, viewportFraction: 0.35);
return Container(
color: Colors.red,
height: 90,
child: PageView.builder(
scrollDirection: Axis.horizontal,
controller: controller,
itemCount: listdata.length,
physics: BouncingScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
return Container(
child: gestureDetector_Ontap(index),
);
},
),
);
}
GestureDetector gestureDetector_Ontap(int index) {
return GestureDetector(
onTap: () {
Menu.myId = listdata[index].id;
Menu.myMenu = listdata[index].menuObj;
display(Menu.myId, Menu.myMenu);
print('myIDMenu ${Menu.myId}');
print('myMenuMenu ${Menu.myMenu}');
},
child: Container(
alignment: AlignmentDirectional.center,
child: Text(
'${listdata[index].menuObj}',
),
),
);
}
Widget build(BuildContext context) {
return Container(
child: scrollList(),
);
}
}
This file contains my list and his class
mylist.dart
class listModel {
int id;
String menuObj;
listModel(this.id, this.menuObj);
}
List listdata = [
listModel(0, 'Menu01'),
listModel(1, 'Menu02'),
listModel(2, 'Menu03'),
listModel(3, 'Menu04'),
listModel(4, 'Menu05')
];
And the container
main.dart
import 'package:flutter/material.dart';
import './menu.dart';
import './displayText.dart';
import './mylist.dart';
void main() {
runApp(MyHomePage());
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
child: Column(
children: <Widget>[
Menu(),
display(Menu.myId, Menu.myMenu),
],
),
),
),
);
}
}
The problem
You're defining Menu this way:
class Menu extends StatefulWidget {
static int myId;
static String myMenu;
#override
_MenuState createState() => _MenuState();
}
When your app starts, myId and myMenu are uninitialized variables, therefore they're implicitely set to null.
Inside _MyHomePageState, you call
display(Menu.myId, Menu.myMenu)
Since you haven't initialized Menu.myId and Menu.myMenu yet, they're still null.
When you tap the GestureDetector, you initialize Menu.myId and Menu.myMenu this way:
Menu.myId = listdata[index].id;
Menu.myMenu = listdata[index].menuObj;
display(Menu.myId, Menu.myMenu);
print('myIDMenu ${Menu.myId}');
print('myMenuMenu ${Menu.myMenu}');
Now, Menu.myId and Menu.myMenu are defined to non-null values. However, this will not update the Container's display(Menu.myId, Menu.myMenu), so they'll still be null, you need to update it by yourself.
The solution
I've added comments through the code, pointing a better approach:
import 'package:flutter/material.dart';
// Avoid displaying the warning "Name types using UpperCamelCase."
class Display extends StatefulWidget {
// Make these fields final and the constructor const
final int myId;
final String myMenu;
const Display(this.myId, this.myMenu);
#override
_DisplayState createState() => _DisplayState();
}
// Avoid displaying the warning "Name types using UpperCamelCase."
class _DisplayState extends State<Display> {
// You don't need this Future nor this initState
//
// Future myVarUsed() async {
// setState(() {
// print('myIdDsiplay: ${widget.myId}'); // null
// print('myMenuDisplay : ${widget.myMenu}'); // null
// });
// }
//
// #override
// void initState() {
// super.initState();
// myVarUsed();
// }
#override
Widget build(BuildContext context) {
return Container(
color: Colors.blue,
height: 250,
width: 250,
child: Row(
children: [
Text('My ID is : ${widget.myId}'),
Text('My menu is : ${widget.myMenu}'),
],
),
);
}
}
class Menu extends StatefulWidget {
// Avoid using mutable static fields
// static int myId;
// static String myMenu;
// To simplify, you can add a onChanged callback to
// be triggered whenever you change `myId` and `myMenu`
final void Function(int myId, String myMenu) onChanged;
const Menu({this.onChanged});
#override
_MenuState createState() => _MenuState();
}
class _MenuState extends State<Menu> {
Container scrollList() {
final PageController controller = PageController(initialPage: 1, keepPage: true, viewportFraction: 0.35);
return Container(
color: Colors.red,
height: 90,
child: PageView.builder(
scrollDirection: Axis.horizontal,
controller: controller,
itemCount: listdata.length,
physics: BouncingScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
return Container(
child: gestureDetectorOntap(index),
);
},
),
);
}
// Avoid displaying the warning "Name non-constant identifiers using lowerCamelCase."
GestureDetector gestureDetectorOntap(int index) {
return GestureDetector(
onTap: () {
// Make these local variables
int myId = listdata[index].id;
String myMenu = listdata[index].menuObj;
// Call the `onChanged` callback
widget.onChanged(myId, myMenu);
// This widget is being thrown away
// display(Menu.myId, Menu.myMenu);
print('myIDMenu $myId');
print('myMenuMenu $myMenu');
},
child: Container(
alignment: AlignmentDirectional.center,
child: Text(
'${listdata[index].menuObj}',
),
),
);
}
Widget build(BuildContext context) {
return Container(
child: scrollList(),
);
}
}
// Avoid the warning "Name types using UpperCamelCase."
class ListModel {
// You can make these fields final and the constructor const
final int id;
final String menuObj;
const ListModel(this.id, this.menuObj);
}
// You can make this list const to avoid modifying it unintentionally later
const List<ListModel> listdata = [
ListModel(0, 'Menu01'),
ListModel(1, 'Menu02'),
ListModel(2, 'Menu03'),
ListModel(3, 'Menu04'),
ListModel(4, 'Menu05')
];
void main() {
runApp(MyHomePage());
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// Create fields to store the current `myId` and current `myMenu`
int myId;
String myMenu;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
child: Column(
children: <Widget>[
// Add the `onChanged` callback here, updating this widget state
Menu(
onChanged: (newMyId, newMyMenu) {
setState(() {
myId = newMyId;
myMenu = newMyMenu;
});
}
),
// Access the current values here
Display(myId, myMenu),
],
),
),
),
);
}
}
Im sorry if the title seems off, I couldn't find a better way to frame it. I have a grid of containers on the screen, and I want to be able to draw on the screen selecting and dragging across the screen. I read about the GestureDetector class but it only detects gesture that starts in one widget, I can do a onPanDown, onPanUpdate,onPanEnd but that just gives me the co-ordinates of the cursor, and I didn't feel like it was the most elegant way to do it.(I might be wrong). The Block Class:
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class Block extends StatefulWidget {
#override
_BlockState createState() => _BlockState();
}
class _BlockState extends State<Block> {
Color boxColor = Colors.white;
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
if (boxColor == Colors.blueGrey[900])
boxColor = Colors.white;
else
boxColor = Colors.blueGrey[900];
setState(() {});
},
child: Container(
height: 20,
width: 20,
decoration: BoxDecoration(
color: boxColor,
border: Border.all(
color: Colors.grey,
width: 1,
)),
),
);
}
}
PathFinding Class: (Painting the blocks in a grid):
import 'package:flutter/material.dart';
import 'Block.dart';
class PathFinding extends StatefulWidget {
#override
_PathFindingState createState() => _PathFindingState();
}
class _PathFindingState extends State<PathFinding> {
#override
Widget build(BuildContext context) {
List<List<Widget>> grid = [
...List.generate(
40, (index) => [...List.generate(40, (index) => Block())])
];
return Scaffold(
body: Column(
// crossAxisAlignment: CrossAxisAlignment.center,
children: [
...grid.map((e) => Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [...e],
))
],
),
);
}
}
Just pass a callback as a parameter from your _PathFindingState, whenevr you are creating a Block.
First, add 2 extra params to your Block that can be passed while creating it.
class Block extends StatefulWidget {
final void onTap; // The function from the parent to be called
final int id; // An id that is unique to this Block
Block({ this.onTap, this.id });
#override
_BlockState createState() => _BlockState();
}
Then, in your _BlockState, whenever a tap is detected, call the new function to inform the Block class, which will then inform the _PathFindingState class.
InkWell(
onTap: () {
if (boxColor == Colors.blueGrey[900])
boxColor = Colors.white;
else
boxColor = Colors.blueGrey[900];
setState(() {});
widget.onTap(widget.id); // This line will call the `onTap` function that is present in the `Block`
},
Finally, in your _PathFindingState,
class _PathFindingState extends State<PathFinding> {
void onTap (int id) {
// A Block with `id` = id has been tapped,
}
#override
Widget build(BuildContext context) {
List<List<Widget>> grid = [
...List.generate(
40, (index) => [...List.generate(40,
(index) => Block(id: index, onTap: onTap) // Pass index as id and the onTap function
)])
];
This architecture can be followed for any Gesture that has been detected on any Block and you will receive the callback in the _PathFindingState class and you can do whatever you want with it.
how can i set the value of a TextFormField from a widget variable when this variable changed according to a setstate action after building the widget and not by the initial value of this textformfeild
what i know that i can change its value by using the TextEditingController but i have too many TextFormField and creating the TextEditingController take a lot of code by using the traditional way by adding them the whole widget:
1-Create a TextEditingController.
2-Connect the TextEditingController to a text field.
3-Create a function to update the latest value.
4-Listen to the controller for changes.
is there any way to build this controller and do those steps inside the code of the TextFormField only? or another way ?
place controler in
TextFormField(
controller: TextEditingController(text: daytask),....
then place setstate() txt=''; like this
setState(() { txt='' }
Best way to do this is to simply make a widget. For this one, here is the code that i would use
class StateTextField extends StatelessWidget {
final String text;
const StateTextField({Key key, this.text = ''}) : super(key: key);
#override
Widget build(BuildContext context) {
return TextField(
controller: TextEditingController(text: text),
);
}
}
that should do the work. If u want to pass the controller, u can pass it too. And to use it, just call the class in build method.
Similar example with TextFormField, TextEditingController, clickable suffixIcon for a selectDate showDatePicker (this is a standard material "lambda" dialog) where setState is updating the initial set date (not by the initialValue, rather by the controller parameter) with a new date.
import 'package:flutter/material.dart';
class CreateOrderForm extends StatefulWidget {
const CreateOrderForm({Key? key}):super(key: key);
#override
CreateOrderFormState createState() => CreateOrderFormState();
}
class CreateOrderFormState extends State<CreateOrderForm>
{
final _formKey = GlobalKey<FormState>();
late DateTime selectedDate;
#override
void initState() {
super.initState();
selectedDate = DateTime.now();
print("initState selectedDate = ${selectedDate.toLocal()}");
}
#override
Widget build(BuildContext context) {
print("build prepare selectedDate: ${selectedDate.toLocal()}");
return Form(
key: _formKey,
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
//initialValue: "${selectedDate.toLocal()}",
controller: TextEditingController(text: "${selectedDate.toLocal()}"),
decoration: InputDecoration(
icon: Icon(Icons.event),
border: OutlineInputBorder(),
labelText: "Assignment Date & Time",
suffixIcon: IconButton(
onPressed: () => _selectDate(context),
icon: Icon(Icons.event))
),
),
const Padding(padding: EdgeInsets.only(top: 8)),
Align(
alignment: Alignment.bottomRight,
child: ElevatedButton(
onPressed: ((){}),
child: Text("Submit")),
)
],
),
),
)
);
}
_selectDate(BuildContext context) async{
await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(1970),
lastDate: DateTime(9999)
).then((value){
if(value != null && value != selectedDate)
{
this.setState(() {
selectedDate = value;
print("New date ${selectedDate.toLocal()}");
});
}
});
}
}
In my app I am generating a ListView and items can be highlighted by tapping on them. That works fine and I also have a callback function that gives me the key for the just selected item. I can currently manually deselect the item by tapping on it again, but will ultimately take that functionality out.
My problem is that I want one and only one item to be selected at a time. In order to create the list I currently take some initial content in the form of a list, generate the tiles and add them to another list. I then use that list to create the ListView. My plan was on the callback from a new selection, run through the list of tiles and deselect them before highlighting the new chosen tile and carrying out the other functions. I have tried various methods to tell each tile to deselect itself but have not found any way to address each of the tiles. Currently I get the error:
Class 'OutlineTile' has no instance method 'deselect'.
Receiver: Instance of 'OutlineTile'
Tried calling: deselect()
I have tried to access a method within the tile class and to use a setter but neither worked so far. I am quite new to flutter so it could be something simple I am missing. My previous experience was with Actionscript where this system would have worked fine and I could access a method of an object (in this case the tile) easily as long s it is a public method.
I'd be happy to have another way to unselect the old item or to find a way to access a method within the tile. The challenge is to make the tiles show not highlighted without them being tapped themselves but when a different tile is tapped.
The code in my parent class is as follows:
class WorkingDraft extends StatefulWidget {
final String startType;
final String name;
final String currentContent;
final String currentID;
final List startContent;
WorkingDraft(
{this.startType,
this.name,
this.currentContent,
this.currentID,
this.startContent});
#override
_WorkingDraftState createState() => _WorkingDraftState();
}
class _WorkingDraftState extends State<WorkingDraft> {
final _formKey = GlobalKey<FormState>();
final myController = TextEditingController();
//String _startType;
String _currentContent = "";
String _name = "Draft";
List _startContent = [];
List _outLineTiles = [];
int _counter = 0;
#override
void dispose() {
// Clean up the controller when the widget is disposed.
myController.dispose();
super.dispose();
}
void initState() {
super.initState();
_currentContent = widget.currentContent;
_name = widget.name;
_startContent = widget.startContent;
_counter = 0;
_startContent.forEach((element) {
_outLineTiles.add(OutlineTile(
key: Key("myKey$_counter"),
outlineName: element[0],
myContent: element[1],
onTileSelected: clearHilights,
));
_counter++;
});
}
dynamic clearHilights(Key myKey) {
_outLineTiles.forEach((element) {
element.deselect(); // this throws an error Class 'OutlineTile' has no instance method 'deselect'.
Key _foundKey = element.key;
print("Element Key $_foundKey");
});
}
.......
and further down within the widget build scaffold:
child: ListView.builder(
itemCount: _startContent.length,
itemBuilder: (context, index) {
return _outLineTiles[index];
},
),
Then the tile class is as follows:
class OutlineTile extends StatefulWidget {
final Key key;
final String outlineName;
final Icon myIcon;
final String myContent;
final Function(Key) onTileSelected;
OutlineTile(
{this.key,
this.outlineName,
this.myIcon,
this.myContent,
this.onTileSelected});
#override
_OutlineTileState createState() => _OutlineTileState();
}
class _OutlineTileState extends State<OutlineTile> {
Color color;
Key _myKey;
#override
void initState() {
super.initState();
color = Colors.transparent;
}
bool _isSelected = false;
set isSelected(bool value) {
_isSelected = value;
print("set is selected to $_isSelected");
}
void changeSelection() {
setState(() {
_myKey = widget.key;
_isSelected = !_isSelected;
if (_isSelected) {
color = Colors.lightBlueAccent;
} else {
color = Colors.transparent;
}
});
}
void deselect() {
setState(() {
isSelected = false;
color = Colors.transparent;
});
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 4.0),
child: Row(
children: [
Card(
elevation: 10,
margin: EdgeInsets.fromLTRB(10.0, 6.0, 5.0, 0.0),
child: SizedBox(
width: 180,
child: Container(
color: color,
child: ListTile(
title: Text(widget.outlineName),
onTap: () {
if (widget.outlineName == "Heading") {
Text("Called Heading");
} else (widget.outlineName == "Paragraph") {
Text("Called Paragraph");
widget.onTileSelected(_myKey);
changeSelection();
},
),
........
Thanks for any help.
Amended Code sample and explanation, that builds to a complete project, from here:
Following the advice from phimath I have created a full buildable sample of the relevant part of my project.
The problem is that the tiles in my listview are more complex with several elements, many of which are buttons in their own right so whilst phimath's solution works for simple text tiles I have not been able to get it working inside my own project. My approach is trying to fundamentally do the same thing as phimath's but when I include these more complex tiles it fails to work.
This sample project is made up of three files. main.dart which simply calls the project and passes in some dummy data in the way my main project does. working_draft.dart which is the core of this issue. And outline_tile.dart which is the object that forms the tiles.
Within working draft I have a function that returns an updated list of the tiles which should show which tile is selected (and later any other changes from the other buttons). This gets called when first going to the screen. When the tile is tapped it uses a callback function to redraw the working_draft class but this seems to not redraw the list as I would expect it to. Any further guidance would be much appreciated.
The classes are:
first class is main.dart:
import 'package:flutter/material.dart';
import 'package:listexp/working_draft.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
home: WorkingDraft(
startType: "Basic",
name: "Draft",
currentID: "anID",
startContent: [
["Heading", "New Heading"],
["Paragraph", "New Text"],
["Image", "placeholder"],
["Signature", "placeholder"]
],
));
}
}
Next file is working_draft.dart:
import 'package:flutter/material.dart';
import 'package:listexp/outline_tile.dart';
class WorkingDraft extends StatefulWidget {
final String startType;
final String name;
final String currentContent;
final String currentID;
final List startContent;
final int selectedIndex;
WorkingDraft(
{this.startType,
this.name,
this.currentContent,
this.currentID,
this.startContent,
this.selectedIndex});
#override
_WorkingDraftState createState() => _WorkingDraftState();
}
class _WorkingDraftState extends State<WorkingDraft> {
int selectedIndex;
String _currentContent = "";
String _name = "Draft";
List _startContent = [];
var _outLineTiles = [];
int _counter = 0;
int _selectedIndex;
bool _isSelected;
dynamic clearHilights(int currentIndex) {
setState(() {
_selectedIndex = currentIndex;
});
}
updatedTiles() {
if (_selectedIndex == null) {
_selectedIndex = 0;
}
_currentContent = widget.currentContent;
_name = widget.name;
_startContent = widget.startContent;
_counter = 0;
_outLineTiles = [];
_startContent.forEach((element) {
_isSelected = _selectedIndex == _counter ? true : false;
_outLineTiles.add(OutlineTile(
key: Key("myKey$_counter"),
outlineName: element[0],
myContent: element[1],
myIndex: _counter,
onTileSelected: clearHilights,
isSelected: _isSelected,
));
_counter++;
});
}
#override
Widget build(BuildContext context) {
updatedTiles();
return Scaffold(
body: Center(
child: Column(children: [
SizedBox(height: 100),
Text("Outline", style: new TextStyle(fontSize: 15)),
Container(
height: 215,
width: 300,
decoration: BoxDecoration(
border: Border.all(
color: Colors.lightGreenAccent,
width: 2,
),
borderRadius: BorderRadius.circular(2),
),
child: ListView.builder(
itemCount: _startContent.length,
itemBuilder: (context, index) {
return _outLineTiles[index];
},
),
),
]),
));
}
}
and finally is outline_tile.dart
import 'package:flutter/material.dart';
class OutlineTile extends StatefulWidget {
final Key key;
final String outlineName;
final Icon myIcon;
final String myContent;
final int myIndex;
final Function(int) onTileSelected;
final bool isSelected;
OutlineTile(
{this.key,
this.outlineName,
this.myIcon,
this.myContent,
this.myIndex,
this.onTileSelected,
this.isSelected});
#override
_OutlineTileState createState() => _OutlineTileState();
}
class _OutlineTileState extends State<OutlineTile> {
Color color;
// Key _myKey;
bool _isSelected;
#override
void initState() {
super.initState();
_isSelected = widget.isSelected;
if (_isSelected == true) {
color = Colors.lightBlueAccent;
} else {
color = Colors.transparent;
}
}
void deselect() {
setState(() {
_isSelected = widget.isSelected;
if (_isSelected == true) {
color = Colors.lightBlueAccent;
} else {
color = Colors.transparent;
}
});
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 4.0),
child: Row(
children: [
Card(
elevation: 10,
margin: EdgeInsets.fromLTRB(10.0, 6.0, 5.0, 0.0),
child: SizedBox(
width: 180,
child: Container(
color: color,
child: ListTile(
title: Text(widget.outlineName),
onTap: () {
if (widget.outlineName == "Heading") {
Text("Called Heading");
} else if (widget.outlineName == "Paragraph") {
Text("Called Paragraph");
} else if (widget.outlineName == "Signature") {
Text("Called Signature");
} else {
Text("Called Image");
}
var _myIndex = widget.myIndex;
widget.onTileSelected(_myIndex);
deselect();
},
),
),
),
),
SizedBox(
height: 60,
child: Column(
children: [
SizedBox(
height: 20,
child: IconButton(
iconSize: 30,
icon: Icon(Icons.arrow_drop_up),
onPressed: () {
print("Move Up");
}),
),
SizedBox(height: 5),
SizedBox(
height: 20,
child: IconButton(
iconSize: 30,
icon: Icon(Icons.arrow_drop_down),
onPressed: () {
print("Move Down");
}),
),
],
),
),
SizedBox(
height: 60,
child: Column(
children: [
SizedBox(
height: 20,
child: IconButton(
iconSize: 20,
icon: Icon(Icons.add_box),
onPressed: () {
print("Add another");
}),
),
SizedBox(
height: 10,
),
SizedBox(
height: 20,
child: IconButton(
iconSize: 20,
icon: Icon(Icons.delete),
onPressed: () {
print("Delete");
}),
),
],
),
),
],
),
);
}
}
Thanks again
Instead of manually deselecting tiles, just keep track of which tile is currently selected.
I've made a simple example for you. When we click a tile, we just set the selected index to the index we clicked, and each tile looks at that to see if its the currently selected tile.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(body: Home()),
);
}
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int selectedIndex;
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: 10,
itemBuilder: (context, index) {
return ListTile(
title: Text('Item: $index'),
tileColor: selectedIndex == index ? Colors.blue : null,
onTap: () {
setState(() {
selectedIndex = index;
});
},
);
},
);
}
}
I've created a form that allows me to update my database. However, if updateAddCash is pressed when the form is blank it updates the database to "" as well.
import 'package:flutter/material.dart';
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
TextEditingController updateNameController;
String _displayValue = "";
// TextEditingController updateAmountController;
Future<List<AddCash>> future;
#override
initState() {
super.initState();
updateNameController = TextEditingController();
future = RepositoryServiceAddCash.getAllAddCash();
}
void dispose() {
updateNameController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
//Text Field to update data
TextField(
controller: updateNameController,
decoration: InputDecoration(
border: InputBorder.none,
hintText: '${addCash.name}',
),
),
RaisedButton(
child: Text("Update"),
onPressed: () {
Navigator.pop(context);
return updateAddCash(addCash);
},
//Shows data from Database
Text(
'${addCash.name}',
),
),
],
),
);
}
updateAddCash(AddCash addCash) async {
String name = updateNameController.text;
addCash.name = name;
await RepositoryServiceAddCash.updateAddCash(addCash);
setState(() {
_displayValue = name;
future = RepositoryServiceAddCash.getAllAddCash();
});
if (_displayValue.isEmpty) {
//KEEP OLD VALUE
addCash.name
} else {
//ADD NEW VALUE
}
}
}
How would I keep the original value if the form is blank?
using future in the initState add a getter function and fetch all the you need and save it in a variable then if textfield1 is empty then pass the value from the getter as your textfield's value