I’m trying to develop a chat application where users can "like" messages by double tapping a message. I want the heart icon to appear at the top right of the card. For reference, I’m sort of going off of how iMessage reactions look like.
The problem is that the corner of the icon is being clipped by the container constraints and I can’t figure out how to not make it look like this:
class ChatBubble extends StatefulWidget {
final String? messageText;
final DateTime? timeStamp;
// I want to use this as a way to identify individual messages
final String? messageId;
final bool? isSelf;
bool? isLiked;
ChatBubble(
{super.key,
required this.messageText,
required this.isSelf,
this.isLiked = false,
this.timeStamp,
this.messageId});
@override
State<ChatBubble> createState() => _ChatBubbleState();
}
class _ChatBubbleState extends State<ChatBubble> {
@override
Widget build(BuildContext context) {
return Align(
alignment: !widget.isSelf! ? Alignment.centerLeft : Alignment.centerRight,
child: Padding(
padding: !widget.isSelf!
? EdgeInsets.only(left: AppPadding.globalSidePadding.scale(context))
: EdgeInsets.only(
right: AppPadding.globalSidePadding.scale(context)),
child: GestureDetector(
onDoubleTap: () {
if (widget.isSelf == false) {
setState(() {
widget.isLiked ??= false;
widget.isLiked = !widget.isLiked!;
});
}
},
child: LayoutBuilder(builder: (context, constraints) {
return Padding(
padding: EdgeInsets.only(
top: AppPadding.transactionCardTopPadding.scale(context)),
child: Stack(
children: [
Card(
color: !widget.isSelf! ? Colors.white : AppColors.pink,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(
AppNums.globalElevatedButtonBorderRadius))),
child: Container(
constraints: BoxConstraints(
maxWidth: constraints.maxWidth * 0.7),
child: Padding(
padding: EdgeInsets.symmetric(
vertical: AppPadding.cardTopPadding
horizontal: AppPadding.chatMessageCardSidePadding
child: Text(widget.messageText!,
style: Fonts.notoSansSerif
.copyWith(
fontSize: 10,
fontWeight: FontWeight.normal,
color: !widget.isSelf!
? Colors.black
: Colors.white)
),
),
),
),
if (widget.isLiked == true)
Positioned(
top: -5,
right: -5,
child: LikedMessage(
reactionCameFromSelf:
widget.isLiked! && !widget.isSelf!)),
],
),
);
}),
),
),
);
}
}
class LikedMessage extends StatelessWidget {
final bool? reactionCameFromSelf;
const LikedMessage({super.key, required this.reactionCameFromSelf});
@override
Widget build(BuildContext context) {
return CircleAvatar(
radius: 20,
backgroundColor: reactionCameFromSelf! ? Colors.grey : AppColors.pink,
foregroundColor: reactionCameFromSelf! ? AppColors.pink : Colors.white,
child: const Icon(Icons.favorite));
}
}
The tricky part here is that each bubble is wrapped in an Align
to control whether the cards show on the left or right side of the screen, depending on who sent the message.
I tried different combinations of using the Stack
widget, but again because technically the underlying widgets of each card span the entire width of the screen, the heart icon would appear way off the card.
Where am I going wrong here?
2
Answers
Set the
clipBehavior
property of theStack
toClip.none
.For this:
Use this: