使用StreamBuilder为CustomScrollView生成SliverList

时间:2019-11-19 01:02:19

标签: flutter dart stream-builder customscrollview

这可能是一个很容易解决的问题,但是我认为无论如何我还是要问:CustomScrollView内是否有任何方法可以固定一个小部件?我想使用CustomScrollView来支持应用栏中的灵活空间,但是我需要使输入小部件固定在屏幕底部。我尝试使用给定的小部件将CustomScrollView嵌套到Column中,但似乎不起作用:

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        CustomScrollView(
          slivers: <Widget>[
            _buildAppBar(), // Returns a SliverAppBar
            _buildMessages(), // Returns a StreamBuilder that returns a SliverList
          ],
        ),
        MessageInputWidget(), // Input that needs to stay fixed
      ],
    );
  }

这是_buildMessages()方法:

  Widget _buildMessages(BuildContext context) {
    return StreamBuilder<List<Message>>(
        stream: widget.classroom.messages(),
        builder: (context, snapshot) {
          print('[DEBUG] Building chat with updated message stream...');
          if (!snapshot.hasData || snapshot.data == null) {
            return Center(
              child: CircularProgressIndicator(),
            );
          }
          _messages = snapshot.data;
          print('[DEBUG] Building ${_messages.length} messages...');
          return SliverList(
            delegate: SliverChildBuilderDelegate(
              (BuildContext context, int index) {
        if (index == _messages.length) {
        return _buildHeader(context);
        }
        return MessageWidget(
        message: _messages[index],
        isReceived: _user.id != _messages[index].sentBy.id,
        showUser: (index ==
        0) || // Show _avatar if it's the first msg
        (index >=
        1 && // Or if it's a different _user than the last
        !(_messages[index].sentBy.id ==
        _messages[index - 1].sentBy.id)),
        );
              },
              childCount: _messages.length,
            ),
          );
        });
  }

有什么建议吗?我找到了一些examples,但是它可以构建整个CustomScrollView,而我只想在每次获得新快照时都构建SliverList。 有什么建议吗?

1 个答案:

答案 0 :(得分:0)

是的,但是您没有将其放入自定义滚动中,因此使用了堆栈小部件。它将分层的小部件放在屏幕上。下面是您之前提出的内容。为了使窗口小部件位于底部,必须使用带有展开的列。

  Stack(
      children: <Widget>[
        yourStreamBuilder(),
        Column(
          children: <Widget>[
            Expanded(child: Container()),
            Container(
              width: MediaQuery.of(context).size.width,
              height: 44,
              color: Colors.red,
              child: Text("Your bottom container"),
            )
          ],
        ),
      ],
    )

完整示例:

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(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

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

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

class _MyHomePageState extends State<MyHomePage> {
  Map<String, dynamic> tocando = {};
  String ultimoTocando;

  Future<List<Map<String, dynamic>>> listaDeMusicas() async {
    return List<Map<String, dynamic>>.generate(
      1200,
      (i) => {"audio": "musica  $i", "idUnico": "$i"},
    );
  }

  tocar(String musica) {
    print("tocando $musica ");
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Stack(
          children: <Widget>[
            yourStreamBuilder(),
            Column(
              children: <Widget>[
                Expanded(child: Container()),
                Container(
                  width: MediaQuery.of(context).size.width,
                  height: 44,
                  color: Colors.red,
                  child: Text("Your bottom container"),
                )
              ],
            ),
          ],
        ));
  }

  Widget yourStreamBuilder() {
    return FutureBuilder<List<Map<String, dynamic>>>(
      future: listaDeMusicas(),
      initialData: [],
      builder: (context, snapshot) {
        return ListView.builder(
          itemCount: snapshot.data.length,
          itemBuilder: (context, index) {
            var item = snapshot.data[index];
            if (tocando[item["idUnico"]] == null)
              tocando[item["idUnico"]] = false;
            return Row(
              children: <Widget>[
                IconButton(
                  icon: Icon(
                      tocando[item["idUnico"]] ? Icons.stop : Icons.play_arrow),
                  onPressed: () {
                    setState(() {
                      if (ultimoTocando != null) {
                        tocando[ultimoTocando] = false;
                      }
                      if (ultimoTocando != item["idUnico"]) {
                        tocando[item["idUnico"]] = !tocando[item["idUnico"]];
                      }
                      if (tocando[item["idUnico"]]) {
                        tocar(item["audio"]);
                      }
                    });

                    ultimoTocando = item["idUnico"];
                  },
                ),
                Text(item["audio"]),
              ],
            );
          },
        );
      },
    );
  }
}