英文:
How to set state and re render a ModalRoute
问题
我有一个搜索模态弹窗,用户可以在其中搜索并根据他们的搜索获取结果。然而,由于该类扩展了ModalRoute而不是StatefulWidget,调用setState不会重新渲染构建,搜索结果不会显示在屏幕上。有没有一种方法可以更新状态或重新渲染屏幕,而不必将该类转换为StatefulWidget?
class JobSearchModal extends ModalRoute {
List<dynamic>? searchResults;
@override
Duration get transitionDuration => const Duration(milliseconds: 250);
@override
bool get opaque => false;
@override
bool get barrierDismissible => false;
@override
Color get barrierColor => Colors.black;
@override
String? get barrierLabel => null;
@override
bool get maintainState => true;
getSearch(String query) async {
var result = await SearchService().getAllPaged(query: query);
setState(() {
searchResults = result;
});
}
_onSearchChanged(String query) {
getSearch(query);
}
@override
Widget buildPage(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: TextField(
onChanged: _onSearchChanged,
autofocus: true,
),
),
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Cancel'))
],
),
const SizedBox(
height: 20,
),
...searchResults?.map(
(search) {
return ListTile(
title: Text(search.title),
);
},
) ?? []
],
),
),
),
);
}
}
请注意,上述代码中的 searchResults
使用了可选链操作符 (?.
) 来处理可能为null的情况。
英文:
I have Search Modal popup where the user can search and get results based on their search. However, since the class extends ModalRoute and not a StatefulWidget, calling setState does not re-render the build and the search results do no appear on the screen. Is there a way to update the state or re-render the screen without having to convert the class to a StatefulWidfet?
class JobSerachModal extends ModalRoute {
List<dynamic>? searchResults;
@override
Duration get transitionDuration => const Duration(milliseconds: 250);
@override
bool get opaque => false;
@override
bool get barrierDismissible => false;
@override
Color get barrierColor => Colors.black;
@override
String? get barrierLabel => null;
@override
bool get maintainState => true;
getSearch(String query) async {
var result = await SearchService().getAllPaged(query: query);
setState(() {
searchResults = result;
});
}
_onSearchChanged(String query) {
getSearch(query);
}
@override
Widget buildPage(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: TextField(
onChanged: _onSearchChanged,
autofocus: true,
),
),
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Cancel'))
],
),
const SizedBox(
height: 20,
),
...searchResults.map(
(search) {
return ListTile(
title: Text(search.title),
);
},
)
],
),
),
),
);
}
}
答案1
得分: 1
Flutters setState()
方法仅在StatefulWidget
中可用,用于在状态更改时重建小部件。您不能从ModalRoute
中调用setState()
方法,因为它在那里不存在。
您可以使用ValueNotifier
和ValueListenableBuilder
来实现您的目标。
代码:
// 定义一个扩展ModalRoute的新类JobSearchModal
class JobSearchModal extends ModalRoute {
// 声明一个ValueNotifier,每当搜索结果发生变化时,它将通知所有监听器
final ValueNotifier<List<dynamic>> searchResults = ValueNotifier<List<dynamic>>([]);
// 设置转场的持续时间
@override
Duration get transitionDuration => const Duration(milliseconds: 250);
@override
bool get opaque => false;
@override
bool get barrierDismissible => false;
@override
Color get barrierColor => Colors.black;
@override
String? get barrierLabel => null;
@override
bool get maintainState => true;
// 定义此异步函数以获取搜索结果
getSearch(String query) async {
var result = await SearchService().getAllPaged(query: query);
searchResults.value = result;
}
// 定义在搜索查询更改时执行的函数
_onSearchChanged(String query) {
getSearch(query);
}
@override
Widget buildPage(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: TextField(
onChanged: _onSearchChanged,
autofocus: true,
),
),
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Cancel'))
],
),
const SizedBox(
height: 20,
),
ValueListenableBuilder(
valueListenable: searchResults,
builder: (context, value, child) {
return Column(
children: value.map(
(search) {
return ListTile(
title: Text(search.title),
);
},
).toList(),
);
},
)
],
),
),
),
);
}
}
(Note: I've removed HTML encoding for special characters like <
and >
in your code.)
英文:
Flutters setState()
method is only available within a StatefulWidget
to rebuild the widgets when there is a state change. You can not call setState()
method from ModalRoute
since it doesn't exist there.
You could use ValueNotifier
and ValueListenableBuilder
to achieve your goal.
The Code:
// Define a new class JobSearchModal that extends ModalRoute
class JobSearchModal extends ModalRoute {
// Declare a ValueNotifier which will notify all the listeners whenever there's a change in search results
final ValueNotifier<List<dynamic>> searchResults = ValueNotifier<List<dynamic>>([]);
// Set duration of transition
@override
Duration get transitionDuration => const Duration(milliseconds: 250);
@override
bool get opaque => false;
@override
bool get barrierDismissible => false;
@override
Color get barrierColor => Colors.black;
@override
String? get barrierLabel => null;
@override
bool get maintainState => true;
// Define this asynchronous function to get search results
getSearch(String query) async {
var result = await SearchService().getAllPaged(query: query);
searchResults.value = result;
}
// Define a function that gets executed when a search query changes
_onSearchChanged(String query) {
getSearch(query);
}
@override
Widget buildPage(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: TextField(
onChanged: _onSearchChanged,
autofocus: true,
),
),
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Cancel'))
],
),
const SizedBox(
height: 20,
),
ValueListenableBuilder(
valueListenable: searchResults,
builder: (context, value, child) {
return Column(
children: value.map(
(search) {
return ListTile(
title: Text(search.title),
);
},
).toList(),
);
},
)
],
),
),
),
);
}
}
答案2
得分: 0
StatefulBuilder(
builder: (BuildContext context, setState) {
return ;
},
),
Use StatefulBuilder
Example:
await showDialog<void>(
context: context,
builder: (BuildContext context) {
int? selectedRadio = 0;
return AlertDialog(
content: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Column(
mainAxisSize: MainAxisSize.min,
children: List<Widget>.generate(4, (int index) {
return Radio<int>(
value: index,
groupValue: selectedRadio,
onChanged: (int? value) {
setState(() => selectedRadio = value);
},
);
}),
);
},
),
);
},
);
英文:
StatefulBuilder(
builder: (BuildContext context, setState) {
return ;
},
),
Use StatefulBuilder
Example:
await showDialog<void>(
context: context,
builder: (BuildContext context) {
int? selectedRadio = 0;
return AlertDialog(
content: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Column(
mainAxisSize: MainAxisSize.min,
children: List<Widget>.generate(4, (int index) {
return Radio<int>(
value: index,
groupValue: selectedRadio,
onChanged: (int? value) {
setState(() => selectedRadio = value);
},
);
}),
);
},
),
);
},
);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论