I am not finding any answer for my question so I am hoping to find someone who can help.
I have a GridView with text buttons.
I can select the buttons, however I can't unselect any of them.
this is my code
#override
Widget build(BuildContext context) {
return TextButton(
onLongPress: () => showDialog<String>(
),
style: ButtonStyle(
side: MaterialStateProperty.all(BorderSide(
width: 5,
color: widget.isSelected ? Colors.black : Colors.white)),
shape: MaterialStateProperty.all(
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))),
backgroundColor: MaterialStateProperty.all(widget.pickerColor),
elevation: MaterialStateProperty.all(10)),
onPressed: () {
widget.selectedCard(widget.index); //This selects the cards, how to unselect (if Statements?)
},
child: FittedBox(
fit: BoxFit.fitHeight,
child: Text(
widget.cardTitle,
style: TextStyle(
fontSize: 17,
color: useWhiteForeground(widget.pickerColor)
? const Color(0xffffffff)
: const Color(0xff000000),
),
),
),
);
}
}
This is the Grid
#override
Widget build(BuildContext context) {
return Consumer<MyCardData>(
builder: (context, cardData, child) {
return Padding(
padding: const EdgeInsets.all(10),
child: GridView.builder(
clipBehavior: Clip.none,
itemBuilder: (context, index) {
final card = cardData.cards[index];
return MyCard(
selectedCard,
index: index,
isSelected: _selectedCard == index,
cardTitle: card.name,
pickerColor: card.cardColor,
deleteCallback: () {
cardData.deleteCallback(card);
},
);
},
itemCount: cardData.cardCount,
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 150,
childAspectRatio: 2.5 / 1,
crossAxisSpacing: 0,
mainAxisSpacing: 0,
),
),
);
},
);
}
}
feel free to use my git to see the full code
get from version control
since you want to make a single selection, it will need a simple workaround.
int _selectedCard = -1;
selectedCard(index) {
// this condition is when user press the same button
// set the _selectedCard back into -1
if (_selectedCard == index) {
setState(() {
_selectedCard = -1;
});
} else{
setState(() {
_selectedCard = index;
});
}
}
Related
Halo,
I have problem with my Selected Container,
it changed on main page when selected, but didn't change when selected in bottomsheet.
here's the video link :
https://youtube.com/shorts/hzPNNQB6Gws?feature=share
here is the screenshoot :
This is how I call in bottomsheet :
bottomsheet: Container(
~~
~~
child: OutlinedButton(
child: Text("Buy Now"),
onPressed: (){
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return bottomContainer(context);
});
},
),
)
here's the bottomContainer widget code :
Widget bottomContainer(BuildContext context) {
~~
~~
return Wrap(
spacing: 8.0,
runSpacing: 4.0,
children: <Widget> [
...List.generate(
listVariant.length,
(index) => selectedButton(
index: index,
text: listVariant[index],
),
),
],
),
~~
~~
}
and here's selectedButton widget full code :
Widget selectedButton({required String text, required int index}) {
return InkWell(
splashColor: Colors.cyanAccent,
onTap: () {
setState(() {
_selectedVariant = index;
print('$index, $text');
});
},
child: Container(
height: 36,
width: text.length.toDouble() *9,
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(10)),
border: Border.all(
width: 1.5,
color: const Color.fromRGBO(78, 125, 150, 1),
),
color: index == _selectedVariant
? const Color.fromRGBO(78, 125, 150, 0.5)
: Colors.white,
),
child: Center(
child: Text(text,
textAlign: TextAlign.center,
style: const TextStyle(
color: Color.fromRGBO(78, 125, 150, 1),
fontSize: 13,
fontWeight: FontWeight.w700
),
),
)
),
);
}
IDK where's the problem because you can see in video that it was working on body, but didn't work in bottomsheet widget.
*All of this code was in one class state
The reason this is happening is that you try to update your main page not your showModalBottomSheet, first change your selectedButton to this:
Widget selectedButton({required String text, required int index, required Function() onTap}) {
return InkWell(
splashColor: Colors.cyanAccent,
onTap: onTap,
child: ...
);
}
then change your bottomContainer to this:
Widget bottomContainer(BuildContext context, void Function(void Function()) innerSetState) {
~~
~~
return Wrap(
spacing: 8.0,
runSpacing: 4.0,
children: <Widget> [
...List.generate(
listVariant.length,
(index) => selectedButton(
onTap:(){
innerSetState(() {
_selectedVariant = index;
});
},
index: index,
text: listVariant[index],
),
),
],
),
~~
~~
}
then change your showModalBottomSheet to this:
onPressed: (){
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (context, innerSetState) {
return bottomContainer(context, innerSetState);
},
),
});
},
Note: when you try to call selectedButton from your main page remember to pass these function to it:
selectedButton(
onTap:(){
setState(() {
_selectedVariant = index;
});
},
...
)
I'm using a ready-made local database in my application and the problem is that I can't update one item from the list. If I add a chapter to favorites, then the button's state is updated only after the page is reopened. Likewise, the favorites list is updated only when the page is reopened. Right now when I add/remove favorites, I dynamically load the entire list so that it updates the values, but I only need to update one item, how can I do this using a provider? I didn’t give code examples, because I want to understand exactly the logic of actions
UPD:
My code:
#override
Widget build(BuildContext context) {
return FutureBuilder<List>(
future: _databaseQuery.getAllChapters(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
return snapshot.connectionState == ConnectionState.done &&
snapshot.hasData
? CupertinoScrollbar(
child: ListView.builder(
physics: const BouncingScrollPhysics(),
itemCount: snapshot.data!.length,
itemBuilder: (BuildContext context, int index) {
return MainChapterItem(
item: snapshot.data![index],
);
},
),
)
: const Center(
child: CircularProgressIndicator.adaptive(),
);
},
);
}
Item:
final MainChapterItemModel item;
#override
Widget build(BuildContext context) {
return Material(
child: InkWell(
child: Container(
padding: const EdgeInsets.all(8),
child: Row(
children: [
IconButton(
icon: item.favoriteState == 0
? const Icon(CupertinoIcons.bookmark)
: const Icon(CupertinoIcons.bookmark_fill),
splashRadius: 22,
splashColor: const Color(0xff81b9b0),
onPressed: () {
context.read<BookmarkButtonState>().addRemoveChapterBookmark(
item.favoriteState == 0 ? 1 : 0, item.id);
},
),
const SizedBox(
width: 8,
),
Flexible(
child: ListTile(
contentPadding: EdgeInsets.zero,
title: Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Text(
item.chapterNumber,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
),
subtitle: Html(
data: item.chapterTitle,
style: {
'#': Style(
fontSize: const FontSize(17),
padding: EdgeInsets.zero,
margin: EdgeInsets.zero,
),
'small': Style(
fontSize: const FontSize(8),
),
'a': Style(
fontSize: const FontSize(14),
color: Colors.blue,
),
},
),
),
),
],
),
),
onTap: () {},
),
);
}
The problem is that when I add to favorites or delete, the button state is not updated. And in the favorites list, the item is not deleted on click, but it disappears after the page is reopened:
IconButton(
icon: item.favoriteState == 0
? const Icon(CupertinoIcons.bookmark)
: const Icon(CupertinoIcons.bookmark_fill),
splashRadius: 22,
splashColor: const Color(0xff81b9b0),
onPressed: () {
context.read<BookmarkButtonState>().addRemoveChapterBookmark(
item.favoriteState == 0 ? 1 : 0, item.id);
},
),
Provider code:
final DatabaseQuery _databaseQuery = DatabaseQuery();
DatabaseQuery get getDatabaseQuery => _databaseQuery;
addRemoveChapterBookmark(int state, int chapterId) {
_databaseQuery.addRemoveFavoriteChapter(state, chapterId);
notifyListeners();
I solved the problem by signing all lists to listen to databaseQuery in the provider:
future: context.watch<BookmarkButtonState>().getDatabaseQuery.getAllChapters(),
As the question suggests I have an ExpansionPanelList, one ExpansionPanel (the last one or the 7th one) should have 2 additional buttons, but how can I add them just in this one last panel & not in all the others as well?
This is the code of my whole Expansion panel, as Im not sure where you have to add the behaviour, but guessing in the body of the ExpansionPanel (close to line 40):
class ExpansionList extends StatefulWidget {
final Info info;
const ExpansionList({
Key key,
this.info,
}) : super(key: key);
#override
_ExpansionListState createState() => _ExpansionListState();
}
class _ExpansionListState extends State<ExpansionList> {
Widget _buildListPanel() {
return Container(
child: Theme(
data: Theme.of(context).copyWith(
cardColor: Color(0xffDDBEA9),
),
child: ExpansionPanelList(
dividerColor: Colors.transparent,
elevation: 0,
expansionCallback: (int index, bool isExpanded) {
setState(() {
infos[index].isExpanded = !isExpanded;
});
},
children: infos.map<ExpansionPanel>((Info info) {
return ExpansionPanel(
headerBuilder: (BuildContext context, bool isExpanded) {
return ListTile(
title: !isExpanded
? Text(
info.headerValue,
) //code if above statement is true
: Text(
info.headerValue,
textScaleFactor: 1.3,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
);
},
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: BoxDecoration(
color: Color(0xffFFE8D6),
borderRadius: BorderRadius.circular(25)),
child: Column(
children: [
ListView.separated(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.only(left: 40.0,),
itemCount: info.expandedValueData.length,
itemBuilder: (context, index) {
return CheckboxListTile(
title: Text(info.expandedValueData[index].title,
style: TextStyle(
decoration: info.expandedValueData[index]
.completed
? TextDecoration.lineThrough
: null)),
value: info.expandedValueData[index].completed,
onChanged: (value) {
setState(() {
// Here you toggle the checked item state
infos.firstWhere(
(currentInfo) => info == currentInfo)
..expandedValueData[index].completed =
value;
});
});
},
separatorBuilder: (BuildContext context, int index) {
return SizedBox(
height: 20,
);
},
),
Row(children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.16),
Text("Abschnitt bis zum Neustart löschen"),
SizedBox(
width: MediaQuery.of(context).size.width * 0.11),
IconButton(
icon: Icon(Icons.delete),
onPressed: () {
setState(() {
infos.removeWhere(
(currentInfo) => info == currentInfo);
});
},
)
]),
],
),
),
),
isExpanded: info.isExpanded);
}).toList(),
),
),
);
}
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Container(
child: _buildListPanel(),
),
);
}
}
Thanks for suggestions!
Hi Just add a field (if you already do not have one) in the info object that will allow you to change the widget that is inflated based on that field.
For example
...
children: infos.map<ExpansionPanel>((Info info) {
return ExpansionPanel(
headerBuilder: (BuildContext context, bool isExpanded) {
return info.type == TYPE_A ? TypeAWidgetHeader(info) : TypeBWidgetHeader(info);
body: info.type == TYPE_A ? TypeAWidgetBody(info) : TypeBWidgetBody(info);
...
I know this question has been asked before, and here's the link to that question:
How do i change the color and text of Container at onTap event in FLUTTER
However in my case I have around 50 containers in a row, so using the provided solution would be extremely lengthy.
Is there any shortcut using UniqueKeys()??
Try this:
class _TestState extends State<Test> {
int selected = 0;
List<Widget> _containerList() {
return List.generate(50, (index) {
return GestureDetector(
onTap: () {
setState(() {
selected = index;
});
},
child: Container(
height: 200,
width: 200,
color: selected == index ? Colors.blue : Colors.transparent,
child: Text("$index"),
),
);
}).toList();
}
#override
Widget build(BuildContext context) {
return Column(
children: _containerList(),
);
}
}
OR
ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 50,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () {
setState(() {
selected = index;
});
},
child: Container(
height: 200,
width: 200,
color: selected == index ? Colors.blue : Colors.transparent,
child: Text("$index"),
),
);
}
)
OR
Wrap(children: _containerList(),)
You can do something like this..
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
var _selectedIndex = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: RefreshIndicator(
onRefresh: () async {
//write your code here to update the list*********
},
child: ListView.builder(
itemCount: 100,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {
setState(() { _selectedIndex = index; });
},
child: Text(
'Line $index',
style: TextStyle(
color: _selectedIndex == index ? Colors.red : Colors.black,
)
),
);
}
)
),
);
}
}
List<String> _selectedIndexs = [];ListView.separated(
padding: EdgeInsets.zero,
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
final _isSelected = _selectedIndexs.contains(index);
return GestureDetector(
onTap: () {
setState(() {
if (_isSelected) {
_selectedIndexs.remove(index);
} else {
_selectedIndexs.add(index);
}
print(_selectedIndexs);
});
},
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 25, vertical: 10),
decoration: BoxDecoration(
color: _isSelected
? ContainerColors.selectedBgColor
: priorityChipBg,
borderRadius: BorderRadii.radius8px,
border: Border.all(
color: _isSelected
? BorderColor.bordersecondaryBlue
: chipBorderColor)),
child: Text(
requestPriority[index],
style: _isSelected
? AppFonts.mediumTextBB.copyWith(
color: TextColors.themeColor,
fontSize: 14,
fontWeight: FontWeight.w900)
: chipTextStyle,
),
),
);
},
separatorBuilder: (BuildContext context, int index) {
return const SizedBox(
width: 20,
);
},
itemCount: 3,
),
),
enter image description hereplz helpp me here i'm new to flutter....! i have seen many tutorials on this but nothig is happen to me...! what i want is i have listing array for gridview images and then ontap button the images shows to next screen ! in that i want sliding images like page is navigating and my images is sliding with same array which shows me above code on my 1st screen ! plz give me some tip on sliding images with same array of this page....! thank you for ua time..
plz give me some coding tips on next screen which i can slide images with same array
return Scaffold(
appBar: getAppBar(),
body: FutureBuilder(
future: _doctorsFuture,
builder: (context, projectSnap) {
Map data = projectSnap.data;
print(projectSnap);
if (projectSnap.connectionState == ConnectionState.none &&
projectSnap.hasData == null) {
return Center(
child: Text(
"Failed to loaed",
style: TextStyle(fontSize: 16.0, color: Colors.red),
));
} else if (projectSnap.hasData) {
return StaggeredGridView.countBuilder(
crossAxisCount: 2,
primary: false,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
itemCount: (data["hits"] as List).length,
itemBuilder: (context, index) {
if (_selectionMode) {
return GridTile(
header: GridTileBar(
trailing: Icon(
_selectedIndexList.contains(index) ? Icons
.check_circle_outline : Icons
.radio_button_unchecked,
color: _selectedIndexList.contains(index) ? Colors
.green : Colors.black,
),
),
child: GestureDetector(
child: Container(
decoration: BoxDecoration(
color: Colors.transparent,
),
child:Image.network(
data['hits'][index]['largeImageURL'],
height: 50,
width: 100,
fit: BoxFit.cover,
)
),
onLongPress: () {
_changeSelection(enable: false, index: -1);
},
onTap: () {
setState(() {
if (_selectedIndexList.contains(index)) {
_selectedIndexList.remove(index);
} else {
_selectedIndexList.add(index);
}
});
},
),
);
}
else {
return GridTile(
child: InkResponse(
child: Image.network(
data['hits'][index]['largeImageURL'],
height: 50,
width: 100,
fit: BoxFit.cover,
),
onLongPress: () {
setState(() {
_changeSelection(enable: true, index: index);
});
},
onTap:(){
Navigator.of(context).push(MaterialPageRoute(builder: (context) => ImageView( imgPath: data['hits'][index]['largeImageURL'],)));
},
),
);
}
},
staggeredTileBuilder: (int index) => StaggeredTile.count(1, index.isEven ? 1.2 : 1.8),
padding: const EdgeInsets.all(4.0),
);
} else {
return Center(child: CircularProgressIndicator());
}
}
),
);
}