Reputation: 307
This is the design I want to make
This is my current design
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
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();
}
}
Upvotes: 0
Reputation: 1
just use column widget first children is Text and second children as TextFormField.
Upvotes: 0
Reputation: 1
List item
You use the the property 'Labletext' of TextFormFiled or TextField.... to give the above text of the textformFiled.
Upvotes: 0
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
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),
),
),
],
),
),
);
}
}
Upvotes: 1
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),
),
),
)
],
)
Upvotes: 1
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