What is the alternative for "initState()` while we using "GetX" and "statelessWidget"?

Viewed 738

I have the following code that is inside a statefullWidget, and I want to change the statefullWidget to a statelessWidget and use GetXCintroller instead.

  AnimationController? _controller;
  Animation<Offset>? _slideAnimation;
  Animation<double>? _opacityAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(
        milliseconds: 300,
      ),
    );
    _slideAnimation = Tween<Offset>(
      begin: const Offset(0, -1.5),
      end: const Offset(0, 0),
    ).animate(
      CurvedAnimation(
        parent: _controller as Animation<double>,
        curve: Curves.fastOutSlowIn,
      ),
    );
    _opacityAnimation = Tween(begin: 0.0, end: 1.0).animate(
      CurvedAnimation(
        parent: _controller as Animation<double>,
        curve: Curves.easeIn,
      ),
    );
    // _heightAnimation.addListener(() => setState(() {}));
  }

I tried to put it inside the onInit() method instead of initState() within a class extends GetxController with GetSingleTickerProviderStateMixin. It seems it works with no errors but when I launch the application on mobile platform, it closes the keyboard when I try to select the text fields on login/signup form. Actually this is a code that animates the login/signup form by switching the form and button text from login to signup mode. This is the form's code:

Card(
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(10.0),
      ),
      elevation: 8.0,
      child: AnimatedContainer(
        duration: const Duration(milliseconds: 300),
        curve: Curves.easeIn,
        height: _authMode!.value == AuthMode.Signup ? 320 : 260,
        //height: _heightAnimation.value.height,
        constraints: BoxConstraints(
            minHeight: _authMode.value == AuthMode.Signup ? 320 : 260),
        width: deviceSize.width * 0.75,
        padding: const EdgeInsets.all(16.0),
        child: Form(
              key: _formKey,
              child: SingleChildScrollView(
                child: Column(
                  children: <Widget>[
                    TextFormField(
                      decoration: const InputDecoration(labelText: 'E-Mail'),
                      keyboardType: TextInputType.emailAddress,
                      validator: (value) {
                        if (value!.isEmpty || !value.contains('@')) {
                          return 'Invalid email!';
                        }
                      },
                      onSaved: (value) {
                        _authData['email'] = value as String;
                      },
                    ),
                    TextFormField(
                      decoration: const InputDecoration(labelText: 'Password'),
                      obscureText: true,
                      controller: _passwordController,
                      validator: (value) {
                        if (value!.isEmpty || value.length < 5) {
                          return 'Password is too short!';
                        }
                      },
                      onSaved: (value) {
                        _authData['password'] = value as String;
                      },
                    ),
                    AnimatedContainer(
                      constraints: BoxConstraints(
                        minHeight: _authMode.value == AuthMode.Signup ? 60 : 0,
                        maxHeight: _authMode.value == AuthMode.Signup ? 120 : 0,
                      ),
                      duration: const Duration(milliseconds: 300),
                      curve: Curves.easeIn,
                      child: FadeTransition(
                        opacity: _opacityAnimation as Animation<double>,
                        child: SlideTransition(
                          position: _slideAnimation as Animation<Offset>,
                          child: TextFormField(
                            enabled: _authMode.value == AuthMode.Signup,
                            decoration: const InputDecoration(
                                labelText: 'Confirm Password'),
                            obscureText: true,
                            validator: _authMode.value == AuthMode.Signup
                                ? (value) {
                                    if (value != _passwordController.text) {
                                      return 'Passwords do not match!';
                                    }
                                  }
                                : null,
                          ),
                        ),
                      ),
                    ),
                    const SizedBox(
                      height: 20,
                    ),
                    if (_isLoading!.value)
                      const CircularProgressIndicator()
                    else
                      Obx(() => ElevatedButton(
                            child: Text(_authMode.value == AuthMode.Login
                                ? 'LOGIN'
                                : 'SIGN UP'),
                            onPressed: _submit,
                            style: ElevatedButton.styleFrom(
                              shape: RoundedRectangleBorder(
                                borderRadius: BorderRadius.circular(30),
                              ),
                              primary: Theme.of(context).primaryColor,
                              padding: const EdgeInsets.symmetric(
                                  horizontal: 30.0, vertical: 8.0),
                              onPrimary: Theme.of(context)
                                  .primaryTextTheme
                                  .button!
                                  .color,
                            ),
                          )),
                    Obx(() => TextButton(
                          child: Text(
                              '${_authMode.value == AuthMode.Login ? 'SIGNUP' : 'LOGIN'} '),
                          onPressed: _switchAuthMode,
                          style: TextButton.styleFrom(
                            padding: const EdgeInsets.symmetric(
                                horizontal: 30.0, vertical: 4),
                            tapTargetSize: MaterialTapTargetSize.shrinkWrap,
                            textStyle: TextStyle(
                                color: Theme.of(context).primaryColor),
                          ),
                        )),
                  ],
                ),
              ),
            )),
      // ),
    );

The text button works(by wrapping it with Obx) and can change the form but text fields are un-clickable and the keyboard get closed immediately and form restarts again.

1 Answers

When you are using the GetX package, you have the option of creating a controller which extends GetxController.

Here is the example of the GetXController.

class AuthController extends GetxController{
  final key = GlobalKey<FormState>();
  late TextEditingController passwordController;
  @override
  void onInit() {
    super.onInit();
    passwordController = TextEditingController();
  }
  
  @override
  void onReady() {
    super.onReady();
  }
  
  @override
  void onClose() {
    super.onClose();
    passwordController.dispose();
  }
}

The alternative to initState() in GetX is onInit()

Please make sure to check this repo github.com/jabeed-ahmed/test.

If it solves your problem, kindly mark it as answered

Related