Dart 侦听StreamingController并更新列表

Dart 侦听StreamingController并更新列表,dart,flutter,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.sen

我想根据用户在搜索窗口小部件中键入的内容不断更新我的播放器列表中的值。我知道我不能在玩家中添加
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,
                                ),
                          ),
              ),
            ),
    ]
   )
  ) 
 }
load(StreamController)异步{
var client=http.client();
var req=http.Request('get',Uri.parse(PRO_PLAYERS\u URL\u API));
var streamRes=等待客户端发送(req);
溪流
.变换(utf8.解码器)
.transform(json.decoder)
.展开((e)=>e)
.map((map)=>ProPlayer.fromJson(map))
.管道(流量控制器);
}
@凌驾
void initState(){
//TODO:实现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)));
负载(流量控制器);
}
@凌驾
小部件构建(构建上下文){
返回容器(
填充:const EdgeInsets.symmetric(
水平:6.0,
垂直线:4.0,
),
子:列(
儿童:[
填充物(
衬垫:
常数边集对称(水平:16.0,垂直:8.0),
孩子:TextField(
控制器:\ u搜索控制器,
装饰:输入装饰(
contentPadding:const EdgeInsets.对称(垂直:5.0),
hintText:'搜索玩家…',
前缀:图标(Icons.search),
后缀:图标按钮(
已按下:(){
设置状态(){
_searchController.clear();
});
},
图标:图标(Icons.close),
),
边框:大纲输入边框(
边界半径:边界半径。圆形(30.0)),
),
),
),扩大(
子项:GridView.builder(
收缩膜:对,
gridDelegate:SliverGridDelegateWithFixedCrossAxisCount(
交叉轴计数:3,
childAspectRatio:0.6,
),
itemCount:players.length,
itemBuilder:(\ux,int index)=>
原岩(
玩家:玩家[索引],
goToDetail:()=>{},
goToSteam:()=>\u启动URL(
玩家[index].profileUrl,
),
),
),
),
]
)
) 
}

更新:我希望gridview在我输入搜索小部件的同时不断更新,这可能吗?我尝试了上面的代码,但没有任何结果。

为什么您的方法不起作用

基本上,您正在尝试将两个单独的功能合并到一个列表中: 一方面,您希望从web api加载所有播放器,另一方面,您希望根据某些条件对其进行筛选

该怎么办

我拙劣的建议是将
玩家
分为两个列表:一个用于所有玩家,另一个用于过滤的玩家(实际应显示的玩家)

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

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),
          );
        }
      )
    ...;
  }
}
class\u SearchWidgetState扩展状态{
final _searchController=TextEditingController();
最终所有玩家=[];
列出filteredPlayers=[];
加载(StreamController)异步{…}
@凌驾
void initState(){
super.initState();
streamController=streamController.broadcast();
streamController.stream.listen((播放器){
所有玩家。添加(玩家);
_updateSearchResults();
});
负载(流量控制器);
}
void _updateSearchResults()=>setState(){
filteredPlayers=所有玩家
.where((player)=>player.alias.startsWith(_searchController.text))
.toList();
});
@凌驾
小部件构建(构建上下文){
返回。。。
文本字段(
控制器:\ u搜索控制器,
装饰:输入装饰(
contentPadding:const EdgeInsets.对称(垂直:5.0),
hintText:'搜索玩家…',
前缀:图标(Icons.search),
后缀:图标按钮(
已按下:(){
_updateSearchResults();
_searchController.clear();
},
图标:图标(Icons.close),
),
边框:大纲输入边框(边框半径:borderRadius.circular(30.0)),
),
...
GridView.builder(
...
itemCount:filteredPlayers.length,
itemBuilder:(\ux,int索引){
最终玩家=过滤层[索引];
返回属性(
玩家:玩家,
goToDetail:()=>{},
goToSteam:()=>_launchURL(player.profileUrl),
);
}
)
...;
}
}

我意识到我必须添加
toList()
where
之后,但仍然没有运气你到底想做什么?按照我的理解,你想提供一些搜索功能,从而根据
\u searchController
中给定的搜索词过滤玩家列表。但是你的示例代码有很多方面我不明白:什么
streamController
应该做什么?加载调用做什么?你如何将搜索结果集成到
构建
功能中?如果你能解释一下你当前的架构应该如何工作,我相信它会更容易帮助你解决你的问题