Related
I wrote the code to get data from List to chips and when click chips the colour changed to blue. But I want to fetch data from firestore instead "words list".
Instead this words list ...
Database collection image
I want to display "WordName" field in the chips.
My code..
class uitry extends StatefulWidget {
const uitry({Key? key}) : super(key: key);
#override
State<uitry> createState() => _uitryState();
}
class _uitryState extends State<uitry> {
List<String> wordList = [
'Shopping',
'Brunch',
'Music',
'Road Trips',
'Tea',
'Trivia',
'Comedy',
'Clubbing',
'Drinking',
'Wine',
];
List<String> selectedWord = [];
List<String>? deSelectedWord = [];
#override
Widget build(BuildContext context) {
double height = MediaQuery.of(context).size.height;
double width = MediaQuery.of(context).size.width;
return Scaffold(
body: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage(Config.app_background4), fit: BoxFit.fill),
),
child: SafeArea(
child: Center(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 14, right: 0),
child: Column(
children: [
SizedBox(
width: width * 0.94,
height: height * 0.30,
child: Column(
children: <Widget>[
const SizedBox(height: 16),
Wrap(
children: wordList.map(
(word) {
bool isSelected = false;
if (selectedWord!.contains(word)) {
isSelected = true;
}
return GestureDetector(
onTap: () {
if (!selectedWord!.contains(word)) {
if (selectedWord!.length < 50) {
selectedWord!.add(word);
deSelectedWord!.removeWhere(
(element) => element == word);
setState(() {});
print(selectedWord);
}
} else {
selectedWord!.removeWhere(
(element) => element == word);
deSelectedWord!.add(word);
setState(() {
// selectedHobby.remove(hobby);
});
print(selectedWord);
print(deSelectedWord);
}
},
child: Container(
margin: const EdgeInsets.symmetric(
horizontal: 5, vertical: 4),
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 5, horizontal: 12),
decoration: BoxDecoration(
color: isSelected
? HexColor('#0000FF')
: HexColor('#D9D9D9'),
borderRadius: BorderRadius.circular(18),
border: Border.all(
color: isSelected
? HexColor('#0000FF')
: HexColor('#D9D9D9'),
width: 2)),
child: Text(
word,
style: TextStyle(
color: isSelected
? Colors.black
: Colors.black,
fontSize: 14,
fontWeight: FontWeight.w600),
),
),
),
);
},
).toList(),
),
],
),
),
],
),
),
],
))),
),
);
}
}
How get that from firestore? I hope You can understand what I ask. Thank you!
I would do the following:
Initialize your list of words to an empty list
Use the initState method of the stateful widget to make a call to firestore to fetch all the documents that have the wordName property and get the word from the result and set it to a new list
Assign the new list to the wordList property and setState to re-render.
This would be it to get the words and set the chips with fetched words.
Keep in mind that since you are making an async call to firestore you should show some form of loading to tell the user you are fetching the data otherwise you would show and empty chip list until you fetch the data.
I have implemented https://pub.dev/packages/alphabet_scroll_view in my project, I edited it for my own customization but when I scroll list with items scroll with letters is not changing.
https://imgur.com/a/ResAVrE here is a video to better understand what I want to achieve. That changes on selected letter is just my tap on them.
Here is other link if above is not working https://drive.google.com/file/d/1Oy6XWalXwXM-yqk7IZU0Av2_jEL3ZNk1/view?usp=sharing. I hope this will working.
I want to change selected letter dynamically when I am scrolling items.
Here is my code:
import 'package:alphabet_scroll_view/src/meta.dart';
import 'package:collection/collection.dart' show IterableExtension;
import 'package:flutter/material.dart';
enum LetterAlignment { left, right }
class AlphabetScrollView extends StatefulWidget {
AlphabetScrollView(
{Key? key,
required this.list,
this.alignment = LetterAlignment.right,
this.isAlphabetsFiltered = true,
this.overlayWidget,
required this.selectedTextStyle,
required this.unselectedTextStyle,
this.itemExtent = 40,
required this.itemBuilder})
: super(key: key);
/// List of Items should be non Empty
/// and you must map your
/// ```
/// List<T> to List<AlphaModel>
/// e.g
/// List<UserModel> _list;
/// _list.map((user)=>AlphaModel(user.name)).toList();
/// ```
/// where each item of this ```list``` will be mapped to
/// each widget returned by ItemBuilder to uniquely identify
/// that widget.
final List<AlphaModel> list;
/// ```itemExtent``` specifies the max height of the widget returned by
/// itemBuilder if not specified defaults to 40.0
final double itemExtent;
/// Alignment for the Alphabet List
/// can be aligned on either left/right side
/// of the screen
final LetterAlignment alignment;
/// defaults to ```true```
/// if specified as ```false```
/// all alphabets will be shown regardless of
/// whether the item in the [list] exists starting with
/// that alphabet.
final bool isAlphabetsFiltered;
/// Widget to show beside the selected alphabet
/// if not specified it will be hidden.
/// ```
/// overlayWidget:(value)=>
/// Container(
/// height: 50,
/// width: 50,
/// alignment: Alignment.center,
/// color: Theme.of(context).primaryColor,
/// child: Text(
/// '$value'.toUpperCase(),
/// style: TextStyle(fontSize: 20, color: Colors.white),
/// ),
/// )
/// ```
final Widget Function(String)? overlayWidget;
/// Text styling for the selected alphabet by which
/// we can customize the font color, weight, size etc.
/// ```
/// selectedTextStyle:
/// TextStyle(
/// fontWeight: FontWeight.bold,
/// color: Colors.black,
/// fontSize: 20
/// )
/// ```
final TextStyle selectedTextStyle;
/// Text styling for the unselected alphabet by which
/// we can customize the font color, weight, size etc.
/// ```
/// unselectedTextStyle:
/// TextStyle(
/// fontWeight: FontWeight.normal,
/// color: Colors.grey,
/// fontSize: 18
/// )
/// ```
final TextStyle unselectedTextStyle;
/// The itemBuilder must return a non-null widget and the third paramter id specifies
/// the string mapped to this widget from the ```[list]``` passed.
Widget Function(BuildContext, int, String) itemBuilder;
#override
_AlphabetScrollViewState createState() => _AlphabetScrollViewState();
}
class _AlphabetScrollViewState extends State<AlphabetScrollView> {
void init() {
widget.list
.sort((x, y) => x.key.toLowerCase().compareTo(y.key.toLowerCase()));
_list = widget.list;
setState(() {});
/// filter Out AlphabetList
if (widget.isAlphabetsFiltered) {
List<String> temp = [];
alphabets.forEach((letter) {
AlphaModel? firstAlphabetElement = _list.firstWhereOrNull(
(item) => item.key.toLowerCase().startsWith(letter.toLowerCase()));
if (firstAlphabetElement != null) {
temp.add(letter);
}
});
_filteredAlphabets = temp;
} else {
_filteredAlphabets = alphabets;
}
calculateFirstIndex();
setState(() {});
}
#override
void initState() {
init();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
listController.addListener(() {
print('scrolling ${listController.position.pixels}');
if (listController.position.pixels >=
listController.position.maxScrollExtent) {
print('achieved end');
} else if (listController.position.pixels <=
listController.position.minScrollExtent) {
print('achieved start');
}
});
});
if (listController.hasClients) {
maxScroll = listController.position.maxScrollExtent;
}
super.initState();
}
ScrollController listController = ScrollController();
final _selectedIndexNotifier = ValueNotifier<int>(0);
final positionNotifer = ValueNotifier<Offset>(Offset(0, 0));
final Map<String, int> firstIndexPosition = {};
List<String> _filteredAlphabets = [];
final letterKey = GlobalKey();
List<AlphaModel> _list = [];
bool isLoading = false;
bool isFocused = false;
final key = GlobalKey();
#override
void didUpdateWidget(covariant AlphabetScrollView oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.list != widget.list ||
oldWidget.isAlphabetsFiltered != widget.isAlphabetsFiltered) {
_list.clear();
firstIndexPosition.clear();
init();
}
}
int getCurrentIndex(double vPosition) {
double kAlphabetHeight = letterKey.currentContext!.size!.height;
return (vPosition ~/ kAlphabetHeight);
}
/// calculates and Maintains a map of
/// [letter:index] of the position of the first Item in list
/// starting with that letter.
/// This helps to avoid recomputing the position to scroll to
/// on each Scroll.
void calculateFirstIndex() {
_filteredAlphabets.forEach((letter) {
AlphaModel? firstElement = _list.firstWhereOrNull(
(item) => item.key.toLowerCase().startsWith(letter));
if (firstElement != null) {
int index = _list.indexOf(firstElement);
firstIndexPosition[letter] = index;
}
});
}
void scrolltoIndex(int x, Offset offset) {
int index = firstIndexPosition[_filteredAlphabets[x].toLowerCase()]!;
final scrollToPostion = widget.itemExtent * index;
if (index != null) {
listController.animateTo((scrollToPostion),
duration: const Duration(milliseconds: 300), curve: Curves.easeOut);
}
positionNotifer.value = offset;
}
void onVerticalDrag(Offset offset) {
int index = getCurrentIndex(offset.dy);
if (index < 0 || index >= _filteredAlphabets.length) return;
_selectedIndexNotifier.value = index;
setState(() {
isFocused = true;
});
scrolltoIndex(index, offset);
}
double? maxScroll;
#override
Widget build(BuildContext context) {
return Stack(
children: [
ListView.builder(
controller: listController,
scrollDirection: Axis.vertical,
itemCount: _list.length,
physics: ClampingScrollPhysics(),
itemBuilder: (_, x) {
return ConstrainedBox(
constraints: BoxConstraints(maxHeight: widget.itemExtent),
child: widget.itemBuilder(_, x, _list[x].key));
}),
Align(
alignment: widget.alignment == LetterAlignment.left
? Alignment.centerLeft
: Alignment.centerRight,
child: Container(
key: key,
padding: const EdgeInsets.symmetric(horizontal: 2),
child: SingleChildScrollView(
child: GestureDetector(
onVerticalDragStart: (z) => onVerticalDrag(z.localPosition),
onVerticalDragUpdate: (z) => onVerticalDrag(z.localPosition),
onVerticalDragEnd: (z) {
setState(() {
isFocused = false;
});
},
child: ValueListenableBuilder<int>(
valueListenable: _selectedIndexNotifier,
builder: (context, int selected, Widget? child) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(
_filteredAlphabets.length,
(x) => GestureDetector(
key: x == selected ? letterKey : null,
onTap: () {
_selectedIndexNotifier.value = x;
scrolltoIndex(x, positionNotifer.value);
},
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topRight: widget.alignment == LetterAlignment.left ? Radius.circular(20) : Radius.circular(0),
bottomRight: widget.alignment == LetterAlignment.left ? Radius.circular(20) : Radius.circular(0),
topLeft: widget.alignment == LetterAlignment.right ? Radius.circular(20) : Radius.circular(0),
bottomLeft: widget.alignment == LetterAlignment.right ? Radius.circular(20) : Radius.circular(0)
),
color: selected == x ? Color(0xFFFA3B71) : Colors.transparent
),
padding: const EdgeInsets.symmetric(
horizontal: 12, vertical: 2),
child: Text(
_filteredAlphabets[x].toUpperCase(),
style: selected == x
? widget.selectedTextStyle
: widget.unselectedTextStyle,
// style: TextStyle(
// fontSize: 12,
// fontWeight: selected == x
// ? FontWeight.bold
// : FontWeight.normal),
),
),
),
));
}),
),
),
),
),
!isFocused
? Container()
: ValueListenableBuilder<Offset>(
valueListenable: positionNotifer,
builder:
(BuildContext context, Offset position, Widget? child) {
return Positioned(
right:
widget.alignment == LetterAlignment.right ? 40 : null,
left:
widget.alignment == LetterAlignment.left ? 40 : null,
top: position.dy,
child: widget.overlayWidget == null
? Container()
: widget.overlayWidget!(_filteredAlphabets[
_selectedIndexNotifier.value]));
})
],
);
}
}
class AlphaModel {
final String key;
final String? secondaryKey;
AlphaModel(this.key, {this.secondaryKey});
}
If you want to test my code you can install package linked above, I just changed customization for background of letter scrollview.
You can do Like this :
Check this Example:
Expanded(
child: AlphabetScrollView(
list:
_filterList.map((e) => AlphaModel(e.employeeName)).toList(),
// isAlphabetsFiltered: false,
alignment: LetterAlignment.right,
itemExtent: 90,
unselectedTextStyle: TextStyle(
fontSize: 18,
fontWeight: FontWeight.normal,
color: _filterList.length > 5
? Colors.black
: Colors.transparent),
selectedTextStyle: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: _filterList.length > 5
? Colors.red
: Colors.transparent),
overlayWidget: (value) => Stack(
alignment: Alignment.center,
children: [
Icon(
Icons.star,
size: 50,
color: Colors.red,
),
Container(
height: 50,
width: 50,
decoration: BoxDecoration(
shape: BoxShape.circle,
// color: Theme.of(context).primaryColor,
),
alignment: Alignment.center,
child: Text(
'$value'.toUpperCase(),
style: TextStyle(fontSize: 18, color: Colors.white),
),
),
],
),
itemBuilder: (_, index, id) {
return InkWell(
onTap: () => Get.toNamed(EmployeeInfo.route,
arguments: _filterList[index]),
child: Container(
margin: EdgeInsets.only(right: 20),
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(bottom: 12.0),
child: Row(
children: [
SizedBox(
width: 10,
),
Stack(
children: [
CircularProfileAvatar(
SystemConfiguration.baseUrl +
SystemConfiguration.getEmployePhoto +
_filterList[index]
.id, //sets image path, it should be a URL string. default value is empty string, if path is empty it will display only initials
radius: 30, // sets radius, default 50.0
backgroundColor: Colors
.transparent, // sets background color, default Colors.white
borderWidth:
2, // sets border, default 0.0
borderColor: Colors
.blue, // sets border color, default Colors.white
cacheImage:
true, // allow widget to cache image against provided url
imageFit: BoxFit.cover,
// sets on tap
showInitialTextAbovePicture: true,
errorWidget: (BuildContext context,
String data, dynamic v) {
return Icon(
FeatherIcons.user,
size: 40,
color: Colors.white,
);
}, // setting it true will show initials text above profile picture, default false
),
Positioned(
bottom: 5,
right: 0,
child: Padding(
padding:
const EdgeInsets.only(left: 3.0),
child: Container(
width: 17,
height: 17,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Color(0xFFe0f2f1)),
child: Icon(
Icons.circle,
size: 16.0,
// ignore: unnecessary_null_comparison
color: (_filterList[index]
.attendanceStatus
.length >
0 &&
_filterList[index]
.InOffice
.contains("IN"))
? Colors.green
: Colors.red[500],
),
),
))
],
),
Expanded(
flex: 3,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
_filterList[index].employeeName,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: GoogleFonts.roboto(
fontSize: 13.0,
fontWeight: FontWeight.w500),
),
],
),
),
),
Expanded(
flex: 2,
child: Stack(
children: [
Positioned(
left: 44,
child: ElevatedButton(
onPressed: () => _launchURL(
_filterList[index].mobile1),
child: Icon(
Icons.call,
size: 20.0,
color: Colors.white,
),
style: ElevatedButton.styleFrom(
shape: CircleBorder(),
padding: EdgeInsets.all(2),
primary:
Colors.blue, // <-- Button color
onPrimary:
Colors.red, // <-- Splash color
),
),
),
ElevatedButton(
onPressed: () {
// _textMe(_filterList[index].mobile1); mobile text
Get.toNamed(ChatViwer.route,
arguments: {
"employe_name":
_filterList[index]
.employeeName,
"employe_id":
_filterList[index].id
});
},
child: Icon(
Icons.message,
size: 20.0,
color: Colors.white,
),
style: ElevatedButton.styleFrom(
shape: CircleBorder(),
padding: EdgeInsets.all(2),
primary:
Colors.blue, // <-- Button color
onPrimary:
Colors.red, // <-- Splash color
),
),
],
),
)
I am trying to preselect a particular tag shown on the right of the image.
However, I am unable to figure out where to set it. The tags are coming from an API (Postgres backend).
Once it is built to a list of overlay as shown on the right again in the screenshot. I just wanted it to preselect, "Morning", "Evening" or "Daytime" based on the time of the day.
To start off with, I am not able to preselect anything in "selectedTags". This can only be done manually by the user when clicked on a tag.
The method is shared below.
showTagPicker(context, allTags) async {
await showModalBottomSheet(
isDismissible: false,
enableDrag: false,
backgroundColor: Colors.transparent,
isScrollControlled: true,
context: context,
builder: (builder) => Center(
child: Container(
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(10),
),
color: Colors.white,
),
margin: EdgeInsets.all(16),
padding: EdgeInsets.all(24),
child: ListView(
shrinkWrap: true,
children: <Widget>[
Text(
"Please pick your tags",
style: TextStyle(fontSize: 16),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: TagPicker(
height: MediaQuery.of(context).size.height * .6,
tags: allTags,
onTagSelected: (_selectedTags) {
selectedTags = _selectedTags;
print("----->");
print(selectedTags);
print("<-----");
},
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
RaisedButton(
color: PRIMARY,
textColor: WHITE,
onPressed: () {
Navigator.of(context).pop();
navigateToAnalysis(context);
},
child: Text("Save"),
),
],
)
],
),
),
),
);
}
I tried, adding "print" to debug and see what and where things are being set but I did not get any further, I have also shown the debug screen if it helps.
Any direction here to preselect one/many tags would be helpful.
Please let me know if I must provide additional details to solve this.
Also, I know there are several things in the code which might be wrong, it is inherited code and I am struggling a bit.
Edit: Including TagPicker. It is not a public library but our widget.
class TagPicker extends StatefulWidget {
const TagPicker(
{Key key, this.height, this.tags, this.onTagSelected, this.selectedTags})
: super(key: key);
#override
TagPickerState createState() => TagPickerState();
final double height;
final List tags;
final List selectedTags;
final Function onTagSelected;
}
class TagPickerState extends State<TagPicker> {
List selectedTags = [];
#override
void initState() {
super.initState();
if (widget.selectedTags != null) {
setState(() {
selectedTags = widget.selectedTags;
});
}
}
#override
Widget build(BuildContext context) {
return widget.tags != null
? Container(
constraints: widget.height != null
? BoxConstraints(maxHeight: widget.height, minHeight: 60)
: BoxConstraints(),
child: SingleChildScrollView(
child: Wrap(
spacing: 0.0,
children: List.generate(
widget.tags.length,
(index) {
return Padding(
padding: const EdgeInsets.only(right: 4.0),
child: ChoiceChip(
selectedColor: PRIMARY,
labelStyle: TextStyle(
fontSize: 12,
color: selectedTags.contains(widget.tags[index])
? WHITE
: Colors.black),
label: Text(widget.tags[index]['tag_name']),
selected: selectedTags.contains(widget.tags[index]),
onSelected: (selected) {
setState(() {
selectedTags.contains(widget.tags[index])
? selectedTags.remove(widget.tags[index])
: selectedTags.add(widget.tags[index]);
widget.onTagSelected(selectedTags);
});
},
),
);
},
),
),
),
)
: Container();
}
}
Pass selectedTags as an argument to TagPicker and modify TagPicker to render an initial set of selected tags. As before onTagSelected callback will provide an updated set.
I have a Dialog class in which I want to show different designations that could be assigned to an employee.
In the beginning, I tried to use only a RaisedButton to select the desired designations. Within the App, the Button should change Colors. This part is found within a StatefulWidget.
I also tried a modified version, where I created a new StatefulWidget only for the Dialog part but this part did not have any effect, thus I thought to implement a SwitchListTile to do the same thing.
The SwitchListTile gets activated and deactivated although only the true value gets registered. This means that when I deactivate (swipe to left) the code does not go within the following setState:
setState(() { hEnabled[hDesignations[index].designation] = value; });
Also when the hEnabled Map gets changed within the setState method the following code does not re-run to change the color of the container:
color: hEnabled[hDesignations[index].designation] ? Colors.green : Colors.grey,
Part with the Dialog:
Widget buildChooseDesignations(
BuildContext context, List<Designation> hDesignations) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadiusDirectional.circular(8.0),
),
child: _buildDialogChild(context, hDesignations),
);
}
_buildDialogChild(BuildContext context, List<Designation> hDesignations) {
//todo: when editing an employee I need the chosen designations (have to pass a list)
Map<String, bool> hEnabled = new Map<String, bool>();
for (var i = 0; i < hDesignations.length; i++) {
hEnabled[hDesignations[i].designation] = false;
}
return Container(
height: 200.0,
//todo: width not working properly
width: 50,
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: hDesignations.length,
itemBuilder: (context, index) {
return Row(
children: <Widget>[
Expanded(
child: Container(
width: 10,
color: hEnabled[hDesignations[index].designation]
? Colors.green
: Colors.grey,
padding: EdgeInsets.only(left: 80),
child: Text(hDesignations[index].designation,
style: TextStyle(fontWeight: FontWeight.bold),),
),
),
Expanded(
child: SwitchListTile(
value: hEnabled[hDesignations[index].designation],
onChanged: (bool value) {
setState(() {
hEnabled[hDesignations[index].designation] =
value;
});
}),
)
],
);
}),
),
SizedBox(
height: 15.0,
),
RaisedButton(
color: Colors.blueGrey,
child: Text(
'set',
style: TextStyle(color: Colors.white),
),
onPressed: () {
//todo: save the 'newly' selected designations in a list on set click
},
)
],
),
);
}
The Dialog is called when I click on the Add + FlatButton and looks like this:
ButtonTheme(
height: 30.0,
// child: Container(),
child: FlatButton(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
color: Colors.blueGrey.shade200,
onPressed: () {
//todo add Dialog
// List<Designation> hList = state.designations;
showDialog(
context: context,
builder: (context) => buildChooseDesignations(
context, state.designations));
// DesignationDialog(
// designations:state.designations));
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0)),
child: Text(
'Add +',
style: TextStyle(color: Colors.black),
),
),
),
Found the problem :)
First I did re-write everything into a new StatefulWidget. This I needed since I want that my widget gets re-build after I click on the SwitchListTile to re-color my Container.
Then I had to move my hEnabled (re-named hChecked) map outside the state. The reason was that the widget would re-build all the everything including the initialization of this map, making the user's input useless.
The same applies to the RaisedButton Widget.
Here is my code:
class DesignationDialog extends StatefulWidget {
final List<Designation> designations;
final Map<String, bool> hChecked;
DesignationDialog({Key key, this.designations, this.hChecked}) : super(key: key);
#override
_DesignationDialogState createState() => _DesignationDialogState();
}
class _DesignationDialogState extends State<DesignationDialog> {
_buildDialogChild(BuildContext context, List<Designation> hDesignations) {
//todo: when editing an employee I need the chosen designations (have to pass a list)
// for (var i = 0; i < hDesignations.length; i++) {
// hChecked[hDesignations[i].designation] = false;
// }
return Container(
height: 200.0,
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: hDesignations.length,
itemBuilder: (context, index) {
// return ButtonTheme(
// //todo: fix the width of the buttons is not working
// minWidth: 20,
// child: RaisedButton(
// color: widget.hChecked[hDesignations[index].designation]
// ? Colors.green
// : Colors.grey,
// child: Text(hDesignations[index].designation),
// onPressed: () {
// //todo mark designation and add to an array
// setState(() {
// widget.hChecked[hDesignations[index].designation] =
// !widget
// .hChecked[hDesignations[index].designation];
// });
// },
// ),
// );
// -- With Switch
return Row(
children: <Widget>[
Expanded(
child: Container(
child: Text(hDesignations[index].designation),
width: 10,
color: widget.hChecked[hDesignations[index].designation]
? Colors.green
: Colors.grey,
)),
Expanded(
child: SwitchListTile(
value: widget.hChecked[hDesignations[index].designation],
onChanged: (bool value) {
setState(() {
widget.hChecked[hDesignations[index].designation] =
value;
});
}),
)
],
);
// -- end
}),
),
SizedBox(
height: 15.0,
),
RaisedButton(
color: Colors.blueGrey,
child: Text(
'set',
style: TextStyle(color: Colors.white),
),
onPressed: () {
//todo: save the 'newly' selected designations in a list on set click
},
)
],
),
);
}
#override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadiusDirectional.circular(8.0),
),
child: _buildDialogChild(context, widget.designations),
);
}
In a Drawer, in listview want to change the color of CustomListTile when the onTap is clicked and setting color of all other children to default?
class CustomListTile extends StatelessWidget {
final Color itemContainerColor;
const CustomListTile({
//deafult color is Colors.white
this.itemContainerColor= Colors.white,
});
#override
Widget build(BuildContext context) {
return InkWell(
onTap: (){},
child: Container(
margin: EdgeInsets.symmetric(vertical: 4),
padding: EdgeInsets.symmetric(vertical: 5, horizontal: 16),
width: 150,
decoration: BoxDecoration(
color: itemContainerColor,
)
child:
Text(
"ListTile 1",
style: TextStyle(
fontSize: 20,
color: Colors.green,
fontWeight: FontWeight.w600),
),
),
));
}
}
Try this.
class ChangeListViewBGColor extends StatefulWidget {
_ChangeListViewBGColorState createState() => _ChangeListViewBGColorState();
}
class _ChangeListViewBGColorState extends State<ChangeListViewBGColor> {
final List<String> _listViewData = [
"Item 1",
"Item 2",
"Item 3",
"Item 4",
"Item 5",
"Item 6",
"Item 7",
"Item 8",
];
int _selectedIndex = 0;
_onSelected(int index) {
setState(() => _selectedIndex = index);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BG change'),
),
body: ListView.builder(
itemCount: _listViewData.length,
itemBuilder: (context, index) => Container(
color: _selectedIndex != null && _selectedIndex == index
? Colors.red
: Colors.white,
child: ListTile(
title: CustomListTile(_listViewData[index]),
onTap: () => _onSelected(index),
),
),
),
);
}
}
class CustomListTile extends StatelessWidget {
var titleName;
CustomListTile(this.titleName);
#override
Widget build(BuildContext context) {
return InkWell(
child: Container(
child: Text(
this.titleName,
style: TextStyle(
fontSize: 20, color: Colors.green, fontWeight: FontWeight.w600),
),
margin: EdgeInsets.symmetric(vertical: 4),
padding: EdgeInsets.symmetric(vertical: 5, horizontal: 16),
width: 150,
)
);
}
}
Aakash Just use a boolean on tab like colorChange = true when button clicked and other hands in child widget of container...
colorChange ?
Text(
"ListTile 1",
style: TextStyle(
fontSize: 20,
color: Colors.red, // which color you need to use
fontWeight: FontWeight.w600),
): Text(
"ListTile 2",
style: TextStyle(
fontSize: 20,
color: Colors.green,
fontWeight: FontWeight.w600),
)
Note: One can go according to #Amit Prajapati 's solution/logic, but if
your use-case is going to get complex over time then I would recommend
going as per the below solution.
Whenever you need to change the property of a specific element from a list of elements, use a list of values having the same datatype as that of the value accepted by that property having the same length as that of the number of elements in your main list.
In your case you need to change the color of a specific ListTile whenever the user clicks on it. So declare a List of Colors.
List<Color> tileColors;
Now in initState() of your main widget initialize the List with its default values (depending on the length of our main widget).
for(int i=0;i<items.length;i++) tileColors.add(defaultColor);
Now while using a builder function set each item(ListTile) of your list with tileColors[index],
(I'll be using ListView.builder)
ListView.builder(
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
return new Container(
color: tileColors[index],
child: ListTile([...]),
);
}
)
Now just setState() the value of the property(color) of that ListTile whenever the user taps on it.
ListView.builder(
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
return new Container(
color: tileColors[index],
child: ListTile(
onTap: (){
setState((){
for(int i=0;i<item.length;i++) tileColors[i] = defaultColor;
tileColors[index] = selectedColor; // selectedColor is the color which you wish to change to.
// Note: You can add your own conditions over. e.g. If you want the first tile to be of a specific color and the rest should be different color while the user taps.
});
}
),
);
}
)
Tip: You can use AnimatedContainer instead of Container widget to create a
smooth transition when the user taps. Set the duration parameter to Duration(milliseconds: 300).