17

I need a textField that has a suffixIcon, but after click on that icon I don't need to open keyboard. How I can do it alternatively without suffixIcon?

enter image description here

Andrew Kovalchuk
  • 897
  • 1
  • 10
  • 29
  • Its confusing. Do you want a text field with suffix icon? Do you want to add functionality to Suffix Icon (make it clickable..)? Do you want the text field be focusable? – Chenna Reddy Sep 25 '19 at 11:51
  • I want clickable icon inside TextField but when I click on it don't show keyboard. – Andrew Kovalchuk Sep 25 '19 at 11:55
  • 1
    `TextField` has `readOnly` attribute, if you set it to `true`, it won't show the keyboard. – Chenna Reddy Sep 25 '19 at 12:05
  • Then i will be unable to put some data into textField. I want if I click on text field write some text, but if i click on suffixIcon don't show keyboard and do some action – Andrew Kovalchuk Sep 25 '19 at 12:24

8 Answers8

21
Container(
  child: Stack(
    alignment: Alignment.centerRight,
    children: <Widget>[
      TextField(),
      IconButton(
        icon: Icon(Icons.image),
        onPressed: () {
          // do something
        },
      ),
    ],
  ),
)
Can
  • 1,646
  • 9
  • 13
  • 1
    This solution doesnt work good when error appears underneath TextField, it makes button not centered vertically anymore – kashlo Oct 14 '20 at 15:12
11

Tested and confirmed, exactly what u want.

Untitled.png

Stack(
  alignment: Alignment.centerRight,
  children: <Widget>[
    TextField(
      keyboardType: TextInputType.text,
      style: Theme.of(context).textTheme.body1,
      obscureText: true,
      decoration: InputDecoration(
        labelText: 'Password',
        contentPadding: const EdgeInsets.fromLTRB(6, 6, 48, 6), // 48 -> icon width
      ),
    ),
    IconButton(
      icon: Icon(Icons.dialpad, color: const Color(0xfff96800)),
      onPressed: () {
        FocusScope.of(context).requestFocus(FocusNode());
        // Your codes...
      },
    ),
  ],
),
ibrahimkarahan
  • 2,697
  • 1
  • 9
  • 20
7

There is one more possible fix for this issue - taken from here: https://github.com/flutter/flutter/issues/39376 - use the standard TextField with a button as suffixIcon and then, the magic trick:

InputDecoration(labelText: "Email address",
    border: OutlineInputBorder(),
    suffixIcon: IconButton(
    iconSize: 40,
    icon: Icon(Icons.fingerprint),
    onPressed: () async {
      focusNode.unfocus();
      focusNode.canRequestFocus = false;
      await performBiometricLogin();
      focusNode.canRequestFocus = true;
    },
  ),
),

Two things that you have to be aware in this case:

a) declare focusNode in your widget (I'm doing it in the state class of my statefull widget) and then use it for your textfield:

FocusNode focusNode = FocusNode();

and in the TextField use the property called focusNode:

focusNode: focusNode,

b) if you don't do any async operation in the onPressed event handler, then you have to follow exactly the logic from the github issue - enable canRequestFocus after some time:

Future.delayed(Duration(milliseconds: 100), () {
    widget.textFieldFocusNode.canRequestFocus = true;
});

Hopefully it will help others as it helped me.

Thanks.

Edi
  • 660
  • 9
  • 22
  • 1
    This is perfect, keeps TextField clean without needing Stacks. I added one thing because if the textField is focused and the suffixIcon is tapped, I don't want focus to be lost. Adding """if (textFieldFocusNode.hasPrimaryFocus) return;"""" in the tap handler did the job. Full answer here https://stackoverflow.com/questions/49125064/how-to-show-hide-password-in-textformfield/68910940#68910940 – Bugzilla Aug 24 '21 at 22:03
4

Click and not open the keyboard? If so, just create a class and assign it to focusNode, setting hasFocus to false, like this:

class AlwaysDisabledFocusNode extends FocusNode {
  @override
  bool get hasFocus => false;
}

new TextField(
focusNode: AlwaysDisabledFocusNode(),
onTap: () {},
keyboardType: TextInputType.text,
decoration: InputDecoration(
border: InputBorder.none,
icon: Icon(Icons.apps),
hintText: 'Password'),
style: Theme.of(context).textTheme.body1,
),

enter image description here

With readOnly: true it changes icon color on click

new TextField(readOnly: true,
    //focusNode: AlwaysDisabledFocusNode(),
    onTap: () {},
    keyboardType: TextInputType.text,
    decoration: InputDecoration(
    border: InputBorder.none,
    icon: Icon(Icons.apps),
    hintText: 'Password'),
    style: Theme.of(context).textTheme.body1,
    ),

