这就是我想做的设计
这是我目前的设计
我是颤振新手。我的问题是如何使文本位于文本表单字段上方。我在互联网上搜索并尝试这样做,但仍然没有成功。我不知道还能去哪里解决我的问题。我希望溢出愿意帮助我。
这是我的代码:
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),
),
),
),
],
)
],
),
)
您的问题是由于小部件放置错误而发生的。请注意,您在列内有行,但您并没有真正使用列的子级来垂直放置“名字”文本小部件。此外,该行目前基本上是多余的。您可以制作我刚刚在下面分享的一排列,以实现您想要的 UI。尝试玩一下:)
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),
),
),
)
],
),
200px 太大了,我更喜欢结构
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),
),
),
],
),
),
);
}
}
要创建所需的 TextField,您只需使用如下所示的 Column:
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),
),
),
)
],
)
在 TextFormField 的输入装饰中,使用
label
代替 hintText
。
decoration: InputDecoration(
border: OutlineInputBorder(),
label: Text('First Name',
style: TextStyle(color: Colors.black, fontSize: 16),),
),
列出项目
您使用 TextFormFiled 或 TextField 的属性“Labletext”...... 给出上面的textformFiled文本。
只需使用列小部件,第一个子级是 Text,第二个子级是 TextFormField。
我已经实现了自己的 TextField,标题位于表单顶部,基于 sm_sayedi Answer 以及 flutter 提供的来源 input_decorator.dart
import 'package:flutter/material.dart';
class MyTextWidget extends StatefulWidget {
final TextEditingController? controller;
final String? initialValue;
final FocusNode? focusNode;
final InputDecoration decoration;
final TextInputType? keyboardType;
final TextStyle? style;
final bool autofocus;
final bool readOnly;
final int? maxLines;
final int? minLines;
final void Function(String)? onChanged;
final TapRegionCallback? onTapOutside;
final bool? enabled;
const MyTextWidget({
super.key,
this.controller,
this.initialValue,
this.focusNode,
this.decoration = const InputDecoration(),
this.keyboardType,
this.style,
this.autofocus = false,
this.readOnly = false,
this.maxLines = 1,
this.minLines,
this.onChanged,
this.onTapOutside,
this.enabled,
});
@override
State<MyTextWidget> createState() => _MyTextWidgetState();
}
class _MyTextWidgetState extends State<MyTextWidget> with SingleTickerProviderStateMixin {
static const Duration _kTransitionDuration = Duration(milliseconds: 167);
static const Curve _kTransitionCurve = Curves.fastOutSlowIn;
late final FocusNode _focusNode;
late final TextEditingController _controller;
Set<MaterialState> get materialState {
return <MaterialState>{
if (!decoration.enabled) MaterialState.disabled,
if (_focusNode.hasFocus) MaterialState.focused,
};
}
bool get _isEmpty => _controller.value.text.isNotEmpty;
bool get _labelShouldWithdraw => _isEmpty || (_focusNode.hasFocus && decoration.enabled);
bool get _floatingLabelEnabled {
return decoration.floatingLabelBehavior != FloatingLabelBehavior.never;
}
InputDecoration? _effectiveDecoration;
InputDecoration get decoration =>
_effectiveDecoration ??= widget.decoration.applyDefaults(Theme.of(context).inputDecorationTheme);
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.focused)) {
return textStyle.copyWith(color: colors.primary);
}
return textStyle;
});
@override
void initState() {
super.initState();
_controller = widget.controller ?? TextEditingController();
_focusNode = widget.focusNode ?? FocusNode();
_focusNode.addListener(() {
setState(() {});
});
}
@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: _labelShouldWithdraw ? 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) label,
TextFormField(
controller: _controller,
initialValue: widget.initialValue,
focusNode: _focusNode,
decoration: decoration.copyWith(floatingLabelBehavior: FloatingLabelBehavior.never),
keyboardType: widget.keyboardType,
style: widget.style,
autofocus: widget.autofocus,
readOnly: widget.readOnly,
maxLines: widget.maxLines,
minLines: widget.minLines,
onChanged: widget.onChanged,
onTapOutside: widget.onTapOutside,
enabled: widget.enabled,
),
],
);
}
@override
void dispose() {
_focusNode.dispose();
super.dispose();
}
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,
);
}
}