Skip to content

Commit e2a2e40

Browse files
committed
✨ 优化主页顶Bar实现
1 parent 1b42c3e commit e2a2e40

File tree

2 files changed

+133
-71
lines changed

2 files changed

+133
-71
lines changed
Lines changed: 86 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1+
import 'dart:math';
2+
13
import 'package:flutter/cupertino.dart';
24
import 'package:flutter/material.dart';
35
import 'package:flutter_bloc/flutter_bloc.dart';
4-
import 'package:flutter_spinkit/flutter_spinkit.dart';
56
import 'package:flutter_unit/app/utils/convert.dart';
6-
import 'package:flutter_unit/app/res/cons.dart';
7+
78
import 'package:flutter_unit/app/router.dart';
89
import 'package:flutter_unit/blocs/bloc_exp.dart';
910
import 'package:flutter_unit/components/permanent/feedback_widget.dart';
10-
import 'package:flutter_unit/components/permanent/loading/planet_loading.dart';
1111
import 'package:flutter_unit/components/permanent/overlay_tool_wrapper.dart';
12+
1213
import 'package:flutter_unit/model/widget_model.dart';
1314
import 'package:flutter_unit/views/common/empty_page.dart';
14-
import 'package:flutter_unit/views/common/loading_page.dart';
1515
import 'package:flutter_unit/views/items/home_item_support.dart';
1616
import 'package:flutter_unit/views/pages/home/toly_app_bar.dart';
1717

@@ -22,16 +22,11 @@ class HomePage extends StatefulWidget {
2222
_HomePageState createState() => _HomePageState();
2323
}
2424

