I have a Grid.View.builder with Buttons inside. I want to be able to select just one Button at a time!
At the moment I can select Buttons but when I select other buttons the previous Button stays selected.
How can I achieve this? In my_card_grid.dart or my_card.dart?
This is my_card_grid.dart
import 'package:flutter/material.dart';
import 'package:cards/widgets/my_card.dart';
import 'package:provider/provider.dart';
import 'package:cards/Models/card_data.dart';
class CardsGrid extends StatelessWidget {
const CardsGrid({Key? key}) : super(key: key);
@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(
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,
),
),
);
},
);
}
}
and this is my_card.dart
import 'package:cards/Models/card.dart';
import 'package:cards/Screens/add_card.dart';
import 'package:flutter/material.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:cards/Models/card_data.dart';
import 'package:provider/provider.dart';
class MyCard extends StatefulWidget {
late String cardTitle;
Color pickerColor;
final VoidCallback deleteCallback;
MyCard(
{required this.cardTitle,
required this.pickerColor,
required this.deleteCallback});
@override
State<MyCard> createState() => _MyCardState();
}
class _MyCardState extends State<MyCard> {
bool selectedCard = false;
@override
Widget build(BuildContext context) {
return TextButton(
onLongPress: () => showDialog<String>(
context: context,
builder: (BuildContext context) => AlertDialog(
actionsAlignment: MainAxisAlignment.spaceEvenly,
title: Center(
child: Text(
widget.cardTitle,
style: TextStyle(
color: widget.pickerColor,
fontWeight: FontWeight.bold,
shadows: [
Shadow(
color: Colors.black.withOpacity(0.3),
offset: Offset(0, 0),
blurRadius: 15,
),
],
),
),
),
content: const Text(
'Möchtest du die Karte wirklich löschen?',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18,
),
),
actions: <Widget>[
TextButton(
style: ButtonStyle(
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
)),
elevation: MaterialStateProperty.all(10),
backgroundColor: MaterialStateProperty.all(Colors.white)),
onPressed: () {
widget.deleteCallback();
Navigator.pop(context);
},
child: const Text(
'Karte löschen',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 16),
),
),
TextButton(
style: ButtonStyle(
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
),
elevation: MaterialStateProperty.all(10),
backgroundColor: MaterialStateProperty.all(Colors.white)),
onPressed: () => Navigator.pop(context),
child: const Text(
'Abbrechen',
style: TextStyle(color: Colors.black, fontSize: 16),
),
),
],
),
),
style: ButtonStyle(
side: MaterialStateProperty.all(BorderSide(
width: 5, color: selectedCard ? Colors.black : Colors.white)),
shape: MaterialStateProperty.all(
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))),
backgroundColor: MaterialStateProperty.all(widget.pickerColor),
elevation: MaterialStateProperty.all(10)),
onPressed: () {
print(selectedCard);
setState(() {
selectedCard = !selectedCard;
});
},
child: FittedBox(
fit: BoxFit.fitHeight,
child: Text(
widget.cardTitle,
style: TextStyle(
fontSize: 17,
color: useWhiteForeground(widget.pickerColor)
? const Color(0xffffffff)
: const Color(0xff000000),
),
),
),
);
}
}
CodePudding user response:
Just a quick thought, I think we can achieve that by doing following modifications, which basically propagating selection info to parent:
- Change
MyCard
intoStatelessWidget
, which takes inisSelected
for rendering purpose - Modifying
CardsGrid
intoStatefulWidget
and adding a stateint selectedIdx
. - Wrap
MyCard
component insideGestureDector
for adjustingselected
Could be something like:
GestureDetector(
onTap() => setState(() => selected = index),
child: MyCard(selected == index),
)
As per requested, for Step 2,
class CardsGrid extends StatefulWidget {
CardsGrid({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => _CardsGridState();
}
class _CardsGridState extends State<CardsGrid> {
int selectedIdx = -1; // or mark as late and initialize in initState() if u prefer
@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 GestureDetector( // ADD
onTap: () => setState(() => selectedIdx = index), // ADD
child: MyCard(
selected: index == selectedIdx, // ADD
cardTitle: card.name,
pickerColor: card.cardColor,
deleteCallback: () {
cardData.deleteCallback(card);
},
), // ADD
);
},
itemCount: cardData.cardCount,
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 150,
childAspectRatio: 2.5 / 1,
crossAxisSpacing: 0,
mainAxisSpacing: 0,
),
),
);
},
);
}
}
CodePudding user response:
If you want the logic of a radio button, it should look like a radio button to be familiar. Find out more at https://material.io/components/radio-buttons. There's example Flutter code there for an implementation as well.