Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
129 views
in Technique[技术] by (71.8m points)

Flutter: How to implement Toolbar Search View to show data between 2 State

I have JSON like this (API):

[
  {
    "country": "United States",
    "continent": "North America",
    "code": "us"
  },
  {
    "country": "Mexico",
    "continent": "North America",
    "code": "mx"
  },
  {
    "country": "Canada",
    "continent": "North America",
    "code": "ca"
  },
  {
    "country": "Guatemala",
    "continent": "North America",
    "code": "gt"
  },
  {
    "country": "Cuba",
    "continent": "North America",
    "code": "cu"
  },
  {
    "country": "Haiti",
    "continent": "North America",
    "code": "ht"
  },
  {
    "country": "Russia",
    "continent": "Europe",
    "code": "ru"
  },
  {
    "country": "Ukraine",
    "continent": "Europe",
    "code": "ua"
  },
  {
    "country": "France",
    "continent": "Europe",
    "code": "fr"
  },
  {
    "country": "Spain",
    "continent": "Europe",
    "code": "es"
  },
  {
    "country": "Sweden",
    "continent": "Europe",
    "code": "se"
  },
  {
    "country": "Norway",
    "continent": "Europe",
    "code": "no"
  }
]

I want to implement Toolbar Search View like this:

enter image description here

I have found some basic tutorials and tried it out, however, to combine 2 states while keeping Gridview form is too difficult for a newbie like me. So please help me, this is the main file

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:load_data/search_model.dart';

class SearchPage extends StatefulWidget {
  @override
  _SearchPageState createState() => _SearchPageState();
}

class _SearchPageState extends State<SearchPage> {
  List<String> _tabs = ['North America', 'Europe'];
  TextEditingController _searchQueryController = TextEditingController();
  bool _isSearching = false;
  String searchQuery = "Search query";

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: _tabs.length,
      child: Scaffold(
        appBar: AppBar(
          title: Text('List Country'),
          bottom: TabBar(
            tabs: _tabs.map((String name) => Tab(child: Text(name))).toList(),
          ),
        ),
        body: FutureBuilder(
            future: SearchServices.getData(),
            builder: (BuildContext context, AsyncSnapshot snapshot) {
              List<Widget> children;
              List<Search> _search = snapshot.data;
              if (snapshot.hasData) {
                return TabBarView(
                  children: _tabs.map((String name) {
                    return ShowList(search: List<Search>.from(_search)..retainWhere((e) => e.continent == name));
                  }).toList(),
                );
              } else {
                children = <Widget>[SizedBox(child: CircularProgressIndicator(), width: 60, height: 60), const Padding(padding: EdgeInsets.only(top: 16), child: Text('Loading...'))];
              }
              return Center(child: Column(mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: children));
            }),
      ),
    );
  }
}

class ShowList extends StatelessWidget {
  final List<Search> search;

  const ShowList({Key key, this.search}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
      itemCount: search.length,
      itemBuilder: (BuildContext context, int index) {
        Search s = search[index];
        return Card(
          child: Column(children: [
            Text(s.country),
            Image.network('https://www.countryflags.io/${s.code}/flat/64.png'),
          ]),
        );
      },
    );
  }
}

class SearchServices {
  static const String url = 'https://firebasestorage.googleapis.com/v0/b/tft-test-48c87.appspot.com/o/search.json?alt=media&token=08236daf-cc72-4c3b-b052-7822f8790b12';

  static Future<List<Search>> getData() async {
    try {
      final response = await http.get(url);
      if (200 == response.statusCode) {
        final List<Search> data = searchFromJson(response.body);
        return data;
      } else {
        return List<Search>();
      }
    } catch (e) {
      return List<Search>();
    }
  }
}

...............................................................

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can copy paste run full code below
You can filter searchQuery in ShowList

code snippet

TextField(
            decoration: InputDecoration(
              hintText: "Country Search",
              suffixIcon: Icon(Icons.search),
            ),
            controller: _searchQueryController,
            onChanged: (value) {
              searchQuery = value;
              setState(() {});
            },
          )
