`import 'dart:async';
import 'package:intl/intl.dart';
import 'package:flutter/material.dart';
import 'package:sticky_infinite_list/sticky_infinite_list.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(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
routes: {
SingleChildScrollPage.ROUTE: (_) => SingleChildScrollPage(),
},
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
final StreamController _streamController = StreamController.broadcast();
final ScrollController _scrollController = ScrollController();
Settings _settings = Settings();
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [SliverAppBar(
expandedHeight: 230.0,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
title: Text('复仇者联盟'),
background: Image.network(
'http://img.haote.com/upload/20180918/2018091815372344164.jpg',
fit: BoxFit.fitHeight,
),
),
)];
},
body:
ScrollWidget(
settings: _settings,
scrollController: _scrollController,
stream: _streamController.stream,
),
)
,
);
@override
void dispose() {
super.dispose();
_streamController.close();
}
}
class ScrollWidget extends StatelessWidget {
final Stream stream;
final ScrollController scrollController;
final Settings settings;
const ScrollWidget({
Key key,
this.stream,
this.scrollController,
this.settings,
}) : super(key: key);
@override
Widget build(BuildContext context) => InfiniteList(
/// when direction changes dynamically, Flutter
/// won't rerender scroll completely,
/// which means that gesture detector on scroll itself
/// remains from original direction
key: Key(settings.scrollDirection.toString()),
scrollDirection: settings.scrollDirection,
anchor: settings.anchor,
controller: scrollController,
direction: settings.multiDirection ? InfiniteListDirection.multi : InfiniteListDirection.single,
negChildCount: settings.negCount,
posChildCount: settings.posCount,
physics: settings.physics,
builder: (context, index) {
final date = DateTime.now().add(
Duration(
days: index,
)
);
if (settings.overlay) {
return InfiniteListItem.overlay(
mainAxisAlignment: settings.mainAxisAlignment,
crossAxisAlignment: settings.crossAxisAlignment,
headerStateBuilder: (context, state) => Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.orange.withOpacity(1 - state.position),
),
height: 70,
width: 70,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
date.day.toString(),
style: TextStyle(
fontSize: 21,
color: Colors.black87,
fontWeight: FontWeight.w600,
),
),
Text(
DateFormat.MMM().format(date),
style: TextStyle(
height: .7,
fontSize: 17,
color: Colors.black87,
fontWeight: FontWeight.w400,
),
)
],
),
),
),
contentBuilder: (context) => Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.blueAccent,
),
height: settings.contentHeight,
width: settings.contentWidth,
child: Center(
child: Text(
DateFormat.yMMMMd().format(date),
style: TextStyle(
fontSize: 18,
color: Colors.white
),
),
),
),
),
);
}
return InfiniteListItem(
mainAxisAlignment: settings.mainAxisAlignment,
crossAxisAlignment: settings.crossAxisAlignment,
positionAxis: settings.positionAxis,
headerStateBuilder: (context, state) => Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.orange.withOpacity(1 - state.position),
),
height: 70,
width: 70,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
date.day.toString(),
style: TextStyle(
fontSize: 21,
color: Colors.black87,
fontWeight: FontWeight.w600,
),
),
Text(
DateFormat.MMM().format(date),
style: TextStyle(
height: .7,
fontSize: 17,
color: Colors.black87,
fontWeight: FontWeight.w400,
),
)
],
),
),
),
contentBuilder: (context) => Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.blueAccent,
),
height: settings.contentHeight,
width: settings.contentWidth,
child: Center(
child: Text(
DateFormat.yMMMMd().format(date),
style: TextStyle(
fontSize: 18,
color: Colors.white
),
),
),
),
),
);
},
);
}
enum ScrollPhysicsEnum {
PLATFORM,
IOS,
ANDROID,
}
class Settings {
int negCount;
int posCount;
bool multiDirection;
HeaderMainAxisAlignment mainAxisAlignment;
HeaderCrossAxisAlignment crossAxisAlignment;
HeaderPositionAxis positionAxis;
double anchor;
Axis scrollDirection;
ScrollPhysicsEnum physicsType;
bool overlay;
bool get scrollVertical => scrollDirection == Axis.vertical;
ScrollPhysics get physics {
switch (physicsType) {
case ScrollPhysicsEnum.PLATFORM:
return null;
case ScrollPhysicsEnum.ANDROID:
return ClampingScrollPhysics();
case ScrollPhysicsEnum.IOS:
return BouncingScrollPhysics();
}
return null;
}
double get contentHeight {
if (scrollVertical) {
return 300;
}
return double.infinity;
}
double get contentWidth {
if (scrollVertical) {
return double.infinity;
}
return 300;
}
Settings({
this.negCount,
this.posCount,
this.mainAxisAlignment = HeaderMainAxisAlignment.start,
this.crossAxisAlignment = HeaderCrossAxisAlignment.start,
this.positionAxis = HeaderPositionAxis.mainAxis,
this.multiDirection = false,
this.anchor = 0,
this.scrollDirection = Axis.vertical,
this.physicsType = ScrollPhysicsEnum.PLATFORM,
this.overlay = false,
});
}
class SingleChildScrollPage extends StatefulWidget {
static const String ROUTE = "/single-child";
@override
_SingleChildScrollPageState createState() => _SingleChildScrollPageState();
}
class _SingleChildScrollPageState extends State {
static const double _headerHeight = 50;
final StreamController<StickyState> _headerStream = StreamController<StickyState>.broadcast();
final StreamController<StickyState> _headerOverlayStream = StreamController<StickyState>.broadcast();
@override
Widget build(BuildContext context) {
final height = MediaQuery.of(context).size.height;
return Scaffold(
appBar: AppBar(
title: const Text('Single element example'),
),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
height: height,
color: Colors.lightBlueAccent,
child: Placeholder(),
),
StickyListItem<String>(
streamSink: _headerStream.sink,
header: Container(
height: _headerHeight,
width: double.infinity,
color: Colors.orange,
child: Center(
child: StreamBuilder<StickyState<String>>(
stream: _headerStream.stream,
builder: (_, snapshot) {
if (!snapshot.hasData) {
return Container();
}
final position = (snapshot.data.position * 100).round();
return Text('Positioned relative. Position: $position%');
},
),
),
),
content: Container(
height: height,
color: Colors.blueAccent,
child: Placeholder(),
),
itemIndex: "single-child",
),
StickyListItem<String>.overlay(
streamSink: _headerOverlayStream.sink,
header: Container(
height: _headerHeight,
width: double.infinity,
color: Colors.orange,
child: Center(
child: StreamBuilder<StickyState<String>>(
stream: _headerOverlayStream.stream,
builder: (_, snapshot) {
if (!snapshot.hasData) {
return Container();
}
final position = (snapshot.data.position * 100).round();
return Text('Positioned overlay. Position: $position%');
},
),
),
),
content: Container(
height: height,
color: Colors.lightBlueAccent,
child: Placeholder(),
),
itemIndex: "single-overlayed-child",
),
Container(
height: height,
color: Colors.cyan,
child: Placeholder(),
),
],
),
),
);
}
@override
void dispose() {
super.dispose();
_headerStream.close();
_headerOverlayStream.close();
}
}`
maybe scroll has poblem