Rive's stateMachine with TextFiled - flutter

I Like to create animation that will follow the TextField text, here is video from
Flutter YouTube.
Now how can I follow the Target.
Here is My rive file on rive.app or GitHub and Design.

We need a StateMachineController and SMIInput<double> that will be responsible to follow the text.
Result
OutPutVideo
Result with Slider
You can follow the GitHub Repository or
class TextFieldWithRive extends StatefulWidget {
TextFieldWithRive({Key? key}) : super(key: key);
#override
_TextFieldWithRiveState createState() => _TextFieldWithRiveState();
}
class _TextFieldWithRiveState extends State<TextFieldWithRive> {
StateMachineController? controller;
SMIInput<double>? valueController;
Artboard? _riveArtboard;
double sliderVal = 0.0;
/// change value based on size>Width
final double strengthOverTextFiled = 1.5;
final TextEditingController textEditingController = TextEditingController();
#override
void initState() {
super.initState();
rootBundle.load("rives/eyeMovement.riv").then((value) async {
final file = RiveFile.import(value);
final artboard = file.mainArtboard;
controller = StateMachineController.fromArtboard(artboard, "eyeMovement");
if (controller != null) {
print("got state");
setState(() {
artboard.addController(controller!);
valueController = controller!.findInput('moevement_controll');
controller!.inputs.forEach((element) {
print(element.name);
});
});
}
_riveArtboard = artboard;
});
///* eye controll with textFiled
textEditingController.addListener(() {
print(textEditingController.text);
if (valueController != null) {
valueController!.value =
textEditingController.text.length * strengthOverTextFiled;
}
});
}
#override
void dispose() {
textEditingController.removeListener(() {});
textEditingController.dispose();
controller!.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: LayoutBuilder(
builder: (context, constraints) => Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
height: constraints.maxWidth * .5,
width: constraints.maxWidth * .5,
child: _riveArtboard == null
? CircularProgressIndicator()
: Rive(
artboard: _riveArtboard!,
),
),
SizedBox(
width: constraints.maxWidth * .8,
child: TextField(
controller: textEditingController,
decoration: InputDecoration(hintText: "keep typing"),
),
),
],
),
),
),
);
}
}

Related

Flutter - Lottie controller loop breaks when playing the animation twice

I coded a simple Lottie animation state manager. From a pool of lottie-json files, each containing also a probability to play, I select one and set the _index to play that file.
However, if randomly the same file will that played before will be played again, the loop just stops and I have to restart... I depict a minimal example of my code here:
class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
final Random rnd = Random();
int _index = 0;
late BechtoAnimation _animation;
late final AnimationController _controller;
#override
void initState() {
super.initState();
_controller = AnimationController(vsync: this)
..addStatusListener((status) {
if(status == AnimationStatus.completed){
setState(() {
int i = 0;
double p = rnd.nextDouble();
double cumulativeProbability = 0.0;
for(AnimationLoop animationLoop in _animation.loop){
cumulativeProbability += animationLoop.probability;
if (p <= cumulativeProbability) {
_index = i;
break;
}
i++;
}
});
}
});
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext buildContext) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
BlocBuilder<MyCubit, MyState>(
builder: (context, state) {
if(state is AnimationLoadedFailure){
return Text(state.toString(), style: const TextStyle(color: Colors.blueGrey));
}else if(state is AnimationLoadedSuccess){
_animation = state.animation;
return SizedBox(
width: 200,
height: 200,
child: Lottie.asset(
state.animation.loop.elementAt(_index).fileName,
width: 200,
height: 200,
fit: BoxFit.fill,
controller: _controller,
onLoaded: (composition){
_controller.duration = composition.duration;
_controller.reset();
_controller.forward();
}
),
);
}else{
return Text(state.toString(), style: const TextStyle(color: Colors.blueGrey));
}
}
)
],
),
));
}
}
As you can see, I select the new animation when the old one is finished via the StatusListener. However, when its the same, everything just stops... Any idea?
Flutter version is: 3.3.0 and my Dart version is 2.18.0

