场景:这是一个大表单,用户选择TextFormField
,然后手动向下滚动到“保存”按钮。如果_formKey.currentState.validate()
检测到验证问题,我们可以将焦点移回出现问题的TextFormField
。
首先,我们调用_myFocusNode.unfocus();
//这是有效的,因为关键字是自动关闭的。接下来,我们调用FocusScope.of(context).requestFocus(_myFocusNode)
//这也是有效的,因为我们可以在之后立即开始键入。但是,FocusScope.of(context).requestFocus
不会自动滚动回TextFormField
。
如果我们尝试另一个TextFormField
(Tfield 2)而不是最后选择的,Tfield 2获得焦点,滚动也使其可见。
注:如果我们再次开始键入,则会执行滚动,并且TextFormField
变为可见。
https://github.com/flutter/flutter/issues/58877
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Material App',
theme: ThemeData.dark(),
home: Home(),
);
}
}
class Home extends StatefulWidget {
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
bool show = false;
TextEditingController cnt1 = new TextEditingController();
TextEditingController cnt2 = new TextEditingController();
TextEditingController cnt3 = new TextEditingController();
TextEditingController cnt4 = new TextEditingController();
TextEditingController cnt5 = new TextEditingController();
TextEditingController cnt6 = new TextEditingController();
TextEditingController cnt7 = new TextEditingController();
TextEditingController cnt8 = new TextEditingController();
FocusNode _focuserr;
FocusNode _focus1;
FocusNode _focus2;
FocusNode _focus3;
FocusNode _focus4;
FocusNode _focus5;
FocusNode _focus6;
FocusNode _focus7;
FocusNode _focus8;
@override
void dispose() {
// Clean up the focus node when the Form is disposed.
_focuserr.dispose();
_focus1.dispose();
_focus2.dispose();
_focus3.dispose();
_focus4.dispose();
_focus5.dispose();
_focus6.dispose();
_focus7.dispose();
_focus8.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
_focus1 = new FocusNode();
_focus2 = new FocusNode();
_focus3 = new FocusNode();
_focus4 = new FocusNode();
_focus5 = new FocusNode();
_focus6 = new FocusNode();
_focus7 = new FocusNode();
_focus8 = new FocusNode();
return Scaffold(
appBar: AppBar(
title: Text('Material App Bar'),
),
body: Center(
child: Container(
child: Text('Hello World'),
),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => StatefulBuilder(
builder: (context, setState) {
return Padding(
padding: EdgeInsets.only(left:10, right: 10, bottom: MediaQuery.of(context).viewInsets.bottom + 5),
child: Container(
height: 300,
child: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
createTextField(cnt1, _focus1, 1),
createTextField(cnt2, _focus2, 2),
createTextField(cnt3, _focus3, 3),
createTextField(cnt4, _focus4, 4),
createTextField(cnt5, _focus5, 5),
createTextField(cnt6, _focus6, 6),
createTextField(cnt7, _focus7, 7),
createTextField(cnt8, _focus8, 8),
RaisedButton(
child: Text('Validate'),
onPressed: () {
_validateInputs(context);
})
],
),
),
),
),
);
},
),
);
},
icon: Icon(Icons.add),
label: Text('bottomsheet'),
),
);
}
Widget createTextField(TextEditingController c, FocusNode f, int id){
return Padding(
padding: const EdgeInsets.only(
top: 5, bottom: 5, left: 10, right: 10),
child: Container(
color: Colors.lightBlue.withOpacity(0.3),
child:
TextFormField(
controller: c,
focusNode: f,
validator: (val) {
var result = isNotNull(val);
if(result != null && _focuserr == null)
_focuserr = f;
return result;
},
decoration: InputDecoration(
counterText : "",
hintStyle: TextStyle(fontSize: 17),
hintText: 'TXT$id',
border: InputBorder.none,
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.blue[300], width: 0.3)),
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
contentPadding: const EdgeInsets.only(left: 10, top: 0),
),
),
)
);
}
void _validateInputs(BuildContext cnt) {
final form = _formKey.currentState;
_focuserr = null;
if (form.validate()) {
form.save();
}
else
{
setState(() {
FocusManager.instance.primaryFocus.unfocus();
FocusScope.of(cnt).requestFocus(_focuserr);
});
}
}
String isNotNull(String val) =>
(val.length == 0) ? 'Cannot be empty' : null;
}
2条答案
按热度按时间9jyewag01#
碰巧是一个已确认的问题,在稳定的v17以及较新的开发通道
drkbr07n2#
这个问题一直存在到现在,you can followup it here,所以我临时解决了这个问题,如下所示:
1-将
FocusNode
定义为如下列表:2-将
FocusNode
传递到输入,如下所示:3-在调用
validate()
之前调用_unFocusNodes()
,如下所示(技巧如下):