11import 'dart:async' ;
2+ import 'dart:math' as math;
23
34import 'package:flutter/material.dart' ;
5+ import 'package:flutter/rendering.dart' ;
46import 'package:gsy_github_app_flutter/common/dao/repos_dao.dart' ;
57import 'package:gsy_github_app_flutter/common/model/RepoCommit.dart' ;
68import 'package:gsy_github_app_flutter/common/model/Repository.dart' ;
9+ import 'package:gsy_github_app_flutter/common/utils/common_utils.dart' ;
710import 'package:gsy_github_app_flutter/common/utils/event_utils.dart' ;
811import 'package:gsy_github_app_flutter/common/utils/navigator_utils.dart' ;
912import 'package:gsy_github_app_flutter/page/repository_detail_page.dart' ;
1013import 'package:gsy_github_app_flutter/widget/event_item.dart' ;
1114import 'package:gsy_github_app_flutter/widget/gsy_common_option_widget.dart' ;
1215import 'package:gsy_github_app_flutter/widget/gsy_list_state.dart' ;
1316import 'package:gsy_github_app_flutter/widget/gsy_pull_load_widget.dart' ;
17+ import 'package:gsy_github_app_flutter/widget/gsy_select_item_widget.dart' ;
18+ import 'package:gsy_github_app_flutter/widget/nested/gsy_nested_pull_load_widget.dart' ;
19+ import 'package:gsy_github_app_flutter/widget/nested/nested_refresh.dart' ;
1420import 'package:gsy_github_app_flutter/widget/repos_header_item.dart' ;
1521import 'package:scoped_model/scoped_model.dart' ;
1622
@@ -37,41 +43,41 @@ class ReposDetailInfoPage extends StatefulWidget {
3743class ReposDetailInfoPageState extends State <ReposDetailInfoPage >
3844 with
3945 AutomaticKeepAliveClientMixin <ReposDetailInfoPage >,
40- GSYListState <ReposDetailInfoPage > {
46+ GSYListState <ReposDetailInfoPage >,
47+ TickerProviderStateMixin {
4148 int selectIndex = 0 ;
4249
4350 ReposDetailInfoPageState ();
4451
52+ final GlobalKey <NestedScrollViewRefreshIndicatorState > refreshIKey =
53+ new GlobalKey <NestedScrollViewRefreshIndicatorState >();
54+
55+ @override
56+ showRefreshLoading () {
57+ new Future .delayed (const Duration (seconds: 0 ), () {
58+ refreshIKey.currentState.show ().then ((e) {});
59+ return true ;
60+ });
61+ }
62+
4563 ///渲染时间Item或者提交Item
4664 _renderEventItem (index) {
47- if (index == 0 ) {
48- return new ReposHeaderItem (
49- ReposHeaderViewModel .fromHttpMap (widget.userName, widget.reposName,
50- ReposDetailModel .of (context).repository), (index) {
51- selectIndex = index;
52- clearData ();
53- showRefreshLoading ();
54- });
55- }
56-
5765 if (selectIndex == 1 ) {
5866 ///提交
5967 return new EventItem (
60- EventViewModel .fromCommitMap (pullLoadWidgetControl.dataList[index - 1 ]),
68+ EventViewModel .fromCommitMap (pullLoadWidgetControl.dataList[index]),
6169 onPressed: () {
62- RepoCommit model = pullLoadWidgetControl.dataList[index - 1 ];
70+ RepoCommit model = pullLoadWidgetControl.dataList[index];
6371 NavigatorUtils .goPushDetailPage (
6472 context, widget.userName, widget.reposName, model.sha, false );
6573 },
6674 needImage: false ,
6775 );
6876 }
6977 return new EventItem (
70- EventViewModel .fromEventMap (pullLoadWidgetControl.dataList[index - 1 ]),
78+ EventViewModel .fromEventMap (pullLoadWidgetControl.dataList[index]),
7179 onPressed: () {
72- EventUtils .ActionUtils (
73- context,
74- pullLoadWidgetControl.dataList[index - 1 ],
80+ EventUtils .ActionUtils (context, pullLoadWidgetControl.dataList[index],
7581 widget.userName + "/" + widget.reposName);
7682 },
7783 );
@@ -138,21 +144,142 @@ class ReposDetailInfoPageState extends State<ReposDetailInfoPage>
138144 bool get isRefreshFirst => true ;
139145
140146 @override
141- bool get needHeader => true ;
147+ bool get needHeader => false ;
148+
149+ AnimationController animationController;
150+
151+ @override
152+ void initState () {
153+ super .initState ();
154+ animationController = new AnimationController (vsync: this );
155+ }
142156
143157 @override
144158 Widget build (BuildContext context) {
145159 super .build (context);
146160 return ScopedModelDescendant <ReposDetailModel >(
147161 builder: (context, child, model) {
148- return GSYPullLoadWidget (
162+ return GSYNestedPullLoadWidget (
149163 pullLoadWidgetControl,
150164 (BuildContext context, int index) => _renderEventItem (index),
151165 handleRefresh,
152166 onLoadMore,
153- refreshKey: refreshIndicatorKey,
167+ refreshKey: refreshIKey,
168+ headerSliverBuilder: (context, _) {
169+ return _sliverBuilder (context, _);
170+ },
154171 );
155172 },
156173 );
157174 }
175+
176+ List <Widget > _sliverBuilder (BuildContext context, bool innerBoxIsScrolled) {
177+ return < Widget > [
178+ SliverPersistentHeader (
179+ delegate: _InfoHeaderDelegate (
180+ maxHeight: 300 ,
181+ minHeight: 300 ,
182+ snapConfig: FloatingHeaderSnapConfiguration (
183+ vsync: this ,
184+ curve: Curves .bounceInOut,
185+ duration: const Duration (milliseconds: 10 ),
186+ ),
187+ child: new ReposHeaderItem (
188+ ReposHeaderViewModel .fromHttpMap (
189+ widget.userName,
190+ widget.reposName,
191+ ReposDetailModel .of (context).repository), (index) {
192+ selectIndex = index;
193+ clearData ();
194+ showRefreshLoading ();
195+ })),
196+ ),
197+ SliverPersistentHeader (
198+ pinned: true ,
199+ delegate: _InfoHeaderDelegate (
200+ maxHeight: 70 ,
201+ minHeight: 70 ,
202+ changeSize: true ,
203+ snapConfig: FloatingHeaderSnapConfiguration (
204+ vsync: this ,
205+ curve: Curves .bounceInOut,
206+ duration: const Duration (milliseconds: 10 ),
207+ ),
208+ builder: (BuildContext context, double shrinkOffset,
209+ bool overlapsContent) {
210+ var lr = 10 - shrinkOffset / 70 * 10 ;
211+ var radius = Radius .circular (4 - shrinkOffset / 70 * 4 );
212+ return SizedBox .expand (
213+ child: Padding (
214+ padding: EdgeInsets .only (bottom: 20 , left: lr, right: lr),
215+ child: new GSYSelectItemWidget (
216+ [
217+ CommonUtils .getLocale (context).repos_tab_activity,
218+ CommonUtils .getLocale (context).repos_tab_commits,
219+ ],
220+ (index) {
221+ selectIndex = index;
222+ clearData ();
223+ showRefreshLoading ();
224+ },
225+ margin: EdgeInsets .zero,
226+ shape: new RoundedRectangleBorder (
227+ borderRadius: BorderRadius .all (radius),
228+ ),
229+ ),
230+ ),
231+ );
232+ }),
233+ ),
234+ ];
235+ }
158236}
237+
238+ ///动态头部处理
239+ class _InfoHeaderDelegate extends SliverPersistentHeaderDelegate {
240+ _InfoHeaderDelegate (
241+ {@required this .minHeight,
242+ @required this .maxHeight,
243+ @required this .snapConfig,
244+ this .child,
245+ this .builder,
246+ this .changeSize = false });
247+
248+ final double minHeight;
249+ final double maxHeight;
250+ final Widget child;
251+ final Builder builder;
252+ final bool changeSize;
253+ final FloatingHeaderSnapConfiguration snapConfig;
254+ AnimationController animationController;
255+
256+ @override
257+ double get minExtent => minHeight;
258+
259+ @override
260+ double get maxExtent => math.max (maxHeight, minHeight);
261+
262+ @override
263+ Widget build (
264+ BuildContext context, double shrinkOffset, bool overlapsContent) {
265+ if (builder != null ) {
266+ return builder (context, shrinkOffset, overlapsContent);
267+ }
268+ return SizedBox .expand (
269+ child: child,
270+ );
271+ }
272+
273+ @override
274+ bool shouldRebuild (_InfoHeaderDelegate oldDelegate) {
275+ return maxHeight != oldDelegate.maxHeight ||
276+ minHeight != oldDelegate.minHeight ||
277+ child != oldDelegate.child;
278+ }
279+
280+ @override
281+ FloatingHeaderSnapConfiguration get snapConfiguration => snapConfig;
282+ }
283+
284+ typedef Widget Builder (
285+ BuildContext context, double shrinkOffset, bool overlapsContent);
0 commit comments