Landon
Landon

Reputation: 538

How can I make TextField's suffix/suffixIcon height resize?

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: SafeArea(
        child: Scaffold(
          body: Column(
            children: [
              Container(
                color: Colors.orange,
                child: TextField(
                  decoration: InputDecoration(
                    suffix: IconButton(
                        icon: Icon(Icons.check_circle),
                        onPressed: () {
                          print('222');
                        }),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

How can I force the check_circle icon to automatically resize to match the height of the actual TextField, i.e., wrt its cursor height?

Upvotes: 2

Views: 12299

Answers (4)

Waad Sulaiman
Waad Sulaiman

Reputation: 21

Inside of decoration. You can modify the suffixIconConstraints, to a size of your choice. Like this:

  @override
  Widget build(BuildContext context) {
    return TextFormField(
      controller: widget.controller,
      onChanged: widget.onTextChanged,
      onEditingComplete: () {
        if (widget.enableAvailabilityCheck &&
            widget.availabilityCheck != null) {
          performAvailabilityCheck();
        }
      },
      obscureText: widget.obscureText && !isObscureTextVisible,
      decoration: InputDecoration(
          suffixIcon: widget.enableAvailabilityCheck
              ? buildSuffixIcon()
              : widget.obscureText
                  ? buildObscureTextIcon()
                  : null,
          suffixIconConstraints: BoxConstraints.tight(const Size(24.0, 24.0))),
    );
  }

Upvotes: 0

BIS Tech
BIS Tech

Reputation: 19424

Used Stack

Stack(
                    children: [
                      TextField(),
                      Positioned.fill(
                          right: 10,
                          child: Align(
                              alignment: Alignment.centerRight,
                              child: InkWell(
                                  onTap: () {
                                    searchController.clear();
                                  },
                                  child: Icon(Icons.clear))))
                    ],
                  ),

Upvotes: 4

roipeker
roipeker

Reputation: 1243

Very good question...

The basics, is to reset all the paddings in the TextField, and not using a IconButton (as all Material components have predefined and internals paddings that you can't modify).

Seems like suffix gets baseline aligned with the text, preventing the material ink interaction, while suffixIcons get properly centered in the text area, BUT propagates the Ink to the TextField. So, so far I couldn't find a way of doing it properly, maybe there's a widget/logic that I'm missing.

Check screenshot at the bottom that shows why the suffix will not be able to align with the text, as it sits within the baseline itself, and the caret generates a bigger height.....

in the first 2 textfields, the GREY boxes are suffix, and yellow, suffixIcon (which centers properly).

Solution 1: (in screenshotm is red background with 2 checkboxes) If you can (design-wise), make a row, and put the TextField and the icon:

var inputBorderDecoration = OutlineInputBorder(
        borderRadius: BorderRadius.zero,
        borderSide: BorderSide(width: 1, color: Colors.black));

    double textHeight = 40;

    // define a width if you want, or let the constrains of the parent define it.
    double inputWidth = double.infinity;

    return Center(
      child: Container(
          width: inputWidth,
          height: textHeight,
          color: Colors.green.withOpacity(.2),
          child: Row(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              Flexible(
                child: TextField(
                  controller: TextEditingController(text: 'hello world'),
                  style: TextStyle(fontSize: textHeight),
                  decoration: InputDecoration(
                    contentPadding: EdgeInsets.zero,
                    enabledBorder: inputBorderDecoration,
                    focusedBorder: inputBorderDecoration,
                    filled: true,
                    fillColor: Colors.red.withOpacity(.5),
                  ),
                ),
              ),
              FittedBox(
                child: InkWell(
                  onTap: () => print("touch button"),
                  child: Icon(Icons.check_circle),
                ),
              ),
            ],
          )),
    );

Solution 2: (in screenshot, last textfield, green box with white icon) Wrap the icon decoration, is the better UI approach, but the TextField will .still receive touch events.

var inputBorderDecoration = OutlineInputBorder(
        borderRadius: BorderRadius.zero,
        borderSide: BorderSide(width: 1, color: Colors.black));

    double fontSize = 24;
    return GestureDetector(
      onTap: () {
        FocusScope.of(context).requestFocus(FocusNode());
      },
      child: Container(
        color: Colors.green.shade50,
        child: Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              Container(
                width: 300,
                height: fontSize,
                color: Colors.orange,
                child: TextField(
                  style: TextStyle(fontSize: fontSize, color: Colors.white),
                  decoration: InputDecoration(
                    fillColor: Colors.purple.withOpacity(.5),
                    filled: true,
                    border: inputBorderDecoration,
                    focusedBorder: inputBorderDecoration,
                    enabledBorder: inputBorderDecoration,
                    contentPadding: EdgeInsets.zero,
                    suffixIcon: GestureDetector(
                      onTap: () => print('on tap'),
                      child: Container(
                        color: Colors.green,
                        child: FittedBox(
                          alignment: Alignment.center,
                          fit: BoxFit.fitHeight,
                          child: IconTheme(
                            data: IconThemeData(),
                            child: Icon(
                              Icons.check_circle,
                              color: Colors.white,
                            ),
                          ),
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );

Solution 3:

Build the decorations yourself using EditableText

enter image description here

Upvotes: 5

Michael Yuwono
Michael Yuwono

Reputation: 2617

Use suffixIcon instead.

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: SafeArea(
        child: Scaffold(
          body: Column(
            children: [
              Container(
                color: Colors.orange,
                child: TextField(
                  decoration: InputDecoration(
                    suffixIcon: IconButton(
                        icon: Icon(Icons.check_circle),
                        onPressed: () {
                          print('222');
                        }),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Upvotes: 6

Related Questions