hexsis_infinity_scroll_bloc 0.2.2
hexsis_infinity_scroll_bloc: ^0.2.2 copied to clipboard
BLoC/Cubit extension for hexsis_infinity_scroll with zero boilerplate and full scroll integration.
Hexsis Infinity Scroll - BLoC Extension #
Zero-boilerplate BLoC/Cubit integration with automatic scroll detection and state management.
Installation #
dependencies:
hexsis_infinity_scroll_bloc: ^0.2.2
Complete Example #
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hexsis_infinity_scroll_bloc/hexsis_infinity_scroll_bloc.dart';
// 1. Define your cubit (just implement fetchPage!)
class ProductCubit extends InfiniteScrollCubit<Product> {
@override
Future<List<Product>> fetchPage(int page) async {
return await api.getProducts(page: page, limit: 20);
}
}
// 2. Use the widget (that's it!)
class ProductListScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => ProductCubit(),
child: Scaffold(
appBar: AppBar(title: Text('Products')),
body: InfiniteScrollBlocListView<Product, ProductCubit>(
itemBuilder: (context, product, index) {
return ProductCard(product);
},
),
),
);
}
}
That's it! The widget automatically:
- ✅ Detects scroll threshold and calls
cubit.loadMore() - ✅ Shows loading indicator on initial load
- ✅ Shows error widget with retry button
- ✅ Shows empty state when no items
- ✅ Shows loading more indicator at bottom
- ✅ Handles pull-to-refresh
- ✅ Uses smart threshold (500px from bottom for long lists)
GridView Support #
InfiniteScrollBlocGridView<Product, ProductCubit>(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
),
itemBuilder: (context, product, index) => ProductCard(product),
)
Customization #
Custom UI Components #
InfiniteScrollBlocListView<Product, ProductCubit>(
itemBuilder: (context, product, index) => ProductCard(product),
// Custom builders
separatorBuilder: (context, index) => Divider(height: 1),
loadingBuilder: (context) => CustomLoadingWidget(),
errorBuilder: (context, error, retry) => CustomErrorWidget(error, retry),
emptyBuilder: (context) => CustomEmptyWidget(),
loadingMoreBuilder: (context) => CustomLoadingMoreWidget(),
)
Configuration #
InfiniteScrollBlocListView<Product, ProductCubit>(
itemBuilder: (context, product, index) => ProductCard(product),
config: InfiniteScrollConfig(
threshold: 0.9, // Load at 90% (small lists)
thresholdPixels: 300, // 300px from bottom (large lists)
thresholdBreakpoint: 3000, // Switch point
debounceMilliseconds: 200, // Faster response
enablePullToRefresh: true,
),
)
How It Works #
InfiniteScrollCubit #
Base cubit that handles all pagination logic:
abstract class InfiniteScrollCubit<T> extends Cubit<InfiniteScrollState<T>> {
// You implement this:
Future<List<T>> fetchPage(int page);
// Already implemented for you:
Future<void> loadPage(int page, {bool isRefresh});
Future<void> refresh();
Future<void> loadMore();
}
State managed automatically:
items- Current listcurrentPage- Page numberhasMore- More items availableisLoading,isLoadingMore,isRefreshingerror,stackTrace
Widget Integration #
The widget:
- Creates ScrollController
- Listens to scroll events
- Calculates smart threshold
- Calls
cubit.loadMore()at threshold - Uses BlocBuilder to rebuild on state changes
- Handles all UI states automatically
You write ~5 lines, get full infinite scroll! 🎉
Advanced Usage #
Manual Control #
// Access cubit directly if needed
BlocBuilder<ProductCubit, InfiniteScrollState<Product>>(
builder: (context, state) {
return Column(
children: [
Text('Loaded ${state.items.length} items'),
if (state.hasMore)
ElevatedButton(
onPressed: () => context.read<ProductCubit>().loadMore(),
child: Text('Load More'),
),
],
);
},
)
Error Handling #
class ProductCubit extends InfiniteScrollCubit<Product> {
@override
Future<List<Product>> fetchPage(int page) async {
try {
return await api.getProducts(page);
} catch (e) {
// Error automatically captured and shown in UI
rethrow;
}
}
}
Comparison #
Without this package:
// 60+ lines of boilerplate:
// - Manual state class
// - Manual loading states
// - Manual scroll detection
// - Manual threshold calculation
// - Manual error handling
// - Manual UI building
With this package:
// 5 lines total:
class ProductCubit extends InfiniteScrollCubit<Product> {
Future<List<Product>> fetchPage(int page) async => api.getProducts(page);
}
InfiniteScrollBlocListView<Product, ProductCubit>(
itemBuilder: (context, product, index) => ProductCard(product),
)
95% less code! 🚀
Reliability #
The cubit ignores fetch completions after it has been closed, preventing late async work from emitting into disposed state. Behavioral tests cover loading, pagination, errors, retries, lifecycle safety, and list/grid widget integration.
License #
MIT License - Copyright (c) 2025 Hexsis Enterprise LLC