SliverAppBar is failing to show the content when AppBar is re-animated (after scrollbar has reached top).
Included a sample project below to demonstrate the issue. Copy/Paste code below (add rxdart dependency to pubspec.yaml) and run app. Notice the SliverAppBar contains some text that is coming from the stream (see function 1 & 2 below). Now scroll down the counter list far enough so that SliverAppBar disappears. Scroll backup to bring the AppBar back into view, notice there is now two ProgressIndicators but no text.
Require the text to appear once AppBar appears back into view, ideally without having to call the following functions again (these are actually api calls in the real app):
SliverAppBar content functions
bloc.fetchTestAppBarTxt1();
bloc.fetchTestAppBarTxt2();
Sample App
void main() => runApp(TestApp());
class TestApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
TestBloc bloc = TestBloc();
bloc.fetchTestTimeline();
bloc.fetchTestAppBarTxt1();
bloc.fetchTestAppBarTxt2();
return MaterialApp(
home: new Scaffold(
backgroundColor: Colors.grey[200],
appBar: AppBar(
backgroundColor: Colors.blueGrey,
elevation: 0.0,
),
body: CustomScrollView(slivers: <Widget>[
SliverAppBar(
automaticallyImplyLeading: false,
backgroundColor: Colors.grey[400],
expandedHeight: 200.0,
floating: true,
snap: true,
flexibleSpace: FlexibleSpaceBar(
background: Column(
children: <Widget>[
Container(
padding: EdgeInsets.only(left: 2.0),
height: 200,
child: Column(
children: <Widget>[
StreamBuilder(
stream: bloc.testAppBarTxt1,
initialData: null,
builder: (BuildContext context,
AsyncSnapshot<String> snapshot) {
if (snapshot.data == null)
return buildProgressIndicator(true);
return Expanded(
child: Text('${snapshot.data}'));
}),
StreamBuilder(
stream: bloc.testAppBarTxt2,
initialData: null,
builder: (BuildContext context,
AsyncSnapshot<String> snapshot) {
if (snapshot.data == null)
return buildProgressIndicator(true);
return Expanded(
child: Text('${snapshot.data}'));
}),
],
),
)
],
),
)),
timelineList(bloc)
])),
);
}
Widget timelineList(TestBloc bloc) {
return StreamBuilder(
stream: bloc.getTestTimeline,
initialData: null,
builder: (BuildContext context, AsyncSnapshot<List<int>> snapshot) {
List<int> val = snapshot.data;
if (val == null)
return SliverToBoxAdapter(child: buildProgressIndicator(true));
if (val.isNotEmpty) {
addToTimelineList(val, bloc);
return SliverList(
delegate: SliverChildListDelegate(new List<Widget>.generate(
bloc.listTest.length, (int index) {
if (index == bloc.listTest.length) {
return SliverToBoxAdapter(
child: buildProgressIndicator(bloc.isPerformingRequest));
} else {
return bloc.listTest[index];
}
})
));
}
});
}
void addToTimelineList(List<int> list, TestBloc bloc) {
for (var val in list) {
bloc.listTest.add(Text('$val'));
}
}
}
class TestBloc {
List<Text> listTest = new List<Text>();
bool isPerformingRequest = false;
final _testAppBarText1 = PublishSubject<String>();
Observable<String> get testAppBarTxt1 => _testAppBarText1.stream;
final _testAppBarText2 = PublishSubject<String>();
Observable<String> get testAppBarTxt2 => _testAppBarText2.stream;
final _testTimeline = PublishSubject<List<int>>();
Observable<List<int>> get getTestTimeline => _testTimeline.stream;
fetchTestTimeline() async {
List item = await Future.delayed(
Duration(seconds: 2), () => List<int>.generate(100, (i) => i));
_testTimeline.sink.add(item);
}
fetchTestAppBarTxt1() async {
String val = await Future.delayed(Duration(seconds: 2), () => "Text One");
_testAppBarText1.sink.add(val);
}
fetchTestAppBarTxt2() async {
String val = await Future.delayed(Duration(seconds: 2), () => "Text Two");
_testAppBarText2.sink.add(val);
}
dispose() {
_testAppBarText1.close();
_testAppBarText2.close();
_testTimeline.close();
}
}