John Reaper
John Reaper

Reputation: 307

How to make the text above the textformfield?

This is the design I want to make

enter image description here

This is my current design

enter image description here

I'm new to flutter. My question is how to make the text above the textformfield. I have searched on the internet and tried to do it but still no success. I don't know where else to go to solve my problem. I hope overflow is willing to help me.

This is my code:

Container(
                        width: double.infinity,
                        margin: EdgeInsets.fromLTRB(10, 0, 10, 10),
                        padding: EdgeInsets.all(15),
                        decoration: BoxDecoration(
                          border: Border.all(
                            color: Colors.transparent,
                            width: 1.0,
                          ),
                        ),
                        child: Column(
                          mainAxisAlignment: MainAxisAlignment.start,
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Row(
                              children: [
                                SizedBox(
                                  height: 100,
                                  width: 100,
                                  child: Text('First Name'),
                                ),
                                SizedBox(
                                  width: 200,
                                  child: TextFormField(
                                    style: TextStyle(color: Colors.black),
                                    controller: firstName,
                                    onSaved: (String? value) {
                                      firstName.text = value!;
                                    },
                                    decoration: InputDecoration(
                                      border: OutlineInputBorder(),
                                      hintText: 'First Name',
                                      hintStyle: TextStyle(
                                          color: Colors.black, fontSize: 16),
                                    ),
                                  ),
                                ),
                              ],
                            )
                          ],
                        ),
                      )

Upvotes: 1

Views: 3199

Answers (7)

AEZAKMI 8
AEZAKMI 8

Reputation: 1

I have implemented my own TextField with Title on top of form, based on Answer, and sources provided by flutter from input_decorator.dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class LabelTextField extends StatefulWidget {
  final TextEditingController? controller;
  final String? initialValue;
  final FocusNode? focusNode;
  final InputDecoration? decoration;
  final TextInputType? keyboardType;
  final TextAlign textAlign;
  final TextStyle? style;
  final EdgeInsets? labelPadding;
  final bool autofocus;
  final bool readOnly;
  final bool obscureText;
  final bool autocorrect;
  final bool enableSuggestions;
  final int? maxLines;
  final int? minLines;
  final int? maxLength;
  final void Function(String)? onChanged;
  final TapRegionCallback? onTapOutside;
  final bool? enabled;
  final List<TextInputFormatter>? inputFormatters;

  const LabelTextField({
    super.key,
    this.controller,
    this.initialValue,
    this.focusNode,
    this.decoration,
    this.keyboardType,
    this.textAlign = TextAlign.start,
    this.style,
    this.labelPadding,
    this.autofocus = false,
    this.readOnly = false,
    this.obscureText = false,
    this.autocorrect = true,
    this.enableSuggestions = true,
    this.maxLines = 1,
    this.minLines,
    this.maxLength,
    this.onChanged,
    this.onTapOutside,
    this.enabled,
    this.inputFormatters,
  });

  @override
  State<LabelTextField> createState() => _LabelTextFieldState();
}

class _LabelTextFieldState extends State<LabelTextField> {
  static const Duration _kTransitionDuration = Duration(milliseconds: 167);
  static const Curve _kTransitionCurve = Curves.fastOutSlowIn;

  late final FocusNode _focusNode;
  late final TextEditingController _controller;

  @override
  void initState() {
    super.initState();
    _controller = widget.controller ?? TextEditingController(text: widget.initialValue ?? '');

    _focusNode = widget.focusNode ?? FocusNode();
    _focusNode.addListener(_focusChanged);
  }

  bool get _isEnabled => widget.enabled ?? widget.decoration?.enabled ?? true;

  bool get _hasIntrinsicError =>
      widget.maxLength != null &&
      widget.maxLength! > 0 &&
      (widget.controller == null
          ? _controller.value.text.characters.length > widget.maxLength!
          : _controller.value.text.characters.length > widget.maxLength!);

  bool get _hasError => widget.decoration?.errorText != null || widget.decoration?.error != null || _hasIntrinsicError;

  bool get _isEmpty => _controller.value.text.isNotEmpty;