flutter - futurebuilder doesn't load until textformfield is clicked

My Bad
It was problem with my future function HashtagService().getSuggestion('topic'); returning empty List before data is properly loaded. EditTopicPage didn't have any problem.
Original Question
I have text form field inside futurebuilder. When I first open page, future is not loaded. When I click on text field to enter something, future is loaded.
I want future to be loaded when the page is first opened.
class EditTopicPage extends StatefulWidget {
const EditTopicPage({required UserProfileModel userProfile, Key? key}) : _userProfile = userProfile, super(key: key);
final UserProfileModel _userProfile;
#override
_EditTopicPageState createState() => _EditTopicPageState();
}
class _EditTopicPageState extends State<EditTopicPage> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final TextEditingController _controller = TextEditingController();
List<String> _hashList = [];
List<String> _suggestionList = [];
late final Future<List<String>> _future;
bool _disabled = true;
final RegExp hashRegex = RegExp(r'^[a-z|A-Z|ㄱ-ㅎ|ㅏ-ㅣ|가-힣|ㆍ|ᆢ]*$');
#override
void initState() {
_future = HashtagService().getSuggestion('topic');
_hashList = widget._userProfile.topic.cast<String>();
super.initState();
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
UserProfileService _userProfileService = UserProfileService();
final Size size = MediaQuery.of(context).size;
return Scaffold(
backgroundColor: Colors.white,
appBar: TopBar(pageTitle: "관심 대화 주제 수정", context: context),
body: ListView(
padding: EdgeInsets.all(16.sp),
children: [
FutureBuilder(
future: _future,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
_suggestionList = List<String>.from(snapshot.data.reversed);
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleLineTextFormField(
controller: _controller,
hintText: '어떤 주제로 대화하고 싶으신가요?',
onChanged: (value) {
if (value.length > 1) {
var lastChar = value.substring(
value.length - 1);
if (!hashRegex.hasMatch(lastChar)) {
var newHash = value.substring(
0, value.length - 1);
if (!_hashList.contains(newHash)) {
setState(() {
_hashList.add(newHash);
_disabled = _hashList.isEmpty || (_hashList.length > 3);
});
}
_controller.clear();
}
} // else if (_expHash.length == 3 && value.isNotEmpty) {
_formKey.currentState!.validate();
},
validator: (value) {
if (!hashRegex.hasMatch(value!)) {
return '\u26a0 한글, 영문만 가능해요';
}
return null;
}
),
DefaultSpacing(),
Row(
children: [
Text('추천 : ',
style: TextStyle(
fontSize: 10.sp,
color: Colors.grey[800],
),
),
Wrap(
spacing: 6.0,
runSpacing: 6.0,
children: _suggestionList.map((suggestion) =>
HashtagSuggestionChip(
suggestion: suggestion,
type: 'topic',
onPressed: () {
if (!_hashList.contains(suggestion)) {
setState(() {
_hashList.add(suggestion);
_disabled = _hashList.isEmpty || (_hashList.length > 3);
});
}
},
)).toList(),
),
],
),
DefaultSpacing(),
Wrap(
spacing: 6.0,
runSpacing: 6.0,
children: _hashList.map((hashtag) =>
HashtagChip(
hashtag: hashtag,
type: 'topic',
onDelete: () {
setState(() {
_hashList.remove(hashtag);
_formKey.currentState!.validate();
_disabled = _hashList.isEmpty || (_hashList.length > 3);
});
},
)).toList()
),
]),
);
}
return CircularProgressIndicator();
}
),
],
),
floatingActionButton: FloatingSaveButton(context: context,
text: '저장',
width: size.width * 0.9,
disabled: _disabled,
onPressed: () async {
_userProfileService.updateTopicHashtag(hashList: _hashList);
Navigator.pop(context);
ScaffoldMessenger.of(context).showSnackBar(SaveSnackBar());
}),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
}
Result: when the page is first opened
Neither hashtag nor progress indicator is shown.
After text form field is selected
I searched similar questions in stackoverflow, but none of the answers solved my problem.
Try like this
#override
void initState() {
setState(() {
_future = HashtagService().getSuggestion('topic');
_hashList = widget._userProfile.topic.cast<String>();
});
super.initState();
}
so your _future is async so the widget will be loaded before loading the service

