tap_on_scroll 0.0.3 copy "tap_on_scroll: ^0.0.3" to clipboard
tap_on_scroll: ^0.0.3 copied to clipboard

Flutter package for reliable tap events on scrollable widgets even during scroll motion. Perfect for lists, grids, and slivers.

tap_on_scroll #

pub package license

A Flutter package that solves the common issue of missed tap events on items while scrolling. tap_on_scroll intercepts tap events during scroll interactions and reliably dispatches them to registered tappable areas in both regular and sliver-based layouts.

๐Ÿ“ฑ Demo #

Here's how tap_on_scroll solves the problem of unresponsive taps during scrolling:

tap_on_scroll demo

Demonstration of tap_on_scroll functionality showing how it ensures reliable tap detection even during active scrolling.

๐Ÿš€ Features #

  • Reliable Tap Detection: Prevents missed tap events while scrolling
  • Tappable Areas: Easily designate areas that should respond to tap events using TappableArea
  • Seamless Integration: Works with existing scrollable widgets
  • Simple API: Minimal setup to enhance tap responsiveness in your Flutter apps
  • Zero Dependencies: Only depends on Flutter core libraries
  • Perfect for Pinned Headers: Makes PinnedHeaderSlivers consistently tappable even during scroll

๐Ÿ“‹ Installation #

Add this to your package's pubspec.yaml file:

dependencies:
  tap_on_scroll: ^0.0.3

Or install it directly from the command line:

flutter pub add tap_on_scroll

๐ŸŽฏ Usage #

Wrap your scrollable widget with TapInterceptor and wrap your tappable items with TappableArea:

Basic Example #

import 'package:flutter/material.dart';
import 'package:tap_on_scroll/tap_on_scroll.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final ScrollController _scrollController = ScrollController();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'tap_on_scroll Demo',
      home: Scaffold(
        appBar: AppBar(
          title: const Text('tap_on_scroll Demo'),
        ),
        body: TapInterceptor(
          child: ListView.builder(
            controller: _scrollController,
            itemCount: 20,
            itemBuilder: (context, index) {
              return TappableArea(
                onTap: () => print('Tapped item $index'),
                child: ListTile(
                  title: Text('Item $index'),
                ),
              );
            },
          ),
        ),
      ),
    );
  }
}

Using with GridView #

TapInterceptor(
  child: GridView.builder(
    gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
      crossAxisCount: 2,
    ),
    itemCount: 20,
    itemBuilder: (context, index) {
      return TappableArea(
        onTap: () => print('Tapped grid item $index'),
        child: Card(
          child: Center(
            child: Text('Grid Item $index'),
          ),
        ),
      );
    },
  ),
)

Using with Pinned Headers (SliverAppBar) #

This is an especially useful application of tap_on_scroll, as pinned headers often lose tap responsiveness during scroll:

TapInterceptor(
  child: CustomScrollView(
    slivers: [
      // Pinned SliverAppBar with TappableArea for title and actions
      SliverAppBar(
        pinned: true,
        expandedHeight: 150.0,
        // Make the title tappable
        flexibleSpace: FlexibleSpaceBar(
          title: TappableArea(
            onTap: () => print('Pinned header title tapped!'),
            child: Text('Pinned Header'),
          ),
          background: Image.network(
            'https://example.com/image.jpg',
            fit: BoxFit.cover,
          ),
        ),
        // CRUCIAL USE CASE: Make action buttons tappable during scroll
        actions: [
          TappableArea(
            onTap: () => print('Search button tapped during scroll!'),
            child: IconButton(
              icon: Icon(Icons.search),
              onPressed: () {}, // This might not work reliably during scroll
            ),
          ),
          TappableArea(
            onTap: () => print('Favorite button tapped during scroll!'),
            child: IconButton(
              icon: Icon(Icons.favorite),
              onPressed: () {}, // This might not work reliably during scroll
            ),
          ),
          TappableArea(
            onTap: () => print('Menu button tapped during scroll!'),
            child: IconButton(
              icon: Icon(Icons.more_vert),
              onPressed: () {}, // This might not work reliably during scroll
            ),
          ),
        ],
      ),

      // Section header that remains tappable
      SliverPersistentHeader(
        pinned: true,
        delegate: YourHeaderDelegate(
          child: TappableArea(
            onTap: () => print('Section header tapped!'),
            child: Container(
              color: Colors.teal,
              child: Center(
                child: Text('Always Tappable Section Header'),
              ),
            ),
          ),
        ),
      ),

      // Regular list items
      SliverList(
        delegate: SliverChildBuilderDelegate(
          (context, index) {
            return TappableArea(
              onTap: () => print('Item $index tapped'),
              child: ListTile(title: Text('Item $index')),
            );
          },
          childCount: 50,
        ),
      ),
    ],
  ),
)

๐Ÿ” How It Works #

TapInterceptor intercepts tap events and checks if a tap falls within any registered tappable areas. When a tap is detected:

  1. It identifies which TappableArea was tapped
  2. Dispatches the tap event to the appropriate area
  3. Triggers the onTap callback you provided

This approach ensures that taps are reliably detected even during scroll momentum, solving a common issue with pinned headers and other interactive elements during scrolling.

Implementation Details #

The package is designed with simplicity in mind:

  • TapInterceptor doesn't require a scroll controller - it works automatically with any scrollable widget
  • TappableArea registers itself with the nearest TapInterceptor ancestor
  • The tap detection works by computing the global position of each tappable area and checking if tap events fall within that area
  • Perfect for pinned headers because it resolves the conflict between scroll gestures and tap interactions that often causes unresponsiveness

๐Ÿงช Example #

Check out the example app for a complete implementation showing how to use tap_on_scroll in a real-world scenario, including a dedicated example of making pinned headers tappable during scrolling.

๐Ÿค Contributing #

Contributions are welcome! If you encounter issues or have suggestions for improvements, please:

  1. Open an issue describing the bug or feature request
  2. Submit a pull request with your changes
  3. Ensure your code follows the project's coding standards

๐Ÿ“„ License #

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿ“ฑ Compatibility #

  • Dart SDK: ^3.7.0
  • Flutter: ">=1.17.0"

๐Ÿ‘ฅ Authors #

  • Adnan Aljafarey - Initial work - GitHub

If you find this package helpful, please consider giving it a star โญ on GitHub!

13
likes
160
points
48
downloads

Publisher

unverified uploader

Weekly Downloads

Flutter package for reliable tap events on scrollable widgets even during scroll motion. Perfect for lists, grids, and slivers.

Homepage
Repository (GitHub)
View/report issues

Topics

#scrolling #tap-while-scrolling #tappable-scroll #tappable #tap-on-scroll

Documentation

Documentation
API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on tap_on_scroll