enter image description here

I think then you have to put a Row with a TextField and an IconButton, with separate actions.

new Row(
  crossAxisAlignment: CrossAxisAlignment.center,
  mainAxisAlignment: MainAxisAlignment.center,
  children: <Widget>[
    new Expanded(
        child: Padding(
      child: new TextField(
        onTap: () {//action of TextField
        },
        keyboardType: TextInputType.text,
        decoration: InputDecoration(
            border: InputBorder.none, hintText: 'Password'),
        style: Theme.of(context).textTheme.body1,
      ),
      padding: EdgeInsets.only(left: 40),
    )),
    IconButton(
      icon: Icon(Icons.apps),
      onPressed: () {//action of iconbutton
      },
    )
  ],
)

enter image description here

Lucas Matos
  • 566
  • 3
  • 8
4

Use readOnly, don't use enabled.

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Muhammad Ashraf
  • 3,323
  • 2
  • 12
  • 19
1

I have achieved the same thing

Container(
        height: 40,
        child: Stack(
          children: <Widget>[
            TextField(
              controller: textEditingController,
              keyboardType: TextInputType.text,
              decoration: InputDecoration(
                prefixIcon: Icon(HelageeIcons.search_icon_of_search_box),
                border: OutlineInputBorder(
                  borderSide: BorderSide(
                    color: Color(0xff575656),
                  ),
                  borderRadius: const BorderRadius.all(
                    const Radius.circular(50.0),
                  ),
                ),
                hintStyle:
                    TextStyle(color: Color(0xffADADAC), fontSize: 14),
                hintText: "Quick Search",
              ),
            ),
            Positioned(
              right: 0,
              child: Container(
                height: 40,
                width: 40,
                child: Container(
                  child: Material(
                      shape: CircleBorder(),
                      color: Colors.transparent,
                      child: InkWell(
                          customBorder: CircleBorder(),
                          onTap: () {},
                          splashColor: Colors.grey,
                          child: Icon(Icons.keyboard))),
                ),
              ),
            ),
          ],
        ),
      ),
0

add suffix icon and suffix icon click on text filed, in my case I have used as below

TextFormField(
    textInputAction: TextInputAction.done,
    maxLines: 1,
    obscureText: _obscureText,
    autofocus: false,
    focusNode: _passwordFocus,
    style: TextStyle(fontSize: 17.0, color: Colors.black),
    onFieldSubmitted: (term) {
      _passwordFocus.unfocus();
      _validateAndSubmit();
    },
    decoration: InputDecoration(
      hintText: HINT_PASSWORD,
      hintStyle: TextStyle(fontSize: 17.0, color: Colors.black54),
      focusedBorder: OutlineInputBorder(
        borderSide: BorderSide(color: Colors.black),
      ),
      enabledBorder: OutlineInputBorder(
        borderSide: BorderSide(color: Colors.black87),
      ),
      errorBorder: OutlineInputBorder(
        borderSide: BorderSide(color: Colors.red),
      ),
      disabledBorder: OutlineInputBorder(
        borderSide: BorderSide(color: Colors.black87),
      ),
      focusedErrorBorder: OutlineInputBorder(
        borderSide: BorderSide(color: Colors.red),
      ),
      labelText: HINT_PASSWORD,
      labelStyle: TextStyle(fontSize: 17.0, color: Colors.black),
      errorStyle: TextStyle(fontSize: 12.0, color: Colors.red),
      prefixIcon: Icon(
        Icons.lock,
        color: themeColor,
      ),
      /// magic is here suffix ixon click
      suffixIcon: IconButton(
        icon: Icon(
          // Based on passwordVisible state choose the icon
          _obscureText ? Icons.visibility : Icons.visibility_off,
          color: themeColor,
        ),
        onPressed: () {
          // Update the state i.e. toogle the state of passwordVisible variable
          setState(() {
            _obscureText ? _obscureText = false : _obscureText = true;
          });
        },
      ),
    ),
    validator: validatePassword,
    onSaved: (value) => _password = value,
  )
Kailash Chouhan
  • 2,328
  • 16
  • 16
0

This should work

Stack(
            alignment: Alignment.centerRight,
            children: <Widget>[
              TextFormField(
              ),
              FlatButton(
                onPressed: () {
                  _openOrhidePassword();
                },
                child: Image(
                  height: 24.0,
                  width: 24.0,
                  image: AssetImage('images/Eye.png'),
                ),
              ),
            ],
          ),

In my case image size was another problem. When I provided the dimension it worked well with other widget.

Wasim
  • 921
  • 12
  • 14