25-
class _HomePageState extends State<HomePage>
26-
with AutomaticKeepAliveClientMixin {
27-
ScrollController _ctrl;
28-
double _limitY = 35;
29-
double _height = kToolbarHeight * 2 - 20;
25+
class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin {
3026

3127
@override
3228
void initState() {
3329
super.initState();
34-
_ctrl = ScrollController()..addListener(_updateAppBarHeight);
3530

3631
WidgetsBinding.instance.addPostFrameCallback((callback) {
3732
OverlayToolWrapper.of(context).showFloating();
@@ -43,19 +38,38 @@ class _HomePageState extends State<HomePage>
4338
super.build(context);
4439

4540
return Scaffold(
46-
appBar: TolyAppBar(
47-
preferredSize: Size.fromHeight(_height),
48-
onItemClick: _switchTab,
49-
),
50-
body: Stack(
41+
body: BlocBuilder<HomeBloc, HomeState>(builder: (ctx, state) {
42+
return Stack(
5143
children: <Widget>[
5244
BlocBuilder<GlobalBloc, GlobalState>(builder: _buildBackground),
53-
BlocBuilder<HomeBloc, HomeState>(builder: _buildContent)
45+
CustomScrollView(
46+
slivers: <Widget>[
47+
_buildPersistentHeader(),
48+
_buildContent(ctx, state),
49+
],
50+
),
5451
],
55-
),
56-
);
52+
);
53+
}));
5754
}
5855

56+
Widget _buildPersistentHeader() => SliverPersistentHeader(
57+
pinned: true,
58+
delegate: FlexHeaderDelegate(
59+
minHeight: 25 + 56.0,
60+
maxHeight: 120.0,
61+
childBuilder: (offset, max, min) {
62+
double dy = max - 25 - offset;
63+
64+
if (dy < min - 25) {
65+
dy = min - 25;
66+
}
67+
return TolyAppBar(
68+
maxHeight: dy,
69+
onItemClick: _switchTab,
70+
);
71+
}));
72+
5973
Widget _buildBackground(BuildContext context, GlobalState state) {
6074
if (state.showBackGround) {
6175
return BackgroundShower();
@@ -64,24 +78,33 @@ class _HomePageState extends State<HomePage>
6478
}
6579

6680
Widget _buildContent(BuildContext context, HomeState state) {
67-
68-
if(state is WidgetsLoading){
69-
return Center(
70-
child: PlateLoading(),
81+
if (state is WidgetsLoading) {
82+
// return SliverToBoxAdapter(
83+
// child: Center(
84+
// child: PlateLoading(),
85+
// ),
86+
// );
87+
//
88+
return SliverToBoxAdapter(
89+
child: Container(),
7190
);
7291
}
7392

7493
if (state is WidgetsLoaded) {
7594
List<WidgetModel> items = state.widgets;
7695
if (items.isEmpty) return EmptyPage();
77-
return ListView.builder(
78-
controller: _ctrl,
79-
itemBuilder: (_, index) => _buildHomeItem(items[index]),
80-
itemCount: items.length);
96+
return SliverList(
97+
delegate: SliverChildBuilderDelegate(
98+
(_, int index) => _buildHomeItem(items[index]),
99+
childCount: items.length),
100+
);
81101
}
102+
82103
if (state is WidgetsLoadFailed) {
83-
return Container(
84-
child: Text('加载数据异常'),
104+
return SliverToBoxAdapter(
105+
child: Container(
106+
child: Text('加载数据异常'),
107+
),
85108
);
86109
}
87110
return Container();
@@ -98,24 +121,48 @@ class _HomePageState extends State<HomePage>
98121
},
99122
);
100123

101-
_updateAppBarHeight() {
102-
if (_ctrl.offset < _limitY * 4) {
103-
setState(() {
104-
_height = kToolbarHeight * 2 - 20 - _ctrl.offset / 4;
105-
});
106-
}
107-
}
108-
109124
_switchTab(int index, Color color) {
110-
if (_ctrl.hasClients) _ctrl.jumpTo(0);
111-
BlocProvider.of<HomeBloc>(context).add(EventTabTap(Convert.toFamily(index)));
125+
126+
BlocProvider.of<HomeBloc>(context)
127+
.add(EventTabTap(Convert.toFamily(index)));
112128
}
113129

114-
_toDetailPage(WidgetModel model){
130+
_toDetailPage(WidgetModel model) {
115131
BlocProvider.of<DetailBloc>(context).add(FetchWidgetDetail(model));
116132
Navigator.pushNamed(context, UnitRouter.widget_detail, arguments: model);
117133
}
118134

119135
@override
120136
bool get wantKeepAlive => true;
121137
}
138+
139+
class FlexHeaderDelegate extends SliverPersistentHeaderDelegate {
140+
FlexHeaderDelegate({
141+
@required this.minHeight,
142+
@required this.maxHeight,
143+
@required this.childBuilder,
144+
});
145+
146+
final double minHeight; //最小高度
147+
final double maxHeight; //最大高度
148+
final Widget Function(double offset, double max, double min)
149+
childBuilder; //最大高度
150+
151+
@override
152+
double get minExtent => minHeight;
153+
154+
@override
155+
double get maxExtent => max(maxHeight, minHeight);
156+
157+
@override
158+
Widget build(
159+
BuildContext context, double shrinkOffset, bool overlapsContent) {
160+
return childBuilder(shrinkOffset, maxHeight, minHeight);
161+
}
162+
163+
@override //是否需要重建
164+
bool shouldRebuild(FlexHeaderDelegate oldDelegate) {
165+
return maxHeight != oldDelegate.maxHeight ||
166+
minHeight != oldDelegate.minHeight;
167+
}
168+
}

lib/views/pages/home/toly_app_bar.dart

Lines changed: 47 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,16 @@ import 'package:flutter/material.dart';
22
import 'package:flutter_unit/app/res/cons.dart';
33
import 'package:flutter_unit/components/permanent/circle.dart';
44

5-
class TolyAppBar extends StatefulWidget implements PreferredSizeWidget {
5+
class TolyAppBar extends StatefulWidget {
6+
final double maxHeight;
67
final Function(int, Color) onItemClick;
78

89
@override
910
_TolyAppBarState createState() => _TolyAppBarState();
1011

11-
final Size preferredSize;
12-
1312
final int defaultIndex;
1413

15-
TolyAppBar({this.onItemClick, this.preferredSize, this.defaultIndex = 0});
14+
TolyAppBar({this.maxHeight, this.onItemClick, this.defaultIndex = 0});
1615
}
1716

1817
const _kBorderRadius = BorderRadius.only(
@@ -29,8 +28,26 @@ class _TolyAppBarState extends State<TolyAppBar>
2928
double _width = 0;
3029
int _selectIndex = 0;
3130

32-
List<int> colors = Cons.tabColors;
33-
List info = Cons.tabs;
31+
static const List<int> colors = [
32+
0xff44D1FD,
33+
0xffFD4F43,
34+
0xffB375FF,
35+
0xFF4CAF50,
36+
0xFFFF9800,
37+
0xFF00F1F1,
38+
0xFFDBD83F
39+
];
40+
41+
static const List<String> info = [
42+
'Stles',
43+
'Stful',
44+
'Scrow',
45+
'Mcrow',
46+
'Sliver',
47+
'Proxy',
48+
'Other'
49+
];
50+
3451

3552
AnimationController _controller;
3653

@@ -64,38 +81,38 @@ class _TolyAppBarState extends State<TolyAppBar>
6481
return Container(
6582
alignment: Alignment.center,
6683
child: Flow(
67-
delegate: TolyAppBarDelegate(_selectIndex,
68-
clicked ? _controller.value : 1, widget.preferredSize.height),
84+
delegate: TolyAppBarDelegate(
85+
_selectIndex, clicked ? _controller.value : 1, widget.maxHeight),
6986
children: [
7087
...colors
7188
.map((e) => GestureDetector(
72-
onTap: () => _onTap(e), child: _buildChild(e)))
89+
onTap: () => _onTap(e), child: _buildChild(e)))
7390
.toList(),
7491
...colors.map((e) => Circle(
75-
color: Color(e),
76-
radius: 6,
77-
))
92+
color: Color(e),
93+
radius: 6,
94+
))
7895
]),
7996
);
8097
}
8198

8299
Widget _buildChild(int color) => Container(
83-
alignment: const Alignment(0, 0.4),
84-
decoration: BoxDecoration(boxShadow: [
85-
BoxShadow(
86-
color: _selectIndex == colors.indexOf(color)
87-
? Colors.transparent
88-
: Color(colors[_selectIndex]),
89-
offset: Offset(1, 1),
90-
blurRadius: 2)
91-
], color: Color(color), borderRadius: _kBorderRadius),
92-
height: widget.preferredSize.height + 20,
93-
width: _width,
94-
child: Text(
95-
info[colors.indexOf(color)],
96-
style: _kTabTextStyle,
97-
),
98-
);
100+
alignment: const Alignment(0, 0.4),
101+
decoration: BoxDecoration(boxShadow: [
102+
BoxShadow(
103+
color: _selectIndex == colors.indexOf(color)
104+
? Colors.transparent
105+
: Color(colors[_selectIndex]),
106+
offset: Offset(1, 1),
107+
blurRadius: 2)
108+
], color: Color(color), borderRadius: _kBorderRadius),
109+
height: widget.maxHeight + 20,
110+
width: _width,
111+
child: Text(
112+
info[colors.indexOf(color)],
113+
style: _kTabTextStyle,
114+
),
115+
);
99116

100117
_onTap(int color) {
101118
if (_selectIndex == colors.indexOf(color)) return;
@@ -125,7 +142,6 @@ class TolyAppBarDelegate extends FlowDelegate {
125142

126143
@override
127144
void paintChildren(FlowPaintingContext context) {
128-
129145
double ox = 0;
130146
double obx = 0;
131147

@@ -141,9 +157,8 @@ class TolyAppBarDelegate extends FlowDelegate {
141157
ox += cSize.width;
142158
}
143159
}
144-
for (int i = (context.childCount / 2).floor();
145-
i < context.childCount;
146-
i++) {
160+
161+
for (int i = (context.childCount / 2).floor(); i < context.childCount; i++) {
147162
if (i - (context.childCount / 2).floor() == selectIndex) {
148163
obx += context.getChildSize(0).width;
149164
} else {

0 commit comments

Comments
 (0)