...
const ShowList({Key key, this.search}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    var detail = search
        .where(
            (s) => s.country.toLowerCase().contains(searchQuery.toLowerCase()))
        .toList();
    return GridView.builder(
      gridDelegate:
          SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
      itemCount: detail.length,
      itemBuilder: (BuildContext context, int index) {
        Search s = detail[index];

working demo

enter image description here

full code

import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;

List<Search> searchFromJson(String str) =>
    List<Search>.from(json.decode(str).map((x) => Search.fromJson(x)));

String searchToJson(List<Search> data) =>
    json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

class Search {
  Search({
    this.country,
    this.continent,
    this.code,
  });

  String country;
  String continent;
  String code;

  factory Search.fromJson(Map<String, dynamic> json) => Search(
        country: json["country"],
        continent: json["continent"],
        code: json["code"],
      );

  Map<String, dynamic> toJson() => {
        "country": country,
        "continent": continentValues.reverse[continent],
        "code": code,
      };
}

enum Continent { NORTH_AMERICA, EUROPE }

final continentValues = EnumValues(
    {"Europe": Continent.EUROPE, "North America": Continent.NORTH_AMERICA});

class EnumValues<T> {
  Map<String, T> map;
  Map<T, String> reverseMap;

  EnumValues(this.map);

  Map<T, String> get reverse {
    if (reverseMap == null) {
      reverseMap = map.map((k, v) => new MapEntry(v, k));
    }
    return reverseMap;
  }
}

class SearchPage extends StatefulWidget {
  @override
  _SearchPageState createState() => _SearchPageState();
}

String searchQuery = "";

class _SearchPageState extends State<SearchPage> {
  List<String> _tabs = ['North America', 'Europe'];
  TextEditingController _searchQueryController = TextEditingController();
  bool _isSearching = false;

  Future<List<Search>> _future;

  @override
  void initState() {
    _future = SearchServices.getData();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: _tabs.length,
      child: Scaffold(
        appBar: AppBar(
          title: TextField(
            decoration: InputDecoration(
              hintText: "Country Search",
              suffixIcon: Icon(Icons.search),
            ),
            controller: _searchQueryController,
            onChanged: (value) {
              searchQuery = value;
              setState(() {});
            },
          ),
          bottom: TabBar(
            tabs: _tabs.map((String name) => Tab(child: Text(name))).toList(),
          ),
        ),
        body: FutureBuilder(
            future: _future,
            builder: (BuildContext context, AsyncSnapshot snapshot) {
              List<Widget> children;
              List<Search> _search = snapshot.data;
              if (snapshot.hasData) {
                return TabBarView(
                  children: _tabs.map((String name) {
                    return ShowList(
                        search: List<Search>.from(_search)
                          ..retainWhere((e) => e.continent == name));
                  }).toList(),
                );
              } else {
                children = <Widget>[
                  SizedBox(
                      child: CircularProgressIndicator(),
                      width: 60,
                      height: 60),
                  const Padding(
                      padding: EdgeInsets.only(top: 16),
                      child: Text('Loading...'))
                ];
              }
              return Center(
                  child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      crossAxisAlignment: CrossAxisAlignment.center,
                      children: children));
            }),
      ),
    );
  }
}

class ShowList extends StatelessWidget {
  final List<Search> search;

  const ShowList({Key key, this.search}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    var detail = search
        .where(
            (s) => s.country.toLowerCase().contains(searchQuery.toLowerCase()))
        .toList();
    return GridView.builder(
      gridDelegate:
          SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
      itemCount: detail.length,
      itemBuilder: (BuildContext context, int index) {
        Search s = detail[index];
        return Card(
          child: Column(children: [
            Text(s.country),
            Image.network('https://www.countryflags.io/${s.code}/flat/64.png'),
          ]),
        );
      },
    );
  }
}

class SearchServices {
  static const String url =
      'https://firebasestorage.googleapis.com/v0/b/tft-test-48c87.appspot.com/o/search.json?alt=media&token=08236daf-cc72-4c3b-b052-7822f8790b12';

  static Future<List<Search>> getData() async {
    try {
      final response = await http.get(url);
      if (200 == response.statusCode) {
        final List<Search> data = searchFromJson(response.body);
        return data;
      } else {
        return List<Search>();
      }
    } catch (e) {
      return List<Search>();
    }
  }
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: SearchPage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...