Reputation: 57
I'm trying to implement the call button inside a card widget,
I want the whole card background to change color to blue (like selected) when I press the call button, and to be changed back to normal when I press any other card, like to make the call button switch for card selection, tried to use the setState function but it didn't work since it changes color only when I'm tapping the whole card not a specific button in it. How do I make the whole card selected when I press the call button and released when I press any other card (after I get back from the dialer application)
Here's my code:
_launchCaller() async {
const url = "tel:+972545522973";
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
return Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Card(
margin: EdgeInsets.fromLTRB(20.0, 6.0, 20.0, 0.0),
color: Colors.brown[30],
child: ListTile(
isThreeLine: true,
title: Row(
children: <Widget> [
Container(
child:Text(widget.helpRequest.category.description) ,
alignment: Alignment.topLeft,
),
Spacer(),
Container(
child:Text(formatter.format(now)),
alignment: Alignment.topRight,
),
]
)
,
subtitle: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
GetUserName(widget.helpRequest.sender_id, DataBaseService().userInNeedCollection),
Text(widget.helpRequest.description),
]
)
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
GestureDetector(
onTap: (){
_launchCaller();
** Here i think I should add the code **
},
onLongPress: () => print("Long Press: Call"),
child: Padding(
padding: EdgeInsets.all(16.0),
child: Icon(Icons.call,
size: 20.0,
color: Colors.green,
)
),
),
],
),
),
),
);
And this setState function I tried to use which didn't work well in my case (I was changing state on the onTap function):
void initState() {
super.initState();
color = Colors.transparent;
}
Upvotes: 1
Views: 1297
Reputation: 10655
Final Output:
You can set the color of a specific card, but for that to happen, you need to have some way to reference that the selected card was clicked on, with this reference we can decide whether the card is selected and if yes then change the color according to our preference.
In the following example, I am more or less using the same card widget template that you stated in the question, then I am using the ListView.builder
to render five cards, each having the same functionality.
Whenever the call button is pressed, the corresponding index
of that specific card is assigned to the state selectedIndex
and from this, we can assign the color to the selected Card.
Here is the full example:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int selectedIndex;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Padding(
padding: const EdgeInsets.only(top: 8.0),
child: ListView.builder(
itemCount: 5,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Card(
margin: EdgeInsets.fromLTRB(20.0, 6.0, 20.0, 0.0),
color: index == selectedIndex
? Colors.amberAccent
: Colors.brown[30],
child: ListTile(
isThreeLine: true,
title: Row(children: <Widget>[
Container(
child: Text("Some Text"),
alignment: Alignment.topLeft,
),
Spacer(),
Container(
child: Text("Some Text"),
alignment: Alignment.topRight,
),
]),
subtitle: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Some Text"),
])),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
GestureDetector(
onTap: () {
setState(() {
selectedIndex = index;
});
},
onLongPress: () => print("Long Press: Call"),
child: Padding(
padding: EdgeInsets.all(16.0),
child: Icon(
Icons.call,
size: 20.0,
color: Colors.green,
),
),
),
],
),
),
),
);
},
),
),
);
}
}
Upvotes: 2
Reputation: 6277
Keep track of the clicked item and pass the index of the list
int clickedItemPosition = -1;
bool isChecked(currentPosition) => clickedItemPosition == currentPosition;
Then in your card
//..
Card(
margin: EdgeInsets.fromLTRB(20.0, 6.0, 20.0, 0.0),
color: isChecked(index) ? Colors.blue : Colors.transparent,
//..
In Gesture detector update the clickedItemPosition
//...
GestureDetector(
onTap: () => setState(() => clickedItemPosition = index),
//..
Upvotes: 1