I am trying to toggle selected in a list of ListTile in a Drawer?
ListTile(
title: Text("Name"),
leading: Icon(Icons.dashboard),
onTap: () {
currentSelected.selected = false
this.selected = true;
currentSelected = this; // << How to get the instance of ListTile
},
),
this points to the widget that contains the code in your question.
You can create a variable where you assign the ListTile, then you can reference it in onTap.
ListTile listTile;
listTile = ListTile(
title: Text("Name"),
leading: Icon(Icons.dashboard),
onTap: () {
currentSelected.selected = false
this.selected = true;
currentSelected = listTile
},
),
return listTile;
It would be better to use a value to store the selected item, like an itemId, instead of a widget reference.
Related
I'm new to Flutter and I have to make a list of rules where every item in the list is green and if you break a rule you can press it and change the color to red. I also have to have extensible.
I also have to have extensible. In my implementation from the YouTube tutorial, I saw that I used .map() to map the items in the list, but now when I have to press and change the color, all items change, not just one.
Any ideas how to fix this?
class _MyHomePageState extends State<MyHomePage> {
bool isSelected = true;
static const lawText =
' example text of the laws that are going to be implemented inside here. This is only to fill out the space at the moment';
final List<Item> items = [
Item(header: 'Law 1 ' , body: lawText),
Item(header: 'Law 2 ' , body: lawText),
Item(header: 'Law 3 ' , body: lawText),
Item(header: 'Law 4 ' , body: lawText),
Item(header: 'Law 5 ' , body: lawText),
];
#override
Widget build(BuildContext context) => Scaffold(
drawer: NavBar(),
appBar: AppBar(
title: Text('ยง Regel'),
centerTitle: true,
),
body: SingleChildScrollView(
//crossAxisAlignment : crossAxisAlignment,
child:ExpansionPanelList(
expansionCallback: (index, isExpanded) {
setState(() => items[index].isExpanded = !isExpanded);
},
children: items
.map((item) => ExpansionPanel(
isExpanded: item.isExpanded,
headerBuilder:(context, isExpanded) => ListTile(
tileColor: isSelected ? Colors.green : Colors.red,
onTap: () => setState(() => isSelected = !isSelected),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
title:Text(
item.header,
style: TextStyle(fontSize: 20),
),
),
body: ListTile(
title: Text(item.body, style: TextStyle(fontSize: 20) ),
//tileColor: Colors.lightGreen,
//onTap: () => setState(() => isSelected = !isSelected),
),
))
.toList(),
),
),
);
}
class Item {
final String header;
final String body;
bool isExpanded;
Item({
required this.header,
required this.body,
this.isExpanded = false,
});
}
I try to do everything with ListTile instead of normal list.
I also tried using elementAt(index) but it didn't work.
try this:
change this
tileColor: isSelected ? Colors.green : Colors.red,
to this:
tileColor: item.isExpanded ? Colors.green : Colors.red,
you have to use bool condition from parent panel
No matter which tile you click, the isSelected will be changed, and every tile will recognize the change since the isSelected condition determines which color you would like to display.
So, You have to change the type of your isSelected from bool to String
, which when you tap it, you can set the isSelected to the label, in this way, flutter will know which tile you want to change.
String selected = '';
in your tile property
tileColor: selected == items[index].header ? Colors.green : Colors.red,
onTap: () => setState(() => selected = items[index].header),
However, for the best practice, either you can set a new field id for the Item class, or you can use asMap() to declare the indexes. Because sometimes, the headers could be same.
The data unLockCard is properly created in the main class where the button is placed.
When I moved the button to a dialog in a different class - the unLockCard is lost. I receive the error message
What is the best way to pass on unLockCard[number] = tarots[0]; into a different widget or class.
Homepage
List<bool> flips = [false, false, false, false];
List tarots = [];
List unLockCard = [];
Widget _buildTarotCard(key, number, title) {
return Column(
children: [
FlipCard(
key: key,
flipOnTouch: true,
front: GestureDetector(
onTap: () {
tarots.shuffle();
key.currentState.toggleCard();
setState(() {
flips[number] = true;
});
unLockCard[number] = tarots[0];
tarots.removeAt(0);
},
Dialog
Widget _showDialog(BuildContext context) {
Future.delayed(Duration.zero, () => showAlert(context));
return Container(
color: Color(0xFF2C3D50),
);
}
void showAlert(BuildContext context) {
List unLockCard = [];
Dialogs.materialDialog(
color: colorTitle,
msg: 'Congratulations, you won 500 points',
msgStyle: TextStyle(color: Colors.white),
title: 'Congratulations',
titleStyle: TextStyle(color: Colors.white),
lottieBuilder: Lottie.asset('assets/lottie/spirituality.json',
fit: BoxFit.contain,
),
dialogWidth: kIsWeb ? 0.3 : null,
context: context,
actions: [
NeumorphicButton(
onPressed: () => Get.toNamed(Routes.DETAILS,
arguments: unLockCard.sublist(0, 4)),
margin: EdgeInsets.symmetric(horizontal: 8.0),
The code is a bit cluttered. You are building a new List unLockCard = []; in the showAlert() method even though you have one already in the HomePage. I suggest you create a CardController class that deals with everything card related and use it in all the views you need. One very elegant way I found is by using the GetX library (https://github.com/jonataslaw/getx). You can declutter your code using a GetView and a GetController (https://github.com/jonataslaw/getx#getview). However, if you don't want to add a new library to your project, you can achieve the same results by having a single point that deals with card actions (i.e. holds a single instance of the unlockCard list and updates it accordingly).
I am working on a flutter project and I want to popup to get generated on clicking a particular tile. This is my code
This is my ListTile generator
Future<Widget> getRecordView() {
print("405 name " + name.toString());
print(nameArr);
var items = List<Record>.generate(int.parse(widget.vcont), (index) => Record(
name: nameArr[index],
type: typeArr[index],
address: addressArr[index],
state: stateArr[index],
phone:phoneArr[index],
city: cityArr[index],
id: idArr[index],
));
print("Started");
var listItems = items;
var listview = ListView.builder(
itemCount: int.parse(widget.vcont),
itemBuilder: (context,index){
return listItems[index] ;
}
);
return Future.value(listview);
}
The Popup I need on tap :
Future <bool> details(BuildContext context,String type) {
return Alert(
context: context,
type: AlertType.success,
title: "Submission",
desc: type, //The parameter
buttons: [
DialogButton(
child: Text(
"OKAY",
style: TextStyle(color: Colors.white, fontSize: 20),
),
onPressed: () => Navigator.pop(context),
color: Color.fromRGBO(0, 179, 134, 1.0),
radius: BorderRadius.circular(0.0),
),
],
).show();
}
I tried to wrap Record with GestureDetector and Inkwell, but I only got errors and Android Studio tells me that Record is not expected in that context. I looked up in the internet and couldnt find anything on this matter. Please help.
Record, as far I can see is just a model, and not a widget. Item Builder requires a widget. You should wrap what you are passing to the item builder with an actual widget like a Container(), ListTile(), .. etc. These widgets can be wrapped with Gesture Detector to perform the pop ups you want.
It would look like this
var listview = ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
// Tap on an item in the list and this will get executed.
},
// Return an actual widget, I'm using a ListTile here, but you can
// use any other type of widget here or a create custom widget.
child: ListTile(
// this will display the record names as list tiles.
title: Text(items[index].name),
),
);
},
);
I want to create a list of widgets(TextFormField) in which I can add a new element with button Add, and remove any element with the button next to that element. So I would have unknown number of TextFormFields in array and would be able to add a new one, and destroy any one TextFormField.
I was able to make adding of new TextFormFields but removing only works if I want to remove last one.
Is there any way to determine the index of removeButton that was clicked?
List<Widget> proba = new List<Widget>();
List<TextEditingController> _controllers = new List<TextEditingController>();
...
IconButton(
icon: Icon(Icons.add_circle_outline),
onPressed: () {
setState(() {
_controllers.add(new TextEditingController());
});
setState(() {
proba.add(Row(
children: [
Icon(Icons.radio_button_unchecked),
Expanded(
child: TextFormField(
controller: _controllers[_controllers.length - 1],
decoration:
InputDecoration(hintText: "Add text..."),
),
),
IconButton(
icon: Icon(Icons.delete),
onPressed: () {
setState(() {
_controllers.removeAt(_controllers.length - 1);
proba.removeAt(proba.length - 1);
});
},
)
],
));
});
},
),
Adding works fine. The code removes last element but I would like to remove the element whose button was clicked.
I think you could use a ListView (for example with the builder constructor), so that each Row is a ListTile. The itemBuilder builds the item and you have access to the index. It would look something like this:
int itemCount = 3;
ListView.builder(
itemCount: _counter,
itemBuilder: (context, index) {
return ListTile(
leading: Icon(Icons.radio_button_unchecked),
title: TextFormField(),
trailing: IconButton(
onPressed: () {
setState(() {
_counter--;
});
},
icon: Icon(Icons.delete),
),
);
},
),
In the setState Method in the onPressed property you have access to the index. In the example the ListView takes care to create the ListTiles based on the itemCount. You might want to create a list of objects instead of just the int itemCount to store data (maybe the text in the TextFormField). But you can still delete the item based on the index from the itemBuilder: values.deleteAt(index).
Have a look at the docs for the ListView and the ListTile classes:
https://api.flutter.dev/flutter/widgets/ListView-class.html
https://api.flutter.dev/flutter/material/ListTile-class.html
there's no named parameters to configure a single tap to trigger Tooltip,
my feeling about the default longPress interaction is that users cannot find this deep-buried function.
I tried to find some hint in tooltip source code but failed.
Tooltip(
message: 'this is something',
child: SizedBox(...),
)
First, define globalkey: GlobalKey _toolTipKey = GlobalKey();
Then wrap your tooltip:
GestureDetector(
onTap: () {
final dynamic _toolTip = _toolTipKey.currentState;
_toolTip.ensureTooltipVisible();
},
child: Tooltip(
key: _toolTipKey,
message: "Your message",
child: Icon(
Icons.info,
),
),
),
Easiest way is to use:
triggerMode: TooltipTriggerMode.tap
Here's an example:
Tooltip(
triggerMode: TooltipTriggerMode.tap,
message: 'this is something',
child: SizedBox(...),
)
The easiest way to get a functionality you need is to clone the original Tooltip widget (call it e.g. TooltipCustom) and change inner GestureDetector behavior.
Particularly replace onLongPress to onTap:
class TooltipCustom extends StatefulWidget {
/// Creates a tooltip.
...
#override
Widget build(BuildContext context) {
...
Widget result = GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: _handleLongPress,
excludeFromSemantics: true,
child: Semantics(
label: excludeFromSemantics ? null : widget.message,
child: widget.child,
),
);
...
return result;
}
}
P.S. It's possible to lose a tooltip hiding feature. Take a look at _handlePointerEvent(PointerEvent event) handler function and realize a proper call of _hideTooltip() method.