Search code examples
flutterdartdynamictextfieldinputformatter

Flutter - Change text input type and input formatters dynamically on tap


I want to change the text input type and input formatters of a text field dynamically on tap. But the problem is once the text input type is done it is not changed on tap whereas the label text acts as expected.

I have done like below

bool joinlinkname = false;
joinchanged() {
  if (joinlinkname == false) {
    setState(() {
      joinlinkname = true;
    });
  } else {
    setState(() {
    joinlinkname = false;
    });
  }
} 

TextField(
  keyboardType: joinlinkname? TextInputType.text : TextInputType.phone,
  labelText: joinlinkname ? 'num' : "text",
  inputFormatters: [joinlinkname ? 
    FilteringTextInputFormatter.allow(RegExp('[azAZ09]')):FilteringTextInputFormatter.allow(RegExp('[0-9]')),
  ],
),

GestureDetector(
  onTap: () {
    joinchanged();
  },
  child: Text(joinlinkname ? 'number' : 'text',
              style: TextStyle(
              color: Colors.blue,
              fontSize: 12,
              ),
         ),
 ),

Please can anyone tell how to do it?


Solution

  • You can copy paste run full code below
    You can use ValueListenableBuilder and ValueNotifier
    You also need FocusNode to control keyboard
    You can see working demo below
    code snippet

    final ValueNotifier<bool> joinlinkname = ValueNotifier<bool>(false);
    ...
    joinchanged() async {
        FocusManager.instance.primaryFocus.unfocus();
        joinlinkname.value = !joinlinkname.value;
        await Future.delayed(Duration(milliseconds: 500), () {});
        myFocusNode.requestFocus();
      }
    ...  
    ValueListenableBuilder(
              builder: (BuildContext context, bool value, Widget child) {
                return Column(
                  children: [
                    GestureDetector(
                      onTap: () {
                        joinchanged();
                      },
                      child: Text(
                        joinlinkname.value ? 'number' : 'text',
                        style: TextStyle(
                          color: Colors.blue,
                          fontSize: 12,
                        ),
                      ),
                    ),
                    TextField(
                      focusNode: myFocusNode,
                      keyboardType: joinlinkname.value
                          ? TextInputType.phone  
    

    working demo

    enter image description here

    full code

    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
            visualDensity: VisualDensity.adaptivePlatformDensity,
          ),
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      final ValueNotifier<bool> joinlinkname = ValueNotifier<bool>(false);
      FocusNode myFocusNode;
    
      @override
      void initState() {
        super.initState();
        myFocusNode = FocusNode();
      }
    
      @override
      void dispose() {
        myFocusNode.dispose();
        super.dispose();
      }
    
      joinchanged() async {
        FocusManager.instance.primaryFocus.unfocus();
        joinlinkname.value = !joinlinkname.value;
        await Future.delayed(Duration(milliseconds: 500), () {});
        myFocusNode.requestFocus();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: Text(widget.title)),
          body: Center(
            child: ValueListenableBuilder(
              builder: (BuildContext context, bool value, Widget child) {
                return Column(
                  children: [
                    GestureDetector(
                      onTap: () {
                        joinchanged();
                      },
                      child: Text(
                        joinlinkname.value ? 'number' : 'text',
                        style: TextStyle(
                          color: Colors.blue,
                          fontSize: 12,
                        ),
                      ),
                    ),
                    TextField(
                      focusNode: myFocusNode,
                      keyboardType: joinlinkname.value
                          ? TextInputType.phone
                          : TextInputType.text,
                      decoration: InputDecoration(
                        labelText: joinlinkname.value ? 'num' : "text",
                      ),
                      inputFormatters: [
                        joinlinkname.value
                            ? FilteringTextInputFormatter.allow(RegExp('[0-9]'))
                            : FilteringTextInputFormatter.allow(RegExp('[azAZ09]')),
                      ],
                    ),
                  ],
                );
              },
              valueListenable: joinlinkname,
            ),
          ),
        );
      }
    }