Flutter 吸顶Scroll View

效果如下:

  • 分为三部分,上部,中部,下部。
  • 上部为 header 部分,不吸顶。
  • 中部吸顶。
  • 下部为 SubPages 部分,可以左右滑动切换页面子页面。
home_scroll.view.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import 'package:flutter/material.dart';
import 'package:get/get.dart';

class HomeScrollView extends GetView {
final Widget top;
final Widget header;
final List<Widget> subPages;

const HomeScrollView(
{super.key,
required this.top,
required this.subPages,
required this.header});

@override
Widget build(BuildContext context) {
return Material(
child: DefaultTabController(
length: 5,
child: Column(
children: [
Expanded(
child: NestedScrollView(
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[top, header];
},
body: TabBarView(
physics: NeverScrollableScrollPhysics(),
children: subPages,
)))
],
)),
);
}
}
home.view.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import 'package:animated_toggle_switch/animated_toggle_switch.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:rflutter_alert/rflutter_alert.dart' as Alert;
import 'package:uTrading/config/log_config.dart';
import 'package:uTrading/config/super_theme.dart';
import 'package:uTrading/controller/countdown.controller.dart';
import 'package:uTrading/page/home/views/home_scroll.view.dart';
import 'package:uTrading/page/home/views/ranking_list.view.dart';
import 'package:uTrading/page/home/widgets/menu_icon_widget.dart';
import 'package:uTrading/page/home/widgets/ranking_header_widget.dart';
import 'package:uTrading/widget/u_text.dart';

import 'home.controller.dart';

class HomeView extends GetView {
const HomeView({super.key});

@override
Widget build(BuildContext context) {
Get.put(CountdownController());
HomeController controller = Get.put(HomeController());

var headerSwitch = Padding(
padding: EdgeInsets.fromLTRB(16.w, 9.h, 16.w, 9.h),
child: Center(
child: SizedBox(
height: 32.h,
width: 200.w,
child: Obx(
() => AnimatedToggleSwitch.size(
current: controller.appIsCEX.value,
values: const [true, false],
iconOpacity: 1,
indicatorSize: Size.fromWidth(99.w),
customIconBuilder: (context, local, global) => Text(
local.value ? 'CEX' : 'DEX',
style: TextStyle(
color: Color.lerp(Color(0xff999999), Color(0xff333333),
local.animationValue),
fontWeight: FontWeight.lerp(FontWeight.normal,
FontWeight.bold, local.animationValue)),
),
borderWidth: 5,
iconAnimationType: AnimationType.onHover,
style: ToggleStyle(
indicatorColor: Color(0xffffc300),
borderColor: Colors.transparent,
borderRadius: BorderRadius.circular(32.r),
),
selectedIconScale: 1,
onChanged: (value) => controller.toggleAppType(),
),
)),
),
);

var headerRightIcon = Positioned(
top: 0,
bottom: 0,
right: 16.w,
child: Center(
child: InkWell(
onTap: () {},
child: Image.asset('assets/images/announce_line_black.png',
width: 20.w, height: 20.w),
)),
);

return HomeScrollView(
top: SliverToBoxAdapter(
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: AssetImage('assets/images/home_top_bg.png'))),
child: Column(
children: [
// 刘海屏
SizedBox(height: MediaQuery.of(context).padding.top),

// 顶部区域
Stack(
children: [
headerSwitch,
headerRightIcon,
],
),

// menu icons
HomeMenuWidget()
],
),
),
), // 上部
header: RankingHeaderWidget(), // 中部
subPages: [ // 下部
RankingListWidget(),
RankingListWidget(),
RankingListWidget(),
RankingListWidget(),
RankingListWidget(),
]);
}
}

class HomeMenuWidget extends StatelessWidget {
const HomeMenuWidget({
super.key,
});

@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.fromLTRB(0, 16.h, 0, 16.h),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
MenuIconWidget(
imgPath: 'assets/images/my_profit.png',
title: 'aa',
onPressed: () {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Click profile')));
}),
MenuIconWidget(
imgPath: 'assets/images/risk_control.png',
title: 'bb',
onPressed: () {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Click profile')));
}),
MenuIconWidget(
imgPath: 'assets/images/api_binding.png',
title: 'cc',
onPressed: () {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Click profile')));
}),
MenuIconWidget(
imgPath: 'assets/images/exchange_register.png',
title: 'dd',
onPressed: () {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Click profile')));
}),
],
),
);
}
}