I have a dynamic list view and I want to open the item when I tap on it, but when I click on it, all list items also open. I only need to open the pressed item. I am using animated container for the animation and Visible to to hide the edit Text widget widget when the card is closed.
**Here is my code **
ListView.builder(
itemCount: dispoModes.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return Visibility(
child: GestureDetector(
onTap: () async {
setState(() {
open = !open;
});
await Future.delayed(
Duration(
milliseconds: open
? 280
: 100), () {
setState(() {
visible = !visible;
});
});
},
child: AnimatedContainer(
decoration:
const BoxDecoration(),
width: double.infinity,
height: open ? 134 : 62,
duration: const Duration(
milliseconds: 700),
curve: Curves.fastOutSlowIn,
child: Card(
shape: RoundedRectangleBorder(
side: BorderSide(
color: open
? HexColor(
'#31679A')
: Colors
.transparent,
width: open ? 2 : 0),
borderRadius:
BorderRadius.circular(
12.0),
),
elevation: 3,
child: Container(
decoration: BoxDecoration(
color:
HexColor('#F5F6F6'),
borderRadius:
const BorderRadius
.all(
Radius.circular(
12)),
border: Border.all(
color: open
? HexColor(
'#31679A')
: HexColor(
'#F5F6F6'),
width: open ? 0 : 2),
),
margin: EdgeInsets.all(
open ? 0 : 2),
child: Align(
alignment:
Alignment.topCenter,
child: Column(
children: [
Padding(
padding: EdgeInsets
.only(top: 5),
child: SizedBox(
height: 34,
child: Image.network(
"https://divadeep-admin.oxa.cloud/"
dispoModes[index]
.imageUrl)),
),
Visibility(
visible: visible,
child: Padding(
padding:
const EdgeInsets
.fromLTRB(
25,
15,
25,
0),
child:
TextField(
keyboardType:
TextInputType
.phone,
decoration:
InputDecoration(
isDense:
true,
hintText:
'Phone Number',
hintStyle: TextStyle(
color: HexColor(
"#9B9898"),
fontSize:
17,
fontFamily:
'Segoe-UI'),
),
),
),
),
],
)),
),
),
),
),
);
}),
enter code here
CodePudding user response:
Extract your list item as individual StatefulWidget
to have it's own state for open and visible
class ListItem extends StatefulWidget {
ListItem({Key? key}) : super(key: key);
@override
State<ListItem> createState() => _ListItemState();
}
class _ListItemState extends State<ListItem> {
bool open = false;
bool visible = false;
@override
Widget build(BuildContext context) {
return Visibility(
child: GestureDetector(
onTap: () async {
setState(() {
open = !open;
});
await Future.delayed(Duration(milliseconds: open ? 280 : 100), () {
setState(() {
visible = !visible;
});
});
},
child: AnimatedContainer(
decoration: const BoxDecoration(),
width: double.infinity,
height: open ? 134 : 62,
duration: const Duration(milliseconds: 700),
curve: Curves.fastOutSlowIn,
child: Card(
shape: RoundedRectangleBorder(
side: BorderSide(
color: open ? HexColor('#31679A') : Colors.transparent,
width: open ? 2 : 0),
borderRadius: BorderRadius.circular(12.0),
),
elevation: 3,
child: Container(
decoration: BoxDecoration(
color: HexColor('#F5F6F6'),
borderRadius: const BorderRadius.all(Radius.circular(12)),
border: Border.all(
color: open ? HexColor('#31679A') : HexColor('#F5F6F6'),
width: open ? 0 : 2),
),
margin: EdgeInsets.all(open ? 0 : 2),
child: Align(
alignment: Alignment.topCenter,
child: Column(
children: [
Padding(
padding: EdgeInsets.only(top: 5),
child: SizedBox(
height: 34,
child: Image.network(
"https://divadeep-admin.oxa.cloud/"
dispoModes[index].imageUrl)),
),
Visibility(
visible: visible,
child: Padding(
padding: const EdgeInsets.fromLTRB(25, 15, 25, 0),
child: TextField(
keyboardType: TextInputType.phone,
decoration: InputDecoration(
isDense: true,
hintText: 'Phone Number',
hintStyle: TextStyle(
color: HexColor("#9B9898"),
fontSize: 17,
fontFamily: 'Segoe-UI'),
),
),
),
),
],
)),
),
),
),
),
);
}
}
Then return it from your ListView
as itemBuilder
, like this:
ListView.builder(
itemCount: dispoModes.length,
shrinkWrap: true,
itemBuilder: (context, index) => ListItem(),
)
CodePudding user response:
int selectedIndex = -1;
Widget build()
...
itemCount: dispoModes.length,
shrinkWrap: true,
itemBuilder: (context, index) {
bool open = selectedIndex == index;
return Visibility(
child: GestureDetector(
onTap: () async {
setState(() {
selectedIndex = (selectedIndex == index) ? -1 : index; // second click closes it
});
await Future.delayed(
Duration(
milliseconds: open
? 280
: 100), () {
setState(() {
// also change it here
visible = !visible;
});
});
},
child: AnimatedContainer(
decoration:
const BoxDecoration(),
width: double.infinity,
height: open ? 134 : 62,
duration: const Duration(
milliseconds: 700),
curve: Curves.fastOutSlowIn,
child: Card(
shape: RoundedRectangleBorder(
side: BorderSide(
color: open
? HexColor(
'#31679A')
: Colors
.transparent,
width: open ? 2 : 0),
borderRadius:
BorderRadius.circular(
12.0),
),
elevation: 3,
child: Container(
decoration: BoxDecoration(
color:
HexColor('#F5F6F6'),
borderRadius:
const BorderRadius
.all(
Radius.circular(
12)),
border: Border.all(
color: open
? HexColor(
'#31679A')
: HexColor(
'#F5F6F6'),
width: open ? 0 : 2),
),
margin: EdgeInsets.all(
open ? 0 : 2),
child: Align(
alignment:
Alignment.topCenter,
child: Column(
children: [
Padding(
padding: EdgeInsets
.only(top: 5),
child: SizedBox(
height: 34,
child: Image.network(
"https://divadeep-admin.oxa.cloud/"
dispoModes[index]
.imageUrl)),
),
Visibility(
visible: visible,
child: Padding(
padding:
const EdgeInsets
.fromLTRB(
25,
15,
25,
0),
child:
TextField(
keyboardType:
TextInputType
.phone,
decoration:
InputDecoration(
isDense:
true,
hintText:
'Phone Number',
hintStyle: TextStyle(
color: HexColor(
"#9B9898"),
fontSize:
17,
fontFamily:
'Segoe-UI'),
),
),
),
),
],
)),
),
),
),
),
);
}),