How to build in flutter [duplicate]

This question already has answers here:
How can I add a border to a widget in Flutter?
(18 answers)
Closed last year.
how to animate border around the square content.
This answer might be a little complicated for simple cases like this. Wish to have answer using paint. I am using Rive for this.
This rive file contains two states,
infinite loop
progress value 0-100
download and add on assets.
Check pub.dev to learn basic. To use this, we need StateMachineController
To lean basic, you can check rives-statemachine-with-textfiled and the complete project on GitHub
Rive Controller Widget on Gist
class RiveBorder extends StatefulWidget {
const RiveBorder({Key? key}) : super(key: key);
#override
_RiveBorderState createState() => _RiveBorderState();
}
class _RiveBorderState extends State<RiveBorder> {
StateMachineController? controller;
//progress value
SMIInput<double>? valueController;
// infinite loop
SMIInput<bool>? loopController;
Artboard? _riveArtboard;
_initRive() {
rootBundle.load("assets/new_file.riv").then((value) async {
final file = RiveFile.import(value);
final artboard = file.mainArtboard;
controller =
StateMachineController.fromArtboard(artboard, "State Machine 1");
if (controller != null) {
debugPrint("got state");
setState(() {
artboard.addController(controller!);
valueController = controller!.findInput('value');
loopController = controller!.findInput('loop');
// ignore: avoid_function_literals_in_foreach_calls
controller!.inputs.forEach((element) {
debugPrint(element.name);
});
});
}
_riveArtboard = artboard;
});
}
#override
void initState() {
_initRive();
super.initState();
}
#override
void dispose() {
controller?.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
const Text("loop"),
const SizedBox(
width: 10,
),
Switch(
value: loopController == null ? false : loopController!.value,
onChanged: (value) {
setState(() {
if (loopController != null) loopController!.value = value;
});
},
),
],
),
Slider(
value: valueController == null ? 0 : valueController!.value,
min: 0,
max: 100,
onChanged: (value) {
setState(() {
valueController != null ? valueController!.value = value : 0;
});
},
),
SizedBox(
height: 100,
width: 100,
child: Stack(
alignment: Alignment.center,
children: [
_riveArtboard == null
? const CircularProgressIndicator()
: Rive(
artboard: _riveArtboard!,
),
const Icon(
Icons.umbrella,
size: 77,
)
],
),
)
],
),
),
);
}
}

How to Set Textfield in flutter to accept only certain values specified from a list or variable in Flutter

