问题描述
我需要你的建议.我有代码可以从api到ListView提取数据.
i need yur advice .I Have code to fetch data from api to ListView .
问题是,如何在此listview中创建searchview.
The question is , how to create searchview in this listview .
class PM extends StatefulWidget {
@override
_PMState createState() => _PMState();
}
class _PMState extends State<PM> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
void showInSnackBar(String value) {
_scaffoldKey.currentState.showSnackBar(new SnackBar(
content: new Text(value),
backgroundColor: Colors.blueAccent,
));
}
final GlobalKey<RefreshIndicatorState> _refresh =
GlobalKey<RefreshIndicatorState>();
ModelPM modelPM;
ModelPM _modelPM;
bool loading = false;
Future<Null> _fetchData() async {
setState(() => loading = true);
var value;
SharedPreferences preferences = await SharedPreferences.getInstance();
setState(() {
value = preferences.getString("id");
});
final response = await http.post(BaseURL.systemTicket, body: {
"key": BaseURL.apiKey,
"method": "get",
"resource": "tabel_pm",
"filters[adminidtabelpm]": value,
});
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
final pmModelFromJson = ModelPM.fromJson(data);
setState(() {
modelPM = pmModelFromJson;
loading = false;
});
} else {
showInSnackBar("Data Gagal Load");
}
}
@override
void initState() {
super.initState();
_fetchData();
}
_listPM(i) {
final x = modelPM.results[i];
return Card(
elevation: 8.0,
margin: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
child: ListTile(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => DetilPM(x, _fetchData)));
},
contentPadding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0),
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
x.name,
textAlign: TextAlign.start,
style: TextStyle(
fontSize: 12,
color: x.status == "Not Yet"
? Colors.blue
: x.status == "Pending" ? Colors.red : Colors.green,
fontWeight: FontWeight.bold),
),
Text(
'Status : ' + x.status,
textAlign: TextAlign.start,
style: TextStyle(
fontSize: 12,
color: x.status == "Not Yet"
? Colors.blue
: x.status == "Pending" ? Colors.red : Colors.green,
fontWeight: FontWeight.bold),
),
SizedBox(
height: 10,
),
],
),
subtitle: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text("MIDTID",
style: TextStyle(color: Colors.black, fontSize: 10))),
),
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text("TID",
style: TextStyle(color: Colors.black, fontSize: 10))),
),
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text("CSI",
style: TextStyle(color: Colors.black, fontSize: 10))),
),
],
),
Row(
children: <Widget>[
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text(x.midtid,
style: TextStyle(color: Colors.black, fontSize: 10))),
),
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text(x.tid,
style: TextStyle(color: Colors.black, fontSize: 10))),
),
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text(x.csi,
style: TextStyle(color: Colors.black, fontSize: 10))),
),
],
)
],
),
trailing:
Icon(Icons.keyboard_arrow_right, color: Colors.black, size: 30.0),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('PM CIMB List'),
),
key: _scaffoldKey,
body: RefreshIndicator(
onRefresh: _fetchData,
key: _refresh,
child: loading
? Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: modelPM.results.length,
itemBuilder: (context, i) {
return _listPM(i);
},
),
),
);
}
}
并在此模型类PM以下.
and below this model class PM .
class ModelPM {
final int status;
final String status_message;
final List<ModelPMResult> results;
ModelPM({this.status, this.status_message, this.results});
factory ModelPM.fromJson(Map<String, dynamic> json) {
List<ModelPMResult> results = (json['result'] as List)
.map((resultTicketJson) => ModelPMResult.fromJson(resultTicketJson))
.toList();
return ModelPM(
status: json['status'],
status_message: json['status_message'],
results: results,
);
}
}
class ModelPMResult {
final String id;
final String admintabelpm;
final String namaitfs;
final String serial;
final String merchantid;
final String assetid;
final String kondisi_edc;
final String status;
final String detail_edc;
final String note;
final String foto_struk;
final String foto_mesin;
final String foto_toko;
final String kondisi_merchant;
final String request_merchant;
final String tgl_pm;
final String name;
final String batch;
final String idmerchant;
final String midtid;
final String tid;
final String csi;
final String sign;
ModelPMResult({
this.id,
this.admintabelpm,
this.namaitfs,
this.serial,
this.merchantid,
this.assetid,
this.kondisi_edc,
this.status,
this.detail_edc,
this.kondisi_merchant,
this.request_merchant,
this.tgl_pm,
this.name,
this.batch,
this.idmerchant,
this.midtid,
this.tid,
this.csi,
this.foto_mesin,
this.foto_struk,
this.foto_toko,
this.note,
this.sign,
});
factory ModelPMResult.fromJson(Map<String, dynamic> json) {
return new ModelPMResult(
id: json['id'],
admintabelpm: json['id'],
namaitfs: json['namaitfs'],
serial: json['serial'],
merchantid: json['merchantid'],
assetid: json['assetid'],
kondisi_edc: json['kondisi_edc'],
status: json['status'],
detail_edc: json['detail_edc'],
kondisi_merchant: json['kondisi_merchant'],
request_merchant: json['request_merchant'],
tgl_pm: json['tgl_pm'],
name: json['name'],
batch: json['batch'],
idmerchant: json['idmerchant'],
midtid: json['midtid'],
tid: json['tid'],
csi: json['csi'],
note: json['note'],
foto_mesin: json['foto_mesin'],
foto_toko: json['foto_toko'],
foto_struk: json['foto_struk'],
sign: json['sign'],
);
}
}
请提供有关如何在我的Page Flutter中创建listview菜单的建议.谢谢你的建议 .以及在搜索菜单中删除数据后,API中的数据如何返回列表
Please advice for , how to create listview menu in my Page Flutter .Thanks for your advice .and also how after the data is deleted in the search menu, data from the API returns to the list
推荐答案
两种解决方案:您可以在下面复制粘贴运行完整代码
解决方案1:使用当前ListView页面进行搜索,在itemBuilder中返回的数据仅适合您的条件,例如字符串包含,否则不返回Container()
Two solutions : you can copy paste run full code below
Solution 1 : Search use current ListView page, In itemBuilder return data only fit your condition, such as string contains, if not return Container()
ListView.builder(
itemCount: modelPM.results.length,
itemBuilder: (context, i) {
if (myController.text == "") return _listPM(i);
if (myController.text != "" &&
modelPM.results[i].tid.contains(myController.text)) {
return _listPM(i);
} else {
return Container();
}
},
),
演示1
完整代码1
import 'package:flutter/material.dart';
import 'dart:convert';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: PM(),
);
}
}
class PM extends StatefulWidget {
@override
_PMState createState() => _PMState();
}
class _PMState extends State<PM> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
void showInSnackBar(String value) {
_scaffoldKey.currentState.showSnackBar(new SnackBar(
content: new Text(value),
backgroundColor: Colors.blueAccent,
));
}
final GlobalKey<RefreshIndicatorState> _refresh =
GlobalKey<RefreshIndicatorState>();
ModelPM modelPM;
ModelPM _modelPM;
bool loading = false;
Future<Null> _fetchData() async {
setState(() => loading = true);
var value;
/*SharedPreferences preferences = await SharedPreferences.getInstance();
setState(() {
value = preferences.getString("id");
});
final response = await http.post(BaseURL.systemTicket, body: {
"key": BaseURL.apiKey,
"method": "get",
"resource": "tabel_pm",
"filters[adminidtabelpm]": value,
});*/
/* if (response.statusCode == 200) {
final data = jsonDecode(response.body);
final pmModelFromJson = ModelPM.fromJson(data);
setState(() {
modelPM = pmModelFromJson;
loading = false;
});
} else {
showInSnackBar("Data Gagal Load");
}*/
String responsebody = '''
{
"status": 200,
"status_message" : "OK",
"result" : [
{
"id": "123",
"name" : "name1",
"notes" : "notes1",
"midtid" : "midtid1",
"tid" : "tid1",
"csi" : "csi1",
"status" : "abc"
}
,
{
"id": "456",
"name" : "name2",
"notes" : "notes2",
"midtid" : "midtid2",
"tid" : "tid2",
"csi" : "csi2",
"status" : "def"
}
]
}
''';
final data = jsonDecode(responsebody);
final pmModelFromJson = ModelPM.fromJson(data);
setState(() {
modelPM = pmModelFromJson;
loading = false;
});
}
@override
void initState() {
super.initState();
_fetchData();
}
_listPM(i) {
final x = modelPM.results[i];
return Card(
elevation: 8.0,
margin: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
child: ListTile(
onTap: () {
/*Navigator.of(context).push(
MaterialPageRoute(builder: (context) => DetilPM(x, _fetchData)));*/
},
contentPadding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0),
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
x.name,
textAlign: TextAlign.start,
style: TextStyle(
fontSize: 12,
color: x.status == "Not Yet"
? Colors.blue
: x.status == "Pending" ? Colors.red : Colors.green,
fontWeight: FontWeight.bold),
),
Text(
'Status : ' + x.status,
textAlign: TextAlign.start,
style: TextStyle(
fontSize: 12,
color: x.status == "Not Yet"
? Colors.blue
: x.status == "Pending" ? Colors.red : Colors.green,
fontWeight: FontWeight.bold),
),
SizedBox(
height: 10,
),
],
),
subtitle: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text("MIDTID",
style: TextStyle(color: Colors.black, fontSize: 10))),
),
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text("TID",
style: TextStyle(color: Colors.black, fontSize: 10))),
),
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text("CSI",
style: TextStyle(color: Colors.black, fontSize: 10))),
),
],
),
Row(
children: <Widget>[
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text(x.midtid,
style: TextStyle(color: Colors.black, fontSize: 10))),
),
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text(x.tid,
style: TextStyle(color: Colors.black, fontSize: 10))),
),
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text(x.csi,
style: TextStyle(color: Colors.black, fontSize: 10))),
),
],
)
],
),
trailing:
Icon(Icons.keyboard_arrow_right, color: Colors.black, size: 30.0),
),
);
}
final myController = TextEditingController();
@override
void dispose() {
// Clean up the controller when the widget is removed from the
// widget tree.
myController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: TextField(
controller: myController,
decoration:
InputDecoration(border: InputBorder.none, hintText: 'Search'),
onChanged: (value) {
setState(() {});
},
),
),
key: _scaffoldKey,
body: RefreshIndicator(
onRefresh: _fetchData,
key: _refresh,
child: loading
? Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: modelPM.results.length,
itemBuilder: (context, i) {
if (myController.text == "") return _listPM(i);
if (myController.text != "" &&
modelPM.results[i].tid.contains(myController.text)) {
return _listPM(i);
} else {
return Container();
}
},
),
),
);
}
}
class ModelPM {
final int status;
final String status_message;
final List<ModelPMResult> results;
ModelPM({this.status, this.status_message, this.results});
factory ModelPM.fromJson(Map<String, dynamic> json) {
List<ModelPMResult> results = (json['result'] as List)
.map((resultTicketJson) => ModelPMResult.fromJson(resultTicketJson))
.toList();
return ModelPM(
status: json['status'],
status_message: json['status_message'],
results: results,
);
}
}
class ModelPMResult {
final String id;
final String admintabelpm;
final String namaitfs;
final String serial;
final String merchantid;
final String assetid;
final String kondisi_edc;
final String status;
final String detail_edc;
final String note;
final String foto_struk;
final String foto_mesin;
final String foto_toko;
final String kondisi_merchant;
final String request_merchant;
final String tgl_pm;
final String name;
final String batch;
final String idmerchant;
final String midtid;
final String tid;
final String csi;
final String sign;
ModelPMResult({
this.id,
this.admintabelpm,
this.namaitfs,
this.serial,
this.merchantid,
this.assetid,
this.kondisi_edc,
this.status,
this.detail_edc,
this.kondisi_merchant,
this.request_merchant,
this.tgl_pm,
this.name,
this.batch,
this.idmerchant,
this.midtid,
this.tid,
this.csi,
this.foto_mesin,
this.foto_struk,
this.foto_toko,
this.note,
this.sign,
});
factory ModelPMResult.fromJson(Map<String, dynamic> json) {
return new ModelPMResult(
id: json['id'],
admintabelpm: json['id'],
namaitfs: json['namaitfs'],
serial: json['serial'],
merchantid: json['merchantid'],
assetid: json['assetid'],
kondisi_edc: json['kondisi_edc'],
status: json['status'],
detail_edc: json['detail_edc'],
kondisi_merchant: json['kondisi_merchant'],
request_merchant: json['request_merchant'],
tgl_pm: json['tgl_pm'],
name: json['name'],
batch: json['batch'],
idmerchant: json['idmerchant'],
midtid: json['midtid'],
tid: json['tid'],
csi: json['csi'],
note: json['note'],
foto_mesin: json['foto_mesin'],
foto_toko: json['foto_toko'],
foto_struk: json['foto_struk'],
sign: json['sign'],
);
}
}
解决方案2:使用 SearchDelegate
搜索,数据实际上显示在另一页中
单击搜索按钮时,打开另一页
演示
Solution 2 : Search with SearchDelegate
, data actually display in another page
When click search button, open another page
demo
完整的演示代码
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: SearchDemo(),
);
}
}
class SearchDemo extends StatefulWidget {
static const String routeName = '/material/search';
@override
_SearchDemoState createState() => _SearchDemoState();
}
class _SearchDemoState extends State<SearchDemo> {
final _SearchDemoSearchDelegate _delegate = _SearchDemoSearchDelegate();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
int _lastIntegerSelected;
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
leading: IconButton(
tooltip: 'Navigation menu',
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow,
color: Colors.white,
progress: _delegate.transitionAnimation,
),
onPressed: () {
_scaffoldKey.currentState.openDrawer();
},
),
title: const Text('Numbers'),
actions: <Widget>[
IconButton(
tooltip: 'Search',
icon: const Icon(Icons.search),
onPressed: () async {
final int selected = await showSearch<int>(
context: context,
delegate: _delegate,
);
if (selected != null && selected != _lastIntegerSelected) {
setState(() {
_lastIntegerSelected = selected;
});
}
},
),
//MaterialDemoDocumentationButton(SearchDemo.routeName),
IconButton(
tooltip: 'More (not implemented)',
icon: Icon(
Theme.of(context).platform == TargetPlatform.iOS
? Icons.more_horiz
: Icons.more_vert,
),
onPressed: () { },
),
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
MergeSemantics(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
Text('Press the '),
Tooltip(
message: 'search',
child: Icon(
Icons.search,
size: 18.0,
),
),
Text(' icon in the AppBar'),
],
),
const Text('and search for an integer between 0 and 100,000.'),
],
),
),
const SizedBox(height: 64.0),
Text('Last selected integer: ${_lastIntegerSelected ?? 'NONE' }.'),
],
),
),
floatingActionButton: FloatingActionButton.extended(
tooltip: 'Back', // Tests depend on this label to exit the demo.
onPressed: () {
Navigator.of(context).pop();
},
label: const Text('Close demo'),
icon: const Icon(Icons.close),
),
drawer: Drawer(
child: Column(
children: <Widget>[
const UserAccountsDrawerHeader(
accountName: Text('Peter Widget'),
accountEmail: Text('[email protected]'),
currentAccountPicture: CircleAvatar(
backgroundImage: AssetImage(
'people/square/peter.png',
package: 'flutter_gallery_assets',
),
),
margin: EdgeInsets.zero,
),
MediaQuery.removePadding(
context: context,
// DrawerHeader consumes top MediaQuery padding.
removeTop: true,
child: const ListTile(
leading: Icon(Icons.payment),
title: Text('Placeholder'),
),
),
],
),
),
);
}
}
class _SearchDemoSearchDelegate extends SearchDelegate<int> {
final List<int> _data = List<int>.generate(100001, (int i) => i).reversed.toList();
final List<int> _history = <int>[42607, 85604, 66374, 44, 174];
@override
Widget buildLeading(BuildContext context) {
return IconButton(
tooltip: 'Back',
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow,
progress: transitionAnimation,
),
onPressed: () {
close(context, null);
},
);
}
@override
Widget buildSuggestions(BuildContext context) {
final Iterable<int> suggestions = query.isEmpty
? _history
: _data.where((int i) => '$i'.startsWith(query));
return _SuggestionList(
query: query,
suggestions: suggestions.map<String>((int i) => '$i').toList(),
onSelected: (String suggestion) {
query = suggestion;
showResults(context);
},
);
}
@override
Widget buildResults(BuildContext context) {
final int searched = int.tryParse(query);
if (searched == null || !_data.contains(searched)) {
return Center(
child: Text(
'"$query"\n is not a valid integer between 0 and 100,000.\nTry again.',
textAlign: TextAlign.center,
),
);
}
return ListView(
children: <Widget>[
_ResultCard(
title: 'This integer',
integer: searched,
searchDelegate: this,
),
_ResultCard(
title: 'Next integer',
integer: searched + 1,
searchDelegate: this,
),
_ResultCard(
title: 'Previous integer',
integer: searched - 1,
searchDelegate: this,
),
],
);
}
@override
List<Widget> buildActions(BuildContext context) {
return <Widget>[
if (query.isEmpty)
IconButton(
tooltip: 'Voice Search',
icon: const Icon(Icons.mic),
onPressed: () {
query = 'TODO: implement voice input';
},
)
else
IconButton(
tooltip: 'Clear',
icon: const Icon(Icons.clear),
onPressed: () {
query = '';
showSuggestions(context);
},
),
];
}
}
class _ResultCard extends StatelessWidget {
const _ResultCard({this.integer, this.title, this.searchDelegate});
final int integer;
final String title;
final SearchDelegate<int> searchDelegate;
@override
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
return GestureDetector(
onTap: () {
searchDelegate.close(context, integer);
},
child: Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Text(title),
Text(
'$integer',
style: theme.textTheme.headline.copyWith(fontSize: 72.0),
),
],
),
),
),
);
}
}
class _SuggestionList extends StatelessWidget {
const _SuggestionList({this.suggestions, this.query, this.onSelected});
final List<String> suggestions;
final String query;
final ValueChanged<String> onSelected;
@override
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
return ListView.builder(
itemCount: suggestions.length,
itemBuilder: (BuildContext context, int i) {
final String suggestion = suggestions[i];
return ListTile(
leading: query.isEmpty ? const Icon(Icons.history) : const Icon(null),
title: RichText(
text: TextSpan(
text: suggestion.substring(0, query.length),
style: theme.textTheme.subhead.copyWith(fontWeight: FontWeight.bold),
children: <TextSpan>[
TextSpan(
text: suggestion.substring(query.length),
style: theme.textTheme.subhead,
),
],
),
),
onTap: () {
onSelected(suggestion);
},
);
},
);
}
}
这篇关于如何在列表颤动中创建SearchView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!