I am trying to recreate the robinhood number_change animation slide
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
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