I'm encountering an issue with the Slidable widget in my Flutter app, specifically related to swipe actions on Text Fields in iOS. The swipe action works fine on Android, but on iOS, it doesn't seem to work properly when I swipe on Text Fields.
When I try to swipe on a Text Field within a Slidable widget in iOS, the swipe action doesn't trigger. It seems that the Text Field is capturing the swipe gesture, and the Slidable action doesn't get invoked.
I've tried wrapping the Slidable widget around a Stack and using GestureDetector to capture swipe gestures, but the issue persists.
Here is the complete code
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:get/get.dart';
import 'app/modules/home/controllers/home_controller.dart';
import 'app/routes/app_pages.dart';
void main() {
runApp(
GetMaterialApp(
title: "Application",
initialRoute: AppPages.INITIAL,
getPages: AppPages.routes,
),
);
}
class HomeView extends GetView<HomeController> {
HomeView({Key? key}) : super(key: key);
final textTheme = ThemeData().textTheme;
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
GetBuilder<HomeController>(
builder: (controller) {
return ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: 1,
itemBuilder: (context, index) {
return _buildWorkoutLogEntryCard(
context,
);
},
);
},
),
],
)),
);
}
Widget _buildWorkoutLogEntryCard(
BuildContext context,) {
bool isSlidableOpen = true; // To control whether the Slidable is open
return Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
margin: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 8.0),
color: Colors.white,
surfaceTintColor: Colors.white,
shadowColor: Colors.white,
child: GestureDetector(
// GestureDetector to capture swipe gestures
onHorizontalDragUpdate: (details) {
if (details.delta.dx > 0) {
// Swiping right
isSlidableOpen = true;
print(true);
} else if (details.delta.dx < 0) {
// Swiping left
isSlidableOpen = false;
print(false);
}
controller.update();
},
child: Stack(
children: [
if (isSlidableOpen)
Slidable(
endActionPane: ActionPane(
motion: const StretchMotion(),
extentRatio: 0.6,
children: [
SlidableAction(
flex: 1,
backgroundColor: Colors.red,
onPressed: (context) {
// Handle action
},
icon: Icons.delete,
),
],
),
child:
Container(), // You can use an empty container as the child
),
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 10),
title: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(width: 5),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Flexible(
child: Padding(
padding: const EdgeInsets.only(right: 8.0),
child: Text(
"hello",
overflow: TextOverflow.visible,
textAlign: TextAlign.left,
style: textTheme.headlineMedium!.copyWith(
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
),
Icon(
FontAwesomeIcons.arrowLeft,
size: 15,
)
],
),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildWarmUpList(context,true),
_buildWarmUpList(context,false),
],
),
),
],
),
),
);
}
Widget _buildWarmUpList(BuildContext context, bool isWarmUp) {
return GetBuilder<HomeController>(
builder: (controller) {
List<TextEditingController> _weightcontrollers =
<TextEditingController>[];
List<TextEditingController> _repcontrollers = <TextEditingController>[];
return ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: 2,
itemBuilder: (context, index) {
_weightcontrollers.add(TextEditingController(
text: '0'
));
_repcontrollers
.add(TextEditingController(text: '0'));
return Slidable(
startActionPane: null,
endActionPane: ActionPane(
motion: const StretchMotion(),
extentRatio: 0.25,
children: [
SlidableAction(
backgroundColor: Colors.red,
icon: Icons.delete,
onPressed: (context) {
// isWarmUp
// ? controller.deleteWarmUpRow(entry, index)
// : controller.deleteSetRow(entry, index);
},
),
],
),
child: Column(
children: [
ListTile(
dense: true,
minVerticalPadding: 0,
contentPadding: EdgeInsets.zero,
leading: Container(
padding: const EdgeInsets.all(8.0),
width: 35,
height: 35,
decoration: const BoxDecoration(
color: Colors.white,
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.white,
offset: Offset(2, 2),
blurRadius: 10.0),
],
),
child: isWarmUp
? ColorFiltered(
colorFilter: const ColorFilter.mode(
Colors.black, BlendMode.srcIn),
child: Image.asset(
'assets/stretch.png',
height: 15,
width: 15,
))
: Align(
alignment: Alignment.center,
child: Text(
'${index + 1}',
style: textTheme.headlineMedium!.copyWith(
color: Colors.black,
fontWeight: FontWeight.bold,
),
))),
title: Container(
decoration: const BoxDecoration(
color: Colors.white,
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.white,
offset: Offset(2, 2),
blurRadius: 10.0),
],
),
child: Align(
alignment: Alignment.center,
child: Row(
children: [
const SizedBox(width: 30.0),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: 60,
child: TextFormField(
decoration: const InputDecoration(
isDense: true, suffixText: 'kg'),
controller: _weightcontrollers[index],
keyboardType: TextInputType.number,
textAlign: TextAlign.end,
onTap: () {
_weightcontrollers[index].selection =
TextSelection(
baseOffset: 0,
extentOffset:
_weightcontrollers[index]
.value
.text
.length);
},
onChanged: (value) {
// controller.updateWeight(
// row, double.tryParse(value) ?? 0);
},
),
),
],
),
),
const SizedBox(width: 30.0),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: 50,
child: TextFormField(
decoration: InputDecoration(
suffixText:
'reps',
),
controller: _repcontrollers[index],
onTap: () {
_repcontrollers[index].selection =
TextSelection(
baseOffset: 0,
extentOffset:
_repcontrollers[index]
.value
.text
.length);
},
keyboardType: TextInputType.number,
textAlign: TextAlign.right,
onChanged: (value) {
// controller.updateReps(
// row, int.tryParse(value) ?? 0);
},
),
),
],
),
),
const SizedBox(width: 30.0),
],
),
),
),
),
const Divider(
color: Colors.grey,
height: 1.0,
thickness: 0.25,
),
],
),
);
},
);
},
);
}
}
How can I make sure that the swipe action works on the entire Slidable widget, even if the user swipes on a Text Field?