收听StreamingController并更新列表

时间:2018-10-16 13:13:45

标签: dart flutter

我想根据用户在进行流式传输时在搜索窗口小部件中键入的内容来不断更新播放器列表中的值。我知道我不能在玩家的add之后添加where,但我只想让您知道我真正想做的事情。这是我的代码:

load(StreamController controller) async {
var client = http.Client();
var req = http.Request('get', Uri.parse(PRO_PLAYERS_URL_API));
var streamRes = await client.send(req);

streamRes.stream
    .transform(utf8.decoder)
    .transform(json.decoder)
    .expand((e) => e)
    .map((map) => ProPlayer.fromJson(map))
    .pipe(streamController);
}

@override
void initState() {
// TODO: implement initState
super.initState();
streamController = StreamController.broadcast();
streamController.stream
    .listen((player) => setState(() => players.isEmpty ? players.add(player) : players.where((p) => p.alias.startsWith(_searchController.text)).toList().add((player))));

    load(streamController);
}

@override
Widget build(Buildcontext context) {
   return Container(
     padding: const EdgeInsets.symmetric(
       horizontal: 6.0,
       vertical: 4.0,
     ),
      child: Column(
       children: <Widget>[
         Padding(
           padding:
              const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
           child: TextField(
             controller: _searchController,
             decoration: InputDecoration(
                contentPadding: const EdgeInsets.symmetric(vertical: 5.0),
               hintText: 'Search for player...',
               prefixIcon: Icon(Icons.search),
               suffixIcon: IconButton(
                onPressed: () {
                  setState(() {
                    _searchController.clear();
                 });
                },
                icon: Icon(Icons.close),
              ),
              border: OutlineInputBorder(
                 borderRadius: BorderRadius.circular(30.0)),
            ),
          ),
         ), Expanded(
              child: GridView.builder(
                shrinkWrap: true,
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                  crossAxisCount: 3,
                  childAspectRatio: 0.6,
                ),
                itemCount: players.length,
                itemBuilder: (_, int index) =>
                        ProPlayerItem(
                            player: players[index],
                            goToDetail: () => {},
                            goToSteam: () => _launchURL(
                                  players[index].profileUrl,
                                ),
                          ),
              ),
            ),
    ]
   )
  ) 
 }

更新:我希望在我以流方式输入搜索小部件时,gridview保持更新,这可能吗?我尝试了上面的代码,但没有任何反应。

1 个答案:

答案 0 :(得分:1)

为什么您的方法不起作用

基本上,您正在尝试将两个单独的功能组合到一个列表中: 一方面,您要从网络api加载所有播放器,另一方面,您要根据某些条件过滤播放器。

该怎么做

我谦虚的建议是将players分成两个列表:一个用于所有玩家,另一个用于已筛选的玩家(应实际显示的玩家)。

这样做的好处是两种功能可以相互独立地工作:如果用户在加载所有播放器后更改搜索查询,仍然可以通过过滤原始列表来显示有用的结果。

class _SearchWidgetState extends State<SearchWidget> {
  final _searchController = TextEditingController();
  final allPlayers = <ProPlayer>[];
  List<ProPlayer> filteredPlayers = <ProPlayer>[];

  load(StreamController controller) async { ... }

  @override
  void initState() {
    super.initState();

    streamController = StreamController.broadcast();
    streamController.stream.listen((player) {
      allPlayers.add(player);
      _updateSearchResults();
    });

    load(streamController);
  }

  void _updateSearchResults() => setState(() {
    filteredPlayers = allPlayers
      .where((player) => player.alias.startsWith(_searchController.text))
      .toList();
  });

  @override
  Widget build(Buildcontext context) {
    return ...
      TextField(
        controller: _searchController,
        decoration: InputDecoration(
          contentPadding: const EdgeInsets.symmetric(vertical: 5.0),
          hintText: 'Search for player...',
          prefixIcon: Icon(Icons.search),
          suffixIcon: IconButton(
          onPressed: () {
            _updateSearchResults();
            _searchController.clear();
          },
          icon: Icon(Icons.close),
        ),
        border: OutlineInputBorder(borderRadius: BorderRadius.circular(30.0)),
      ),
      ...
      GridView.builder(
        ...
        itemCount: filteredPlayers.length,
        itemBuilder: (_, int index) {
          final player = filteredPlayers[index];

          return ProPlayerItem(
            player: player,
            goToDetail: () => {},
            goToSteam: () => _launchURL(player.profileUrl),
          );
        }
      )
    ...;
  }
}