【问题标题】:How Create SearchView in List Flutter如何在 List Flutter 中创建 SearchView
【发布时间】:2019-11-30 12:44:45
【问题描述】:

我需要你的建议。 我有从 api 获取数据到 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。

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 中创建列表视图菜单。 谢谢你的建议 。 以及在搜索菜单中删除数据后,API中的数据如何返回列表

【问题讨论】:

    标签: android search flutter dart


    【解决方案1】:

    两种解决方案:您可以在下面复制粘贴运行完整代码
    解决方案1:使用当前ListView页面搜索,在itemBuilder中返回数据只适合你的条件,如字符串包含,如果不返回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搜索,数据实际显示在另一个页面
    当点击搜索按钮时,打开另一个页面
    演示

    完整的演示代码

    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('peter.widget@example.com'),
                  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);
              },
            );
          },
        );
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-12-18
      • 1970-01-01
      • 1970-01-01
      • 2016-07-10
      • 2016-04-13
      • 1970-01-01
      • 2022-11-19
      • 2018-02-07
      • 1970-01-01
      相关资源
      最近更新 更多