So I am making my first Flutter app, and on the login screen I used a custom button widget with animation (I made it a class, so that I can use it multiple times in my application). My custom button widget is based on this Tutorial. My question is, I am trying to invoke text validations by using the setState() method in the method I am about to pass to the widget class. Since it is on a completely different class I am unable to invoke the setState() method.
I have searched SO as much as I can, but I cant seem to find any useful question that apply to my use case. What I want done is, once the user presses the custom widget button, the Custom Widget Button's onPressed() method should invoke the validateTextField() method and use setState() to set the TexFormField's errorText parameter accordingly (the text field is in the Login Widget Class).
PS: This is my first SO question, so please bear with me if I made any mistakes, if I need to edit any part of this question just comment on it I will do so. And if you require any more code just ask, thank you.
Here is my code:
My Custom Widget Class:
class LoginProgressButton extends StatefulWidget {
final Color successButtonColor;
final Color buttonColor;
final Color splashColor;
@required
final bool onPressed;
@required
final VoidCallback navigator;
const LoginProgressButton({
Key key,
this.onPressed,
this.successButtonColor,
this.buttonColor,
this.splashColor,
this.navigator,
}) : super(key: key);
@override
State<StatefulWidget> createState() => _LoginProgressButton();
}
class _LoginProgressButton extends State<LoginProgressButton>
with TickerProviderStateMixin {
int _state = 0;
double _width = 240.0;
Animation _animation;
AnimationController _controller;
GlobalKey _globalKey = GlobalKey();
@override
Widget build(BuildContext context) {
return Container(
key: _globalKey,
alignment: Alignment.center,
height: 60.0,
width: _width,
child: ButtonTheme(
height: 60.0,
minWidth: _width,
shape: OutlineInputBorder(
borderRadius: BorderRadius.circular(30.0),
),
child: RaisedButton(
onPressed: () => onPressed(),
color: _state == 2 ? widget.successButtonColor : widget.buttonColor,
child: loginState(),
splashColor: widget.splashColor,
onHighlightChanged: null,
),
),
);
}
Widget loginState() {
if (_state == 2) {
return Icon(
Icons.check,
color: Colors.white,
);
} else if (_state == 1) {
return SizedBox(
height: 30.0,
width: 30.0,
child: CircularProgressIndicator(
value: null,
backgroundColor: Colors.white,
strokeWidth: 3.0,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
);
} else {
return Text('Connect',
style: TextStyle(
color: Colors.white,
fontSize: 24.0,
));
}
}
void animateButton() {
print(_state);
double initialWidth = _globalKey.currentContext.size.width;
_controller =
AnimationController(duration: Duration(milliseconds: 300), vsync: this);
_animation = Tween(begin: 0.0, end: 1.0).animate(_controller)
..addListener(() {
setState(() {
_width = initialWidth - ((initialWidth - 60.0) * _animation.value);
//this reduces the width by 48.0 for each frame, thus showing a smooth transition
});
});
_controller.forward(); //the forward function starts the animation
//starting with the default state
setState(() => _state = 1);
Timer(Duration(milliseconds: 3600), () => setState(() => _state = 2));
Timer(Duration(milliseconds: 4200), () => widget.navigator());
Timer(Duration(milliseconds: 4400), () => reset());
}
void reset() {
_width = 240.0;
_state = 0;
}
@override
void dispose() {
super.dispose();
}
void onPressed() {
if (widget.onPressed) {
setState(() {
if (_state == 0) {
animateButton();
} else if (_state == 2) {
reset();
}
});
} else {}
}
}
The Custom Widget being invoked by the Login Widget Class:
LoginProgressButton(
buttonColor: Theme.of(context).buttonColor,
splashColor: Theme.of(context).splashColor,
onPressed: _validateTextField(_pageHostLink),
navigator: _navigation,
successButtonColor: Colors.greenAccent,
),
On Pressed method passed to Custom Widget:
void _validateField() {
String value = _pageHostLink;
setState(() {
_fieldValidated = value == null ? false : value.isNotEmpty;
});
print("value is $value of datatype ${value.runtimeType}");
setState(() => _errorText =
_fieldValidated ? null : 'This field cannot be left empty');
}
bool _validateTextField(String value) {
print("value is $value of datatype ${value.runtimeType}");
_validateField();
return value == null ? false : value.isNotEmpty;
}
The Navigator function that pushes the next route if validation is successful
void _navigation() {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => LoginPage(
pageHostLink: _pageHostLink,
),
),
);
}