SwipeTo icon indicating copy to clipboard operation
SwipeTo copied to clipboard

SwipeTo interferes with vertical scrolling after swipe – especially on child widget

Open AnkitFlutterDev opened this issue 7 months ago • 0 comments

I’m using the swipe_to: ^1.0.6 package and noticed an issue when displaying multiple SwipeTo widgets (e.g., 100 messages in a list). After a onLeftSwipe or onRightSwipe animation is triggered, vertical scrolling becomes very difficult when trying to scroll by dragging on the SwipeTo child itself.

If I scroll outside the SwipeTo area (e.g., between the child widgets), scrolling works perfectly fine. This strongly suggests that the swipe gesture detection is still capturing touch input and not releasing it cleanly after the animation completes.

Code Snippet:

import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:gap/gap.dart'; import 'package:swipe_to/swipe_to.dart'; import '../../core/constants/constants.dart';

class ChatsView extends StatefulWidget { const ChatsView({super.key});

@override State<ChatsView> createState() => _ChatsViewState(); }

class _ChatsViewState extends State<ChatsView> { List<Map<String, dynamic>> messages = [ {'byMe': true, 'message': "What time?"}, {'byMe': false, 'message': "Need any help?"}, {'byMe': true, 'message': "Thank you so much!"}, {'byMe': false, 'message': "Happy birthday!"}, {'byMe': true, 'message': "Happy birthday!"}, {'byMe': false, 'message': "Works for me."}, {'byMe': true, 'message': "Works for me."}, {'byMe': false, 'message': "Sure, where shall we go?"}, {'byMe': true, 'message': "Sorry I'm late."}, {'byMe': false, 'message': "Sounds good!"}, {'byMe': true, 'message': "Thanks!"}, {'byMe': false, 'message': "Good morning!"}, {'byMe': true, 'message': "Did you watch the game last night?"}, {'byMe': false, 'message': "Just sent it to your email."}, {'byMe': true, 'message': "Okay, will do."}, {'byMe': false, 'message': "See you then!"}, {'byMe': true, 'message': "Great job on the presentation!"}, {'byMe': false, 'message': "Okay, will do."}, {'byMe': true, 'message': "Thank you so much!"}, {'byMe': false, 'message': "Okay, will do."}, {'byMe': true, 'message': "I'm good, thanks."}, {'byMe': false, 'message': "Good morning!"}, {'byMe': true, 'message': "Hello, how are you?"}, {'byMe': false, 'message': "Hello, how are you?"}, {'byMe': true, 'message': "Thanks, appreciate it."}, {'byMe': false, 'message': "What time?"}, {'byMe': true, 'message': "Talk to you later."}, {'byMe': false, 'message': "I'm good, thanks."}, {'byMe': true, 'message': "Want to grab lunch?"}, {'byMe': false, 'message': "Good night!"}, {'byMe': true, 'message': "Sure, where shall we go?"}, {'byMe': false, 'message': "Thank you so much!"}, {'byMe': true, 'message': "Hello, how are you?"}, {'byMe': false, 'message': "Let's try that new place."}, {'byMe': true, 'message': "No, I missed it. Who won?"}, {'byMe': false, 'message': "Let’s catch up soon."}, {'byMe': true, 'message': "Call me when you're free."}, {'byMe': false, 'message': "Works for me."}, {'byMe': true, 'message': "Want to grab lunch?"}, {'byMe': false, 'message': "No problem."}, {'byMe': true, 'message': "Sorry I'm late."}, {'byMe': false, 'message': "Happy birthday!"}, {'byMe': true, 'message': "Okay, will do."}, {'byMe': false, 'message': "Need any help?"}, {'byMe': true, 'message': "Works for me."}, {'byMe': false, 'message': "See you then!"}, {'byMe': true, 'message': "Works for me."}, {'byMe': false, 'message': "Works for me."}, {'byMe': true, 'message': "Sure, where shall we go?"}, {'byMe': false, 'message': "Yes! It was amazing!"}, {'byMe': true, 'message': "Not much, just working."}, {'byMe': false, 'message': "What's up?"}, {'byMe': true, 'message': "Works for me."}, {'byMe': false, 'message': "Yes! It was amazing!"}, {'byMe': true, 'message': "Good morning!"}, {'byMe': false, 'message': "Thank you so much!"}, {'byMe': true, 'message': "Need any help?"}, {'byMe': false, 'message': "Thanks!"}, {'byMe': true, 'message': "Hello, how are you?"}, {'byMe': false, 'message': "Sounds good!"}, {'byMe': true, 'message': "Hello, how are you?"}, {'byMe': false, 'message': "Not much, just working."}, {'byMe': true, 'message': "Works for me."}, {'byMe': false, 'message': "How about 3 PM?"}, {'byMe': true, 'message': "Not much, just working."}, {'byMe': false, 'message': "Happy birthday!"}, {'byMe': true, 'message': "Did you watch the game last night?"}, {'byMe': false, 'message': "Sounds good!"}, {'byMe': true, 'message': "Good night!"}, {'byMe': false, 'message': "Don't worry about it."}, {'byMe': true, 'message': "Team A won in the last minute."}, {'byMe': false, 'message': "Happy birthday!"}, {'byMe': true, 'message': "Hello, how are you?"}, {'byMe': false, 'message': "I am fine, how are you?"}, {'byMe': true, 'message': "I'm stuck in traffic."}, {'byMe': false, 'message': "See you then!"}, {'byMe': true, 'message': "No problem."}, {'byMe': false, 'message': "Talk to you later."}, {'byMe': true, 'message': "What time?"}, {'byMe': false, 'message': "How about 3 PM?"}, {'byMe': true, 'message': "Need any help?"}, {'byMe': false, 'message': "Good morning!"}, {'byMe': true, 'message': "Good night!"}, {'byMe': false, 'message': "Not much, just working."}, {'byMe': true, 'message': "Hello, how are you?"}, {'byMe': false, 'message': "Absolutely!"}, {'byMe': true, 'message': "No, I missed it. Who won?"}, {'byMe': false, 'message': "How's the project going?"}, {'byMe': true, 'message': "Take your time."}, {'byMe': false, 'message': "Sounds good!"}, {'byMe': true, 'message': "Happy birthday!"}, {'byMe': false, 'message': "Can you send me the report?"}, {'byMe': true, 'message': "I'm good, thanks."}, {'byMe': false, 'message': "I am fine, how are you?"}, {'byMe': true, 'message': "No, I missed it. Who won?"}, {'byMe': false, 'message': "Works for me."}, {'byMe': true, 'message': "Don't worry about it."}, {'byMe': false, 'message': "Let's meet tomorrow."}, {'byMe': true, 'message': "Happy birthday!"}, {'byMe': false, 'message': "Can you send me the report?"}, {'byMe': true, 'message': "Team A won in the last minute."}, {'byMe': false, 'message': "I am fine, how are you?"}, {'byMe': true, 'message': "Sure, where shall we go?"}, {'byMe': false, 'message': "Happy birthday!"}, {'byMe': true, 'message': "Unbelievable!"}, {'byMe': false, 'message': "Team A won in the last minute."}, {'byMe': true, 'message': "No, I missed it. Who won?"}, {'byMe': false, 'message': "Thank you so much!"}, {'byMe': true, 'message': "I'm good, thanks."}, {'byMe': false, 'message': "Thank you so much!"}, {'byMe': true, 'message': "Thanks, appreciate it."}, {'byMe': false, 'message': "It's almost done."}, {'byMe': true, 'message': "Can you send me the report?"}, {'byMe': false, 'message': "Yes! It was amazing!"}, {'byMe': true, 'message': "Yes! It was amazing!"}, {'byMe': false, 'message': "Thanks!"}, {'byMe': true, 'message': "Not much, just working."}, {'byMe': false, 'message': "Sorry I'm late."}, {'byMe': true, 'message': "No problem."}, {'byMe': false, 'message': "Not much, just working."}, ]; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), body: ListView.separated( physics: const BouncingScrollPhysics(), reverse: true, padding: EdgeInsets.all(20), itemBuilder: (context, index) { final msg = messages[index]; bool isByMe = msg['byMe'] == true; return Row( // mainAxisSize: MainAxisSize.min, // mainAxisAlignment: isByMe ? MainAxisAlignment.end : MainAxisAlignment.start, children: [ SwipeTo( key: UniqueKey(), iconOnLeftSwipe: Icons.arrow_forward, iconOnRightSwipe: Icons.arrow_back, onRightSwipe: (details) { log("\n Left Swipe Data --> $index"); }, onLeftSwipe: null, animationDuration: Duration(milliseconds: 100), swipeSensitivity: 20, child: Container( padding: EdgeInsets.all(30), decoration: BoxDecoration(color: primary, borderRadius: BorderRadius.circular(5)), child: Text(msg['message'], style: whiteSemiBold14), ), ), ], ); }, separatorBuilder: (context, index) => Gap(0), itemCount: messages.length, ), ); } }

Steps to Reproduce: 1. Create a ListView or SingleChildScrollView with ~100 SwipeTo wrapped messages. 2. Swipe a message to the left or right. 3. Try to scroll vertically by dragging on the same message’s widget. 4. Scrolling becomes unresponsive or very difficult. 5. Now try scrolling by dragging between the messages (outside the widget) – it works as expected.

Expected Behavior: Vertical scrolling should resume smoothly after the swipe animation finishes — even when dragging directly over the child widget of SwipeTo.

Environment: • Flutter version: Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel stable, 3.32.2, on macOS 15.3.2 24D81 darwin-arm64, locale en-IN) [✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0) [✓] Xcode - develop for iOS and macOS (Xcode 16.3) [✓] Chrome - develop for the web [✓] Android Studio (version 2024.2) [✓] VS Code (version 1.100.3) [✓] Connected device (4 available) [✓] Network resources • Package version: latest swipe_to: ^1.0.6 • Platform: Android & iOS • Tested on: [e.g. Pixel 6, iPhone 16 Pro Mx]

// here is the example video

https://github.com/user-attachments/assets/2b8263c4-cbbf-417c-ace3-defecbf5016b

AnkitFlutterDev avatar Jun 14 '25 10:06 AnkitFlutterDev