0

This is probably a really easy-to-fix question, but I figured that I might as well ask it here anyways: Is there any way to anchor a widget within a CustomScrollView? I want to use the CustomScrollView to support a flexible space in the app bar, but I need to have an input widget stay fixed at the bottom of the screen. I tried nesting the CustomScrollView into a Column with the given widget, but it doesn't seem to be working:

  @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
      ],
    );
  }

And here's that _buildMessages() method:

  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,
            ),
          );
        });
  }

Any suggestions? I've found some examples but that builds the whole CustomScrollView while I only want to build the SliverList whenever I get a new snapshot. Any suggestions?

Nicholas Chiang
  • 317
  • 2
  • 11

1 Answers1

0

Yes, but for that you don't put it in the custom scroll, you use a stack widget. It puts the layered widget on the screen. What comes below you put before. In order for your widget to be positioned at the bottom, you must use a column with an expanded.

  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"),
            )
          ],
        ),
      ],
    )

Complete exemple:

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"]),
              ],
            );
          },
        );
      },
    );
  }
}
Claudio Castro
  • 1,541
  • 12
  • 28