  bool get _labelShouldAppear => _isEmpty || (_focusNode.hasFocus && decoration.enabled);

  bool get _floatingLabelEnabled {
    return decoration.floatingLabelBehavior != FloatingLabelBehavior.never;
  }

  Set<MaterialState> get materialState {
    return <MaterialState>{
      if (!_isEnabled) MaterialState.disabled,
      if (_focusNode.hasFocus) MaterialState.focused,
      if (_hasError) MaterialState.error,
    };
  }

  InputDecoration? _effectiveDecoration;

  InputDecoration get decoration => _effectiveDecoration ??=
      (widget.decoration ?? const InputDecoration()).applyDefaults(Theme.of(context).inputDecorationTheme);

  @override
  void didUpdateWidget(LabelTextField oldWidget) {
    super.didUpdateWidget(oldWidget);

    if (widget.decoration != oldWidget.decoration) {
      _effectiveDecoration = null;
    }
  }

  TextStyle get labelStyle => MaterialStateTextStyle.resolveWith((Set<MaterialState> states) {
        final ColorScheme colors = Theme.of(context).colorScheme;
        final TextTheme textTheme = Theme.of(context).textTheme;
        final TextStyle textStyle = textTheme.bodyLarge ?? const TextStyle();
        if (states.contains(MaterialState.disabled)) {
          return textStyle.copyWith(color: colors.onSurface.withOpacity(0.38));
        }
        if (states.contains(MaterialState.error)) {
          return textStyle.copyWith(color: colors.secondary);
        }
        if (states.contains(MaterialState.focused)) {
          return textStyle.copyWith(color: colors.primary);
        }
        return textStyle;
      });

  @override
  Widget build(BuildContext context) {
    final ThemeData themeData = Theme.of(context);
    InputDecorationTheme defaults = themeData.inputDecorationTheme;

    final Widget? label = decoration.labelText == null && decoration.label == null
        ? null
        : AnimatedOpacity(
            duration: _kTransitionDuration,
            curve: _kTransitionCurve,
            opacity: _labelShouldAppear ? 1.0 : 0.0,
            child: AnimatedDefaultTextStyle(
              duration: _kTransitionDuration,
              curve: _kTransitionCurve,
              style: _getInlineLabelStyle(
                themeData,
                defaults.labelStyle ?? labelStyle,
              ),
              child: decoration.label ??
                  Text(
                    decoration.labelText!,
                    overflow: TextOverflow.ellipsis,
                    textAlign: ([FloatingLabelAlignment.start, null].contains(
                      decoration.floatingLabelAlignment,
                    ))
                        ? TextAlign.start
                        : TextAlign.center,
                  ),
            ),
          );

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      mainAxisAlignment: MainAxisAlignment.start,
      children: [
        if (_floatingLabelEnabled && label != null)
          Padding(
            padding: widget.labelPadding ?? const EdgeInsets.only(bottom: 8.0),
            child: label,
          ),
        TextFormField(
          controller: _controller,
          focusNode: _focusNode,
          decoration: decoration.copyWith(
            floatingLabelBehavior: FloatingLabelBehavior.never,
          ),
          keyboardType: widget.keyboardType,
          style: widget.style,
          autofocus: widget.autofocus,
          readOnly: widget.readOnly,
          obscureText: widget.obscureText,
          autocorrect: widget.autocorrect,
          enableSuggestions: widget.enableSuggestions,
          maxLines: widget.maxLines,
          minLines: widget.minLines,
          maxLength: widget.maxLength,
          onChanged: widget.onChanged,
          onTapOutside: widget.onTapOutside,
          inputFormatters: widget.inputFormatters,
          enabled: widget.enabled,
        ),
      ],
    );
  }

  void _focusChanged() {
    setState(() {});
  }

  TextStyle _getInlineLabelStyle(ThemeData themeData, TextStyle labelStyle) {
    final TextStyle defaultStyle = MaterialStateProperty.resolveAs(labelStyle, materialState);
    final TextStyle? style = MaterialStateProperty.resolveAs(decoration.labelStyle, materialState) ??
        MaterialStateProperty.resolveAs(themeData.inputDecorationTheme.labelStyle, materialState);

    return themeData.textTheme.titleMedium!.merge(defaultStyle).merge(style).copyWith(height: 1);
  }

  @override
  void dispose() {
    _focusNode.removeListener(_focusChanged);
    super.dispose();
  }
}