I am working on a web app where users can post stuffs and make them more accessible by associating the posts with tags. so my idea is similar to stackoverflow's way of giving tags to posts, I am creating a Textfield with which will accept only few tags(string values) which I will create from a list and users can put them in their post. But I aint getting how to implement this as textfield has only few keyboardtypes... and I what I want to achieve is if I entered a value from a that list then it should act like a chip text(tag).
or Is there any other way to do this,
your help is appreciated,
thank you
Yes, there is. you can use the flutter_tagging package on the PUB
It has supports for Web
The gif below explains what you want to achieve
You can find an implementation of a Chip Input Field type widget here:
Latest: https://gist.github.com/slightfoot/c6c0f1f1baca326a389a9aec47886ad6
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
// See: https://twitter.com/shakil807/status/1042127387515858949
// https://github.com/pchmn/MaterialChipsInput/tree/master/library/src/main/java/com/pchmn/materialchips
// https://github.com/BelooS/ChipsLayoutManager
void main() => runApp(ChipsDemoApp());
class ChipsDemoApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primaryColor: Colors.indigo,
accentColor: Colors.pink,
),
home: DemoScreen(),
);
}
}
class DemoScreen extends StatefulWidget {
#override
_DemoScreenState createState() => _DemoScreenState();
}
class _DemoScreenState extends State<DemoScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Material Chips Input'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
decoration: const InputDecoration(hintText: 'normal'),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ChipsInput<AppProfile>(
decoration: InputDecoration(prefixIcon: Icon(Icons.search), hintText: 'Profile search'),
findSuggestions: _findSuggestions,
onChanged: _onChanged,
chipBuilder: (BuildContext context, ChipsInputState<AppProfile> state, AppProfile profile) {
return InputChip(
key: ObjectKey(profile),
label: Text(profile.name),
avatar: CircleAvatar(
backgroundImage: NetworkImage(profile.imageUrl),
),
onDeleted: () => state.deleteChip(profile),
onSelected: (_) => _onChipTapped(profile),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
);
},
suggestionBuilder: (BuildContext context, ChipsInputState<AppProfile> state, AppProfile profile) {
return ListTile(
key: ObjectKey(profile),
leading: CircleAvatar(
backgroundImage: NetworkImage(profile.imageUrl),
),
title: Text(profile.name),
subtitle: Text(profile.email),
onTap: () => state.selectSuggestion(profile),
);
},
),
),
),
],
),
);
}
void _onChipTapped(AppProfile profile) {
print('$profile');
}
void _onChanged(List<AppProfile> data) {
print('onChanged $data');
}
Future<List<AppProfile>> _findSuggestions(String query) async {
if (query.length != 0) {
return mockResults.where((profile) {
return profile.name.contains(query) || profile.email.contains(query);
}).toList(growable: false);
} else {
return const <AppProfile>[];
}
}
}
// -------------------------------------------------
const mockResults = <AppProfile>[
AppProfile('Stock Man', 'stock#man.com', 'https://d2gg9evh47fn9z.cloudfront.net/800px_COLOURBOX4057996.jpg'),
AppProfile('Paul', 'paul#google.com', 'https://mbtskoudsalg.com/images/person-stock-image-png.png'),
AppProfile('Fred', 'fred#google.com',
'https://media.istockphoto.com/photos/feeling-great-about-my-corporate-choices-picture-id507296326'),
AppProfile('Bera', 'bera#flutter.io',
'https://upload.wikimedia.org/wikipedia/commons/7/7c/Profile_avatar_placeholder_large.png'),
AppProfile('John', 'john#flutter.io',
'https://upload.wikimedia.org/wikipedia/commons/7/7c/Profile_avatar_placeholder_large.png'),
AppProfile('Thomas', 'thomas#flutter.io',
'https://upload.wikimedia.org/wikipedia/commons/7/7c/Profile_avatar_placeholder_large.png'),
AppProfile('Norbert', 'norbert#flutter.io',
'https://upload.wikimedia.org/wikipedia/commons/7/7c/Profile_avatar_placeholder_large.png'),
AppProfile('Marina', 'marina#flutter.io',
'https://upload.wikimedia.org/wikipedia/commons/7/7c/Profile_avatar_placeholder_large.png'),
];
class AppProfile {
final String name;
final String email;
final String imageUrl;
const AppProfile(this.name, this.email, this.imageUrl);
#override
bool operator ==(Object other) =>
identical(this, other) || other is AppProfile && runtimeType == other.runtimeType && name == other.name;
#override
int get hashCode => name.hashCode;
#override
String toString() {
return 'Profile{$name}';
}
}
// -------------------------------------------------
typedef ChipsInputSuggestions<T> = Future<List<T>> Function(String query);
typedef ChipSelected<T> = void Function(T data, bool selected);
typedef ChipsBuilder<T> = Widget Function(BuildContext context, ChipsInputState<T> state, T data);
class ChipsInput<T> extends StatefulWidget {
const ChipsInput({
Key key,
this.decoration = const InputDecoration(),
#required this.chipBuilder,
#required this.suggestionBuilder,
#required this.findSuggestions,
#required this.onChanged,
this.onChipTapped,
}) : super(key: key);
final InputDecoration decoration;
final ChipsInputSuggestions findSuggestions;
final ValueChanged<List<T>> onChanged;
final ValueChanged<T> onChipTapped;
final ChipsBuilder<T> chipBuilder;
final ChipsBuilder<T> suggestionBuilder;
#override
ChipsInputState<T> createState() => ChipsInputState<T>();
}
class ChipsInputState<T> extends State<ChipsInput<T>> implements TextInputClient {
static const kObjectReplacementChar = 0xFFFC;
Set<T> _chips = Set<T>();
List<T> _suggestions;
int _searchId = 0;
FocusNode _focusNode;
TextEditingValue _value = TextEditingValue();
TextInputConnection _connection;
String get text => String.fromCharCodes(
_value.text.codeUnits.where((ch) => ch != kObjectReplacementChar),
);
bool get _hasInputConnection => _connection != null && _connection.attached;
void requestKeyboard() {
if (_focusNode.hasFocus) {
_openInputConnection();
} else {
FocusScope.of(context).requestFocus(_focusNode);
}
}
void selectSuggestion(T data) {
setState(() {
_chips.add(data);
_updateTextInputState();
_suggestions = null;
});
widget.onChanged(_chips.toList(growable: false));
}
void deleteChip(T data) {
setState(() {
_chips.remove(data);
_updateTextInputState();
});
widget.onChanged(_chips.toList(growable: false));
}
#override
void initState() {
super.initState();
_focusNode = FocusNode();
_focusNode.addListener(_onFocusChanged);
}
void _onFocusChanged() {
if (_focusNode.hasFocus) {
_openInputConnection();
} else {
_closeInputConnectionIfNeeded();
}
setState(() {
// rebuild so that _TextCursor is hidden.
});
}
#override
void dispose() {
_focusNode?.dispose();
_closeInputConnectionIfNeeded();
super.dispose();
}
void _openInputConnection() {
if (!_hasInputConnection) {
_connection = TextInput.attach(this, TextInputConfiguration());
_connection.setEditingState(_value);
}
_connection.show();
}
void _closeInputConnectionIfNeeded() {
if (_hasInputConnection) {
_connection.close();
_connection = null;
}
}
#override
Widget build(BuildContext context) {
var chipsChildren = _chips
.map<Widget>(
(data) => widget.chipBuilder(context, this, data),
)
.toList();
final theme = Theme.of(context);
chipsChildren.add(
Container(
height: 32.0,
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(
text,
style: theme.textTheme.subhead.copyWith(
height: 1.5,
),
),
_TextCaret(
resumed: _focusNode.hasFocus,
),
],
),
),
);
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
//mainAxisSize: MainAxisSize.min,
children: <Widget>[
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: requestKeyboard,
child: InputDecorator(
decoration: widget.decoration,
isFocused: _focusNode.hasFocus,
isEmpty: _value.text.length == 0,
child: Wrap(
children: chipsChildren,
spacing: 4.0,
runSpacing: 4.0,
),
),
),
Expanded(
child: ListView.builder(
itemCount: _suggestions?.length ?? 0,
itemBuilder: (BuildContext context, int index) {
return widget.suggestionBuilder(context, this, _suggestions[index]);
},
),
),
],
);
}
#override
void updateEditingValue(TextEditingValue value) {
final oldCount = _countReplacements(_value);
final newCount = _countReplacements(value);
setState(() {
if (newCount < oldCount) {
_chips = Set.from(_chips.take(newCount));
}
_value = value;
});
_onSearchChanged(text);
}
int _countReplacements(TextEditingValue value) {
return value.text.codeUnits.where((ch) => ch == kObjectReplacementChar).length;
}
#override
void performAction(TextInputAction action) {
_focusNode.unfocus();
}
void _updateTextInputState() {
final text = String.fromCharCodes(_chips.map((_) => kObjectReplacementChar));
_value = TextEditingValue(
text: text,
selection: TextSelection.collapsed(offset: text.length),
composing: TextRange(start: 0, end: text.length),
);
_connection.setEditingState(_value);
}
void _onSearchChanged(String value) async {
final localId = ++_searchId;
final results = await widget.findSuggestions(value);
if (_searchId == localId && mounted) {
setState(() => _suggestions = results.where((profile) => !_chips.contains(profile)).toList(growable: false));
}
}
}
class _TextCaret extends StatefulWidget {
const _TextCaret({
Key key,
this.duration = const Duration(milliseconds: 500),
this.resumed = false,
}) : super(key: key);
final Duration duration;
final bool resumed;
#override
_TextCursorState createState() => _TextCursorState();
}
class _TextCursorState extends State<_TextCaret> with SingleTickerProviderStateMixin {
bool _displayed = false;
Timer _timer;
#override
void initState() {
super.initState();
_timer = Timer.periodic(widget.duration, _onTimer);
}
void _onTimer(Timer timer) {
setState(() => _displayed = !_displayed);
}
#override
void dispose() {
_timer.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return FractionallySizedBox(
heightFactor: 0.7,
child: Opacity(
opacity: _displayed && widget.resumed ? 1.0 : 0.0,
child: Container(
width: 2.0,
color: theme.primaryColor,
),
),
);
}
}

