Home > Net >  Animating LinearProgressIndicator within bloc pattern
Animating LinearProgressIndicator within bloc pattern

Time:12-10

I have a bloc which emits states that contain some progress value (0-100%). This value is to be displayed with LinearProgressIndicator. Updates may occur in chunks, meaning progress can jump from, say, 0% to 30% in a single step.

Below is a simple snippet to reproduce this behavior:

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

class StartProgressEvent {}

class ProgressState {
  final double progress;
  ProgressState(this.progress);
}

class ProgressBloc extends Bloc<StartProgressEvent, ProgressState> {
  ProgressBloc() : super(ProgressState(0)) {
    on<StartProgressEvent>(_startProgress);
  }

  void _startProgress(
    StartProgressEvent event,
    Emitter<ProgressState> emit,
  ) async {
    emit(ProgressState(0.1));
    await Future.delayed(const Duration(seconds: 3));

    emit(ProgressState(0.4));
    await Future.delayed(const Duration(seconds: 3));

    emit(ProgressState(0.7));
    await Future.delayed(const Duration(seconds: 3));

    emit(ProgressState(1.0));
  }
}

void main() {
  runApp(const DemoApp());
}

class DemoApp extends StatelessWidget {
  const DemoApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: BlocProvider<ProgressBloc>(
            create: (context) => ProgressBloc()..add(StartProgressEvent()),
            child: BlocBuilder<ProgressBloc, ProgressState>(
              builder: (context, state) => LinearProgressIndicator(value: state.progress),
            ),
          ),
        ),
      ),
    );
  }
}

This snippet shows the following indicator:

linear progress indicator

Instead of updating instantly, I want my indicator to animate ongoing changes, i.e. to update smoothly from its previous state to the current one.

I found this answer suggesting that we use TweenAnimationBuilder to animate LinearProgressIndicator but it implies that we know its current value which we don't.

In a broader sense this question is not limited to progress indicator. I believe it can be framed this way: how can we animate between two consecutive "states" of a widget (either stateless or stateful) within bloc architecture?

CodePudding user response:

You can try AnimatedFractionallySizedBox with your duration instead of LinearProgressIndicator

class DemoApp extends StatelessWidget {
  const DemoApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            BlocProvider<ProgressBloc>(
              create: (context) => ProgressBloc()..add(StartProgressEvent()),
              child: BlocBuilder<ProgressBloc, ProgressState>(
                  builder: (context, state) => AnimatedFractionallySizedBox(
                        duration: Duration(seconds: 3),
                        alignment: Alignment.centerLeft,
                        widthFactor: state.progress,
                        child: Container(
                          alignment: Alignment.centerLeft,
                          width: double.infinity,
                          height: 10,
                          color: Colors.blue,
                        ),
                      )

                  // LinearProgressIndicator(value: state.progress),
                  ),
            ),
          ],
        ),
      ),
    );
  }
}
  • Related