Reputation: 1064
I have this a stateful widget which could be in two situations, the first one is a Container with a first text in it, for example, "Register", the second one is a different colored container with a different text, for example "confirm". The Problem is that the transition between these two situations is done using an animation and it's not an on-the-fly logic for example:
color: isSituation1 ? Colors.blue : Colors.red.
it's actually something like this:
color: Color.lerp(Colors.blue, Colors.red, _animation1.value)
and I have a function which runs when the user taps on the container which forwards the animation controller, like so:
_controller1.forward()
and this is a widget called let's say Button1
So in My HomePage stateful widget I have another button which should trigger the inverse process in the Button1 widget, so it would be:
_controller1.reverse()
I tried creating a function in the Button1 widget but then I cannot run it from outside. How could I do it if it's possible?
Upvotes: 1
Views: 1252
Reputation: 4741
So basically you want to call methods of your CustomWidget from another widget. You can define ControllerClass that you will emit an instance when you create a new instance of your CustomWidget. This ControllerClass instance will hold the functions of your CustomWidget and you will be able to call them from outside.
By example a class that is a modal rounded progressbar that can be showed and hided from outise with a controller class. In this example a controller class is called ProgressBarHandler. I don't know if it is a better and the right approach but works.
class ModalRoundedProgressBar extends StatefulWidget {
final String _textMessage;
final double _opacity;
final Color _color;
final Function _handlerCallback;
ModalRoundedProgressBar({
@required Function handleCallback(ProgressBarHandler handler), //callback to get a controller
String message = "",
double opacity = 0.7,
Color color = Colors.black54,
}) : _textMessage = message,
_opacity = opacity,
_color = color,
_handlerCallback = handleCallback;
@override
State createState() => _ModalRoundedProgressBarState();
}
class _ModalRoundedProgressBarState extends State<ModalRoundedProgressBar> {
bool _isShowing = false;
@override
void initState() {
super.initState();
// init controller.
ProgressBarHandler handler = ProgressBarHandler();
handler.show = this.show;
handler.dismiss = this.dismiss;
widget._handlerCallback(handler); // callback call.
}
@override
Widget build(BuildContext context) {
if (!_isShowing) return Stack();
return Material(
color: Colors.transparent,
child: Stack(
children: <Widget>[
Opacity(
opacity: widget._opacity,
child: ModalBarrier(
dismissible: false,
color: Colors.black54,
),
),
Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(),
Text(widget._textMessage),
],
),
),
],
),
);
}
void show() {
setState(() => _isShowing = true);
}
void dismiss() {
setState(() => _isShowing = false);
}
}
class ProgressBarHandler {
Function show; // will point to widget show method
Function dismiss; // will point to another method.
}
// ...in another external widget you can do...
// ... code your things and:
var controller;
var progressBar = ModalRoundedProgressBar(
handleCallback: ((handler){ controller = handler; } ),);
//calling show method with controller
RaisedButton(
onPressed: () { controller.show(); }
);
//calling dismiss method with controller
RaisedButton(
onPressed: () { controller.dismiss(); }
);
Upvotes: 2
Reputation: 17746
It is possible, but you probably don't want to do that. You should either provide the AnimationController
from the parent or structure your app to prevent such behaviors. Anyway, if you still want to go this way, here you have it.
class HomePage extends StatefulWidget {
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
VoidCallback _reverseAnimation;
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text('Reverse animation'),
onPressed: () => _reverseAnimation(),
),
Button1((controller) => _reverseAnimation = controller),
],
),
);
}
}
class Button1 extends StatefulWidget {
final ValueChanged<VoidCallback> callback;
Button1(this.callback);
_Button1State createState() => _Button1State();
}
class _Button1State extends State<Button1> with SingleTickerProviderStateMixin {
AnimationController _someAnimationController;
void _reverseAnimation() {
_someAnimationController?.reverse();
}
@override
void initState() {
super.initState();
if (widget.callback != null) {
widget.callback(_reverseAnimation);
}
}
@override
Widget build(BuildContext context) {
return Container(
child: RaisedButton(
child: Text('Start animation'),
onPressed: () => _someAnimationController.forward(),
),
);
}
}
Upvotes: 0