fluttercolorstextfieldhint

Positioning Asterisk Adjacent to Hint Text in Flutter TextField


I've developed a custom input widget in Flutter to streamline the process of adding input fields in registration forms. This widget offers a range of customizable parameters, allowing for flexible configuration to suit various form requirements.

However, I've encountered an issue with the positioning of an asterisk (*) within the input field. The intention is for the asterisk to appear immediately after the text input, typically indicating that the field is required. However, upon implementation, the asterisk consistently appears at the rightmost part of the input field, rather than adjacent to the text input as desired.

import 'package:flutter/material.dart';

enum InputRestriction {
  text,
  number,
  textAndNumber,
}

Widget Input({
  double borderRadius = 16,
  double width = double.infinity,
  double height = 60,
  double left = 0,
  double right = 0,
  double top = 0,
  double bottom = 0,
  String hint = "",
  double fontSize = 16,
  bool prefixIconShow = false,
  bool suffixIconShow = false,
  IconData prefixIconName = Icons.person,
  IconData suffixIconName = Icons.lock,
  TextInputType textInputType = TextInputType.text,
  Color color = AppColors.black,
  required TextEditingController controller,
  bool password = false,
  Color containerBackgroundColor = AppColors.white,
  Color textFieldBackgroundColor = AppColors.white,
  double contentPaddingLeft = 0,
  double contentPaddingRight = 0,
  TextAlign textalign = TextAlign.left,
  RichText? suffix,
  List<String>? autofillHints,
  int maxLines = 1,
  TextOverflow overflow = TextOverflow.clip,
  required InputRestriction inputRestriction,
}) {
  TextInputType getTextInputType() {
    switch (inputRestriction) {
      case InputRestriction.text:
        return TextInputType.text;
      case InputRestriction.number:
        return TextInputType.number;
      case InputRestriction.textAndNumber:
        return TextInputType.text;
      default:
        return TextInputType.text;
    }
  }

  return Visibility(
    visible: true,
    child: Container(
      width: width,
      height: height,
      padding:
          EdgeInsets.only(left: left, right: right, top: top, bottom: bottom),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.all(Radius.circular(borderRadius)),
        color: containerBackgroundColor,
      ),
      child: Container(
        alignment: Alignment.center,
        decoration: BoxDecoration(
          borderRadius: BorderRadius.all(Radius.circular(borderRadius)),
          color: textFieldBackgroundColor,
        ),
        child: Stack(
          alignment: Alignment.centerRight,
          children: [
            TextField(
              textAlign: textalign,
              keyboardType: getTextInputType(),
              controller: controller,
              obscureText: password,
              cursorColor: color,
              maxLines: maxLines,
              style: TextStyle(
                fontSize: fontSize,
                fontFamily: "Poppins",
                fontWeight: FontWeight.w400,
                color: AppColors.black,
              ),
              decoration: InputDecoration(
                border: InputBorder.none,
                hintText: hint,
                contentPadding: EdgeInsets.only(
                  left: contentPaddingLeft,
                  right: contentPaddingRight,
                ),
                suffixIcon: suffixIconShow
                    ? Icon(
                        suffixIconName,
                        color: color,
                      )
                    : null,
              ),
              autofillHints: autofillHints,
            ),
            Visibility(
              visible: suffix != null,
              child: Padding(
                padding: const EdgeInsets.only(right: 8.0),
                child: suffix ?? Container(),
              ),
            ),
          ],
        ),
      ),
    ),
  );
}

I want the asterisk to appear immediately after the text. But when I use it, the asterisk appears at the rightmost part of the input.

this is how I call it

Expanded(
      child: Input(
    inputRestriction: InputRestriction.text,
    controller: name,
    fontSize: responsive.screenWidth / 30,
    hint: "İsim",
    textFieldBackgroundColor:
        AppColors.RegisterPageTextFieldColor,
    contentPaddingLeft: responsive.screenWidth / 32.72,
    suffix: RichText(
      softWrap: true,
      text: TextSpan(
        text: '* ',
        style: TextStyle(
          color: AppColors.darkMagenta,
        ),
        children: [
          TextSpan(
            text: '',
            style: TextStyle(
              color: AppColors.darkMagenta,
            ),
          ),
        ],
      ),
    ),
  )),

Solution

  • import 'package:flutter/material.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          debugShowCheckedModeBanner: false,
          home: Scaffold(
            body: Center(
              child: Input(hint: "İsim"),
            ),
          ),
        );
      }
    }
    
    Widget Input({
      double borderRadius = 16,
      double width = double.infinity,
      double height = 60,
      double left = 0,
      double right = 0,
      double top = 0,
      double bottom = 0,
      String hint = "",
      double fontSize = 16,
      bool prefixIconShow = false,
      bool suffixIconShow = false,
      IconData prefixIconName = Icons.person,
      IconData suffixIconName = Icons.lock,
      TextInputType textInputType = TextInputType.text,
      Color color = Colors.black,
      bool password = false,
      Color containerBackgroundColor = Colors.white,
      Color textFieldBackgroundColor = Colors.white,
      double contentPaddingLeft = 0,
      double contentPaddingRight = 0,
      TextAlign textalign = TextAlign.left,
      RichText? suffix,
      List<String>? autofillHints,
      int maxLines = 1,
      TextOverflow overflow = TextOverflow.clip,
    }) {
      return Visibility(
        visible: true,
        child: Container(
          width: width,
          height: height,
          padding:
              EdgeInsets.only(left: left, right: right, top: top, bottom: bottom),
          decoration: BoxDecoration(
            borderRadius: BorderRadius.all(Radius.circular(borderRadius)),
            color: containerBackgroundColor,
          ),
          child: Container(
            alignment: Alignment.center,
            decoration: BoxDecoration(
              borderRadius: BorderRadius.all(Radius.circular(borderRadius)),
              color: textFieldBackgroundColor,
            ),
            child: TextField(
              textAlign: textalign,
              obscureText: password,
              cursorColor: color,
              maxLines: maxLines,
              style: TextStyle(
                fontSize: fontSize,
                fontWeight: FontWeight.w400,
                color: Colors.black,
              ),
              decoration: InputDecoration(
                label: RichText(
                  softWrap: true,
                  text: TextSpan(
                    text: hint,
                    style: TextStyle(
                      color: Colors.black,
                    ),
                    children: [
                      TextSpan(
                        text: '* ',
                        style: TextStyle(
                          color: Colors.blue,
                        ),
                      ),
                    ],
                  ),
                ),
                floatingLabelBehavior: FloatingLabelBehavior.never,
                border: InputBorder.none,
                contentPadding: EdgeInsets.only(
                  left: contentPaddingLeft,
                  right: contentPaddingRight,
                ),
                suffixIcon: suffixIconShow
                    ? Icon(
                        suffixIconName,
                        color: color,
                      )
                    : null,
              ),
              autofillHints: autofillHints,
            ),
          ),
        ),
      );
    }
    

    I used label widget of input decorator as an example, deleted some components I dont ahve like colors but of course you don't need to, so now you have to apply some logic to parse Textspan instead of widgets, or maybe just let them pass a color and a bool isRequired (or enum Required {asterisk, check, exclamation} ) and you will draw an important check for them

    enter image description here