Flutter - How set double value to Bloc?

In my application there is a field for input of a certain value in double format, but this is not working.
What am I doing wrong?
My Bloc
class BudgetBloc extends BlocBase {
String _documentId;
double _movimentos;
BudgetBloc() {
_movimentosController.listen((value) => _movimentos = value);
}
void setBudget(Budget budget) {
_documentId = budget.documentId();
setMovimentos(budget.movimentos);
}
var _movimentosController = BehaviorSubject<double>();
Stream<double> get outMovimentos => _movimentosController.stream;
void setMovimentos(double value) => _movimentosController.sink.add(value);
bool insertOrUpdate() {
var budget = Budget()
..movimentos = _movimentos;
if (_documentId?.isEmpty ?? true) {
_repository.add(budget);
} else {
_repository.update(_documentId, budget);
}
return true;
}
#override
void dispose() {
_movimentosController.close();
super.dispose();
}
}
My BudgetPage
class BudgetPage extends StatefulWidget {
BudgetPage(this.budget);
final Budget budget;
#override
_BudgetPageState createState() => _BudgetPageState();
}
class _BudgetPageState extends State<BudgetPage> {
TextEditingController _movimentosController;
final _bloc = BudgetBloc();
#override
void initState() {
_movimentosController =
TextEditingController(text: widget.budget.movimentos.toString());
super.initState();
}
#override
void dispose() {
_movimentosController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Add Movimento"),
),
body: Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(
children: <Widget>[
Container(
child: TextField(
decoration: InputDecoration(labelText: "Movimento"),
controller: _movimentosController,
onChanged: _bloc.setMovimentos,
),
),
Container(
height: 20,
),
RaisedButton(
child: Text("Save"),
onPressed: () {
if (_bloc.insertOrUpdate()) {
Navigator.pop(context);
}
},
)
],
),
),
),
);
}
}
Thanks
Function(double) can't be assigned to the parameter type void Function(String)
The error is telling you that you are providing a String when it expects a double.
I would try passing a double to the BLoC, something like this:
onChanged: (value) => _bloc.setMovimentos(double.parse(value)),