demo .png

Upvotes: 0

Nilesh Kalsariya
Nilesh Kalsariya

Reputation: 1

just use column widget first children is Text and second children as TextFormField.

Upvotes: 0

Usman Ali
Usman Ali

Reputation: 1


List item


You use the the property 'Labletext' of TextFormFiled or TextField.... to give the above text of the textformFiled.

Upvotes: 0

Rohit Krishna
Rohit Krishna

Reputation: 202

In the input decoration of TextFormField, use label instead of hintText.

 decoration: InputDecoration(
    border: OutlineInputBorder(),
    label: Text('First Name',
           style: TextStyle(color: Colors.black, fontSize: 16),),
    ),

Upvotes: 0

Md. Yeasin Sheikh
Md. Yeasin Sheikh

Reputation: 63559

200px is too big and structure I will prefer

Row
 -Expanded
   - Column (CrossAxisAlignment.startMainAxisSize.min,)
     - Text
     - TextFormField
  -Expanded
   - Column (CrossAxisAlignment.startMainAxisSize.min,)
     - Text
     - TextFormField
  -Expanded
   - Column (CrossAxisAlignment.startMainAxisSize.min,)
     - Text
     - TextFormField
 @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Container(
            padding: EdgeInsets.all(15),
            decoration: BoxDecoration(
              border: Border.all(
                color: Colors.transparent,
                width: 1.0,
              ),
            ),
            child: Row(
              children: [
                filed(),
                filed(),
                filed(),
              ],
            ),
          )
        ],
      ),
    );
  }

  Expanded filed() {
    return Expanded(
      child: Padding(
        padding: EdgeInsets.all(8),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          mainAxisSize: MainAxisSize.min,
          children: [
            Padding(
              padding: EdgeInsets.only(bottom: 20),
              child: Text('First Name'),
            ),
            TextFormField(
              style: TextStyle(color: Colors.black),
              onSaved: (String? value) {},
              decoration: InputDecoration(
                border: OutlineInputBorder(),
                hintText: 'First Name',
                hintStyle: TextStyle(color: Colors.black, fontSize: 16),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

enter image description here

Upvotes: 1

sm-sayedi
sm-sayedi

Reputation: 905

To create the TextField you want, you just need to use a Column like this:

Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text('First Name', style: TextStyle(fontWeight: FontWeight.bold),),
          SizedBox(
            width: 200,
            child: TextFormField(
              style: TextStyle(color: Colors.black),
              onSaved: (String? value) {
                // firstName.text = value!;
              },
              decoration: InputDecoration(
                border: OutlineInputBorder(),
                hintText: 'First Name',
                hintStyle: TextStyle(color: Colors.black, fontSize: 16),
              ),
            ),
          )
        ],
      )

The result is: enter image description here

Upvotes: 1

Wiktor
Wiktor

Reputation: 775

Your problem occurs because of wrong widget placement. Notice that you've Row inside a Column, but you don't really use Column's children in order to vertically place 'First Name' text widget.Also the row is basically redundant currently. You can make a Row of Columns I just shared below in order to achieve your desired UI. Try to play with it :)

child: Column(
  crossAxisAlignment: CrossAxisAlignment.start,
  mainAxisAlignment: MainAxisAlignment.start,
  children: [
    const SizedBox(
      height: 20,
      width: 100,
      child: Text('First Name'),
    ),
    SizedBox(
      width: 150,
      child: TextFormField(
        style: const TextStyle(color: Colors.black),
        decoration: const InputDecoration(
          border: OutlineInputBorder(),
          hintText: 'First Name',
          hintStyle: TextStyle(color: Colors.black, fontSize: 16),
        ),
      ),
    )
  ],
),

Upvotes: 1

Related Questions