英文:
Enable/Disable button when TextField has input inside a BottomSheet
问题
我要在BottomSheet内有一个简单的TextField和一个TextButton。只有在TextField中有文本时,TextButton才应该处于启用状态。然而,它只在我点击屏幕或按下回车键时启用/禁用按钮。我希望它能实时更改。
以下是我的完整代码:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyBottomSheet(),
);
}
}
class MyBottomSheet extends StatefulWidget {
@override
_MyBottomSheetState createState() => _MyBottomSheetState();
}
class _MyBottomSheetState extends State<MyBottomSheet> {
late TextEditingController _textController;
bool _isButtonDisabled = true;
@override
void initState() {
super.initState();
_textController = TextEditingController();
_textController.addListener(_onTextChanged);
}
void _onTextChanged() {
setState(() {
_isButtonDisabled = _textController.text.isEmpty;
});
}
@override
void dispose() {
_textController.dispose();
super.dispose();
}
void _showBottomSheet() {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: Container(
height: 300,
width: double.infinity,
child: Column(
children: [
TextField(
controller: _textController,
autofocus: true,
decoration: const InputDecoration(
contentPadding: EdgeInsets.symmetric(horizontal: 15),
hintText: '输入姓名...',
),
),
TextButton(
onPressed: _isButtonDisabled ? null : () {
// 在这里处理按钮点击事件
},
child: const Text('保存'),
)
],
),
),
);
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('测试'),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
floatingActionButton: FloatingActionButton(
shape: CircleBorder(),
onPressed: _showBottomSheet,
child: Icon(Icons.add_rounded),
),
bottomNavigationBar: BottomAppBar(
height: 60,
shape: CircularNotchedRectangle(),
notchMargin: 8.0,
clipBehavior: Clip.antiAlias,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
onPressed: () {},
icon: Icon(Icons.more_horiz_rounded),
),
IconButton(
onPressed: () {},
icon: Icon(Icons.menu_rounded),
)
],
),
),
);
}
}
我在BottomSheet之外尝试了相同的方法,它可以正常工作。
英文:
I want to have a simple TextField and a TextButton inside a BottomSheet. The TextButton should only be enabled if there is some text in the TextField. However it only enables/disables the button when I click the screen or enter. I want it to change in real time.
Here is my full code:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyBottomSheet(),
);
}
}
class MyBottomSheet extends StatefulWidget {
@override
_MyBottomSheetState createState() => _MyBottomSheetState();
}
class _MyBottomSheetState extends State<MyBottomSheet> {
late TextEditingController _textController;
bool _isButtonDisabled = true;
@override
void initState() {
super.initState();
_textController = TextEditingController();
_textController.addListener(_onTextChanged);
}
void _onTextChanged() {
setState(() {
_isButtonDisabled = _textController.text.isEmpty;
});
}
@override
void dispose() {
_textController.dispose();
super.dispose();
}
void _showBottomSheet() {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom
),
child: Container(
height: 300,
width: double.infinity,
child: Column(
children: [
TextField(
controller: _textController,
autofocus: true,
decoration: const InputDecoration(
contentPadding: EdgeInsets.symmetric(horizontal: 15),
hintText: 'Enter name...',
),
),
TextButton(
onPressed: _isButtonDisabled ? null : () {
},
child: const Text('Save'),
)
],
),
),
);
}
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('TEST'),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked ,
floatingActionButton: FloatingActionButton(
shape: CircleBorder(),
onPressed: (_showBottomSheet),
child: Icon(Icons.add_rounded),
),
bottomNavigationBar: BottomAppBar(
height: 60,
shape: CircularNotchedRectangle(),
notchMargin: 8.0,
clipBehavior: Clip.antiAlias,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
onPressed: () {},
icon: Icon(Icons.more_horiz_rounded),
),
IconButton(
onPressed: () {},
icon: Icon(Icons.menu_rounded)
)
],
),
),
);
}
void _onSubmit() {
// Handle form submission here
}
}
I tried the same approach outside the BottomSheet and it works fine.
答案1
得分: 0
以下是您要翻译的内容:
你必须将模态内容移到一个单独的StatefulWidget,如下所示
```dart
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyBottomSheet(),
);
}
}
class MyBottomSheet extends StatefulWidget {
@override
State<MyBottomSheet> createState() => _MyBottomSheetState();
}
class _MyBottomSheetState extends State<MyBottomSheet> {
late TextEditingController _textController;
@override
void initState() {
super.initState();
_textController = TextEditingController();
}
@override
void dispose() {
_textController.dispose();
super.dispose();
}
void _showBottomSheet() {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return ModalContent(controller: _textController);
}
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('TEST'),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked ,
floatingActionButton: FloatingActionButton(
shape: const CircleBorder(),
onPressed: (_showBottomSheet),
child: const Icon(Icons.add_rounded),
),
bottomNavigationBar: BottomAppBar(
height: 60,
shape: const CircularNotchedRectangle(),
notchMargin: 8.0,
clipBehavior: Clip.antiAlias,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
onPressed: () {},
icon: const Icon(Icons.more_horiz_rounded),
),
IconButton(
onPressed: () {},
icon: const Icon(Icons.menu_rounded)
)
],
),
),
);
}
void _onSubmit() {
// 处理表单提交
}
}
class ModalContent extends StatefulWidget {
final TextEditingController controller;
const ModalContent({super.key, required this.controller});
@override
State<ModalContent> createState() => _ModalContentState();
}
class _ModalContentState extends State<ModalContent> {
bool _isButtonDisabled = true;
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom
),
child: Container(
height: 300,
width: double.infinity,
child: Column(
children: [
TextField(
controller: widget.controller,
autofocus: true,
decoration: const InputDecoration(
contentPadding: EdgeInsets.symmetric(horizontal: 15),
hintText: '输入姓名...',
),
onChanged: (value) {
print("值为空 : ${value.isEmpty}");
setState(() {
_isButtonDisabled = value.isEmpty;
});
}
),
TextButton(
onPressed: _isButtonDisabled ? null : () {
},
child: const Text('保存'),
)
],
),
),
);
}
}
<details>
<summary>英文:</summary>
You must move Modal content into a separated StatefulWidget like bellow
```dart
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyBottomSheet(),
);
}
}
class MyBottomSheet extends StatefulWidget {
@override
State<MyBottomSheet> createState() => _MyBottomSheetState();
}
class _MyBottomSheetState extends State<MyBottomSheet> {
late TextEditingController _textController;
@override
void initState() {
super.initState();
_textController = TextEditingController();
}
@override
void dispose() {
_textController.dispose();
super.dispose();
}
void _showBottomSheet() {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return ModalContent(controller: _textController);
}
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('TEST'),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked ,
floatingActionButton: FloatingActionButton(
shape: const CircleBorder(),
onPressed: (_showBottomSheet),
child: const Icon(Icons.add_rounded),
),
bottomNavigationBar: BottomAppBar(
height: 60,
shape: const CircularNotchedRectangle(),
notchMargin: 8.0,
clipBehavior: Clip.antiAlias,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
onPressed: () {},
icon: const Icon(Icons.more_horiz_rounded),
),
IconButton(
onPressed: () {},
icon: const Icon(Icons.menu_rounded)
)
],
),
),
);
}
void _onSubmit() {
// Handle form submission here
}
}
class ModalContent extends StatefulWidget {
final TextEditingController controller;
const ModalContent({super.key, required this.controller});
@override
State<ModalContent> createState() => _ModalContentState();
}
class _ModalContentState extends State<ModalContent> {
bool _isButtonDisabled = true;
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom
),
child: Container(
height: 300,
width: double.infinity,
child: Column(
children: [
TextField(
controller: widget.controller,
autofocus: true,
decoration: const InputDecoration(
contentPadding: EdgeInsets.symmetric(horizontal: 15),
hintText: 'Enter name...',
),
onChanged: (value) {
print("Value is empty : ${value.isEmpty}");
setState(() {
_isButtonDisabled = value.isEmpty;
});
}
),
TextButton(
onPressed: _isButtonDisabled ? null : () {
},
child: const Text('Save'),
)
],
),
),
);
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论