Last active
January 27, 2025 20:30
-
-
Save marcoredz/f88cdef264faaf8316e0c8a0487460c7 to your computer and use it in GitHub Desktop.
Bloc list performance playground
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import 'dart:math'; | |
| import 'package:flutter/material.dart'; | |
| import 'package:flutter_bloc/flutter_bloc.dart'; | |
| Color getRandomColor() { | |
| return Color((Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0); | |
| } | |
| void main() => runApp(MyApp()); | |
| class MyApp extends StatelessWidget { | |
| const MyApp({super.key}); | |
| @override | |
| Widget build(BuildContext context) => const MaterialApp(home: HomePage()); | |
| } | |
| class ColorItem { | |
| ColorItem({required this.index, required this.color, this.isLoading = false}); | |
| final int index; | |
| final Color color; | |
| final bool isLoading; | |
| @override | |
| bool operator ==(covariant ColorItem other) { | |
| if (identical(this, other)) return true; | |
| return other.index == index && | |
| other.color == color && | |
| other.isLoading == isLoading; | |
| } | |
| @override | |
| int get hashCode => index.hashCode ^ color.hashCode ^ isLoading.hashCode; | |
| ColorItem copyWith({ | |
| int? index, | |
| Color? color, | |
| bool? isLoading, | |
| }) { | |
| return ColorItem( | |
| index: index ?? this.index, | |
| color: color ?? this.color, | |
| isLoading: isLoading ?? this.isLoading, | |
| ); | |
| } | |
| } | |
| class ColorsState { | |
| ColorsState({required int size, List<ColorItem>? colors}) | |
| : colors = colors ?? | |
| List.generate(size, | |
| (index) => ColorItem(index: index, color: getRandomColor())); | |
| final List<ColorItem> colors; | |
| ColorsState copyWith({List<ColorItem>? colors}) { | |
| return ColorsState( | |
| size: colors?.length ?? this.colors.length, colors: colors); | |
| } | |
| @override | |
| bool operator ==(Object other) => false; | |
| @override | |
| int get hashCode => colors.hashCode; | |
| } | |
| class ColorsCubit extends Cubit<ColorsState> { | |
| ColorsCubit() : super(ColorsState(size: 20)); | |
| Future<void> toggle(int index) async { | |
| // Set loading state | |
| state.colors[index] = state.colors[index].copyWith(isLoading: true); | |
| print('$index: ${state.colors[index].isLoading}'); | |
| emit(state); | |
| await Future.delayed(const Duration(seconds: 1)); | |
| // Update color and unset loading state | |
| state.colors[index] = state.colors[index].copyWith( | |
| color: getRandomColor(), | |
| isLoading: false, | |
| ); | |
| print('$index: ${state.colors[index].isLoading}'); | |
| emit(state); | |
| } | |
| } | |
| class IndexCubit extends Cubit<int> { | |
| IndexCubit(int index) : super(index); | |
| } | |
| class HomePage extends StatelessWidget { | |
| const HomePage({super.key}); | |
| @override | |
| Widget build(BuildContext context) { | |
| return BlocProvider( | |
| create: (_) => ColorsCubit(), | |
| child: Scaffold(body: const _GridView()), | |
| ); | |
| } | |
| } | |
| class _GridView extends StatelessWidget { | |
| const _GridView(); | |
| @override | |
| Widget build(BuildContext context) { | |
| print('### _GridView build ###'); | |
| return GridView.builder( | |
| gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( | |
| crossAxisCount: 20, | |
| ), | |
| itemCount: context.select( | |
| (ColorsCubit cubit) => cubit.state.colors.length, | |
| ), | |
| itemBuilder: (_, index) { | |
| return _GridItem(index); | |
| }, | |
| ); | |
| } | |
| } | |
| class _GridItem extends StatelessWidget { | |
| final int index; | |
| const _GridItem(this.index); | |
| @override | |
| Widget build(BuildContext context) { | |
| final colorItem = context.select( | |
| (ColorsCubit cubit) => cubit.state.colors[index], | |
| ); | |
| print('### GridItem build $index - ${colorItem.color} ###'); | |
| return GestureDetector( | |
| onTap: () => context.read<ColorsCubit>().toggle(index), | |
| child: colorItem.isLoading | |
| ? const Center( | |
| child: SizedBox( | |
| width: 24, | |
| height: 24, | |
| child: CircularProgressIndicator(strokeWidth: 2), | |
| ), | |
| ) | |
| : ColoredBox(color: colorItem.color), | |
| ); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment