Is there a way to make a conditional rebuild of a widget

Issue

I am trying to recreate the robinhood number_change animation slide

enter image description here
enter image description here

Since I want to run the animation every time the state number changes, I thought using a State provider would help.

I am currently using Redux.

I am using animatedList to add and remove digits.

I made every digit a list of 1-9 vertical digits to achieve that slide up and down slide, but now I am bit stuck on how to only rebuild the digit that changed.

even though there is distinct: true they are all connected to the same store.

My widget container looks like this

class NumberColViewContainer extends StatelessWidget {
  /// A bool to indicate that you have passed a set of 3 digits and starting a new one
  final bool comma;

  /// The [TextStyle] of the number
  final TextStyle textStyle;
  // The [Duration] the animation will take to slide the number into place
  final Duration duration;
  // The curve that is used during the animation
  final Curve curve;

  NumberColViewContainer(
      {@required this.textStyle,
      @required this.duration,
      this.comma = false,
      @required this.curve});
  @override
  Widget build(BuildContext context) {
    return StoreConnector<AppState, _ViewModel>(
      builder: (context, vm) {
        return NumberColView(
          animateTo: vm.position,
          textStyle: textStyle,
          duration: duration,
          curve: curve,
          comma: comma
        );
      },
      converter: _ViewModel.fromStore,
      distinct: true,
    );
  }
}

class _ViewModel {
  _ViewModel({
    this.position,
    // this.store
  });

  final int  position;
  // final Store<AppState> store;

  static _ViewModel fromStore(Store<AppState> store) {
    return _ViewModel(
      position: store.state.numberSlideEpicPositionState.position,
      // store: store,
    );
  }
}

My NumberColView(list digit) to this

class NumberColView extends StatefulWidget {
  final int animateTo;
  final bool comma;
  final TextStyle textStyle;
  final Duration duration;
  final Curve curve;

  NumberColView(
      {@required this.animateTo,
      @required this.textStyle,
      @required this.duration,
      this.comma = false,
      @required this.curve})
      : assert(animateTo != null && animateTo >= 0 && animateTo < 10);

  @override
  _NumberColState createState() => _NumberColState();
}

class _NumberColState extends State<NumberColView>
    with SingleTickerProviderStateMixin {
  ScrollController _scrollController;

  double _elementSize = 0.0;

  @override
  void initState() {
    super.initState();
    _scrollController = new ScrollController();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _elementSize = _scrollController.position.maxScrollExtent / 10;
      setState(() {});

      _scrollController.animateTo(_elementSize * widget.animateTo,
          duration: widget.duration, curve: widget.curve);
    });
  }


@override
  void didUpdateWidget(NumberColView oldWidget) {
    if (oldWidget.animateTo != widget.animateTo) {
      _scrollController.animateTo(
          _elementSize * widget.animateTo,
          duration: widget.duration,
          curve: widget.curve);
    }

    super.didUpdateWidget(oldWidget);
  }
  @override
  Widget build(BuildContext context) {
    // print(widget.animateTo);
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        IgnorePointer(
          child: ConstrainedBox(
            constraints: BoxConstraints(maxHeight: _elementSize),
            child: SingleChildScrollView(
              controller: _scrollController,
              child: Column(
                children: List.generate(10, (position) {
                  return Text(position.toString(), style: widget.textStyle);
                }),
              ),
            ),
          ),
        ),
        widget.comma
            ? Container(
                child: Text(', ',
                    style:
                        TextStyle(fontSize: 16, fontWeight: FontWeight.bold)))
            : Container(),
      ],
    );
  }
}

something tells me there a way to achieve the effect without my approach but I couldn’t find one so if one does know a easier other way please share

Solution

Here , just use a setState function .
This function notify the framework that the internal state of this object has changed.

Simply use a statefulWidget.

Example of use:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  var value = 0;
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(
            title: Text('Flutter is Awesome'),
          ),
          body: Column(
            children: [
              Text('The new value : $value'),
              OutlinedButton(
                onPressed: () {
                  setState(() { 
                    value++; // do your change here 
                  });
                },
                child: Text('Tap to increase'))
            ],
          )),
    );
  }
}

Don’t forget to do Hot restart to make sure it will work . Hope it will useful

Answered By – Kab Agouda

Answer Checked By – Willingham (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *