How to toggle the suffix icon on the textfields separately

1,906

Solution 1

You need to seperate _isToggle variable for each TextFormField. And set only the tapped TextFormField.

EDIT:


  TextEditingController _controller1 = TextEditingController();
  TextEditingController _controller2 = TextEditingController();
  TextEditingController _controller3 = TextEditingController();

  List<bool> toggleList = List<bool>();

  void _toggle(int index) {
    setState(() {
      toggleList[index] = !toggleList[index];
      // _isToggle = !_isToggle;
    });
  }

  List<Widget> widgetList = List<Widget>();

  InputDecoration _getInputDecoration(String string, int index) {
    return InputDecoration(
      isDense: true,
      suffixIcon: Padding(
        padding: EdgeInsetsDirectional.only(end: 12.0),
        child: GestureDetector(
          child: toggleList[index]
              ? Icon(
                  Icons.lock_outline_rounded,
                  color: Colors.black,
                )
              : Icon(
                  Icons.lock_open_rounded,
                  color: Colors.black,
                ),
          onTap: () {
            _toggle(index);
          },
        ),
      ),
    );
  }

  addList() {
    widgetList.add(TextFormField(
      controller: _controller1,
      decoration: _getInputDecoration("Write your current pass", 0),
      keyboardType: TextInputType.text,
      obscureText: toggleList[0],
    ));

    widgetList.add(TextFormField(
      controller: _controller2,
      decoration: _getInputDecoration("Write your current pass", 1),
      keyboardType: TextInputType.text,
      obscureText: toggleList[1],
    ));

    widgetList.add(TextFormField(
      controller: _controller3,
      decoration: _getInputDecoration("Write your current pass", 2),
      keyboardType: TextInputType.text,
      obscureText: toggleList[2],
    ));
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
        padding: const EdgeInsets.all(8),
        itemCount: widgetList.length,
        itemBuilder: (BuildContext context, int index) {
          return widgetList[index];
        });

Solution 2

Please check the code for dynamically setting the obscureText when you have multiple TextEditingController.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      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> {
  List _controller = List<TextEditingController>.generate(
      3, (index) => TextEditingController());
  List<bool> _isToggle = List<bool>.generate(3, (index) => true);

  void _toggle(int index) {
    setState(() {
      _isToggle[index] = !_isToggle[index];
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Padding(
          padding: EdgeInsets.all(10),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              for (int i = 0; i < 3; i++)
                TextFormField(
                  controller: _controller[i],
                  //decoration: _getInputDecoration("Write your current pass"),
                  keyboardType: TextInputType.text,
                  obscureText: _isToggle[i],
                  decoration: InputDecoration(
                    suffixIcon: Padding(
                      padding: EdgeInsetsDirectional.only(end: 12.0),
                      child: GestureDetector(
                        child: _isToggle[i]
                            ? Icon(
                                Icons.lock_outline_rounded,
                                color: Colors.black,
                              )
                            : Icon(
                                Icons.lock_open_rounded,
                                color: Colors.black,
                              ),
                        onTap: () => _toggle(i),
                      ),
                    ),
                  ),
                ),
            ],
          ),
        ),
      ),
    );
  }
}
Share:
1,906
Admin
Author by

Admin

Updated on December 25, 2022

Comments

  • Admin
    Admin over 1 year

    I have three pass fields which have icons to show/hide the pass. The default obscureText is true and when the user clicks in the icon, it calls a method _toggle that will turn the obscure text false, showing the textField content.
    But, when the user clicks in the icon, it toggles to all the 3 textfields but i wanted toggle only the field clicked. How can I treat this?

    My text fields (X 3):

    TextFormField(
              controller: _controller1,
              decoration: _getInputDecoration("Write your current pass"),
              keyboardType: TextInputType.text,
              obscureText: _isToggle,
    

    My get input decoration (with the icon inside a Gesture detector) :

    suffixIcon:
            Padding(
              padding: EdgeInsetsDirectional.only(end: 12.0),
              child: GestureDetector(
                child: _isToggle ? Icon(Icons.lock_outline_rounded, color: Colors.black,)  :
                Icon(Icons.lock_open_rounded, color: Colors.black,),
    
                onTap: _toggle,
              )
            ),
    

    This is the _toggle method:

    void _toggle() {
        setState(() {
          _isToggle = !_isToggle;
        });
      }
    
  • Admin
    Admin over 3 years
    I thought would have a dynamic way to do that
  • Akif
    Akif over 3 years
    It will be a list and you will check only the index. It is also dynamic.
  • Admin
    Admin over 3 years
    A list? I'm not realising it
  • Admin
    Admin over 3 years
    Very nice code, but I'm getting an error RangeError (index): Invalid value: Valid value range is empty: 0 in the toggleList[index] ? Icon...
  • Admin
    Admin over 3 years
  • Akif
    Akif over 3 years
    That is great! List<bool> _isToggle = List<bool>.generate(3, (index) => true);
  • bluenile
    bluenile over 3 years
    Yep, List.generate is awesome. I love Dart.