Skip to content

Commit 91df5d3

Browse files
committed
feat: club detail page
1 parent 3a3d5aa commit 91df5d3

File tree

1 file changed

+151
-125
lines changed

1 file changed

+151
-125
lines changed

lib/page/club_suggestion/club_detail.dart

Lines changed: 151 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,16 @@ class _ClubDetailState extends State<ClubDetail> {
2222
late ScrollController _scrollController;
2323
late Future<String> _content;
2424

25-
static const _expandedHeight = 300.0;
25+
static const _expandedHeight = 280.0;
26+
static const _maxWidth = 600.0;
2627

27-
bool _isShrunk = false;
28+
double _opacity = 0.0;
2829

2930
void _scrollListener() {
30-
final shouldBeShrunk = _scrollController.hasClients &&
31-
_scrollController.offset > (_expandedHeight - kToolbarHeight);
32-
33-
if (shouldBeShrunk != _isShrunk) {
34-
setState(() {
35-
_isShrunk = shouldBeShrunk;
36-
});
37-
}
31+
_opacity = (_scrollController.offset / (_expandedHeight - kToolbarHeight));
32+
if (_opacity < 0.0) _opacity = 0.0;
33+
if (_opacity >= 1.0) _opacity = 1.0;
34+
setState(() {});
3835
}
3936

4037
@override
@@ -54,135 +51,164 @@ class _ClubDetailState extends State<ClubDetail> {
5451

5552
@override
5653
Widget build(BuildContext context) {
57-
return Scaffold(
58-
body: CustomScrollView(
59-
controller: _scrollController,
60-
slivers: [
61-
SliverAppBar(
62-
expandedHeight: _expandedHeight,
63-
centerTitle: false,
64-
pinned: true,
65-
title: Visibility(
66-
visible: _isShrunk,
67-
child: Text(widget.info.title),
68-
),
69-
elevation: 0,
70-
//leading: const BackButton(),
71-
flexibleSpace: FlexibleSpaceBar(
72-
background: Column(
73-
crossAxisAlignment: CrossAxisAlignment.center,
74-
mainAxisAlignment: MainAxisAlignment.center,
75-
children: [
76-
Image(
77-
image: widget.info.icon,
78-
height: 100,
79-
width: 100,
80-
).clipOval(),
81-
const SizedBox(
82-
height: 10,
83-
),
84-
Text(
85-
widget.info.title,
86-
),
87-
const SizedBox(
88-
height: 10,
89-
),
90-
Text(
91-
widget.info.intro,
92-
),
93-
const SizedBox(
94-
height: 10,
95-
),
96-
Text(
97-
widget.info.typeList
98-
.map<String>((type) => switch (type) {
99-
ClubType.tech => "技术",
100-
ClubType.acg => "晒你系",
101-
ClubType.union => "官方",
102-
ClubType.profit => "商业",
103-
ClubType.sport => "体育",
104-
ClubType.art => "文化",
105-
ClubType.unknown => "未知",
106-
})
107-
.join("; "),
108-
//style: TextStyle(fontSize: 14),
109-
),
110-
],
111-
).padding(top: kToolbarHeight),
112-
),
54+
return Theme(
55+
data: ThemeData(
56+
colorScheme: ColorScheme.fromSeed(
57+
seedColor: Colors.yellow,
58+
brightness: Theme.of(context).brightness,
11359
),
114-
SliverToBoxAdapter(
115-
child: ConstrainedBox(
116-
constraints: BoxConstraints(
117-
minHeight: MediaQuery.of(context).size.height,
118-
),
119-
child: Material(
120-
elevation: 7,
121-
child: [
122-
[
123-
TextButton(
124-
child: Text("QQ"),
125-
onPressed: () async {
60+
),
61+
child: Scaffold(
62+
body: CustomScrollView(
63+
controller: _scrollController,
64+
slivers: [
65+
SliverAppBar(
66+
expandedHeight: _expandedHeight,
67+
centerTitle: false,
68+
pinned: true,
69+
title: Opacity(
70+
opacity: _opacity,
71+
child: Text(widget.info.title),
72+
),
73+
elevation: 0,
74+
//leading: const BackButton(),
75+
flexibleSpace: FlexibleSpaceBar(
76+
background: Column(
77+
crossAxisAlignment: CrossAxisAlignment.center,
78+
mainAxisAlignment: MainAxisAlignment.center,
79+
children: [
80+
Image(
81+
image: widget.info.icon,
82+
height: 100,
83+
width: 100,
84+
fit: BoxFit.fill,
85+
).clipOval(),
86+
const SizedBox(height: 16),
87+
Text(
88+
widget.info.title,
89+
style: TextStyle(
90+
fontSize: 16,
91+
fontWeight: FontWeight.bold,
92+
),
93+
),
94+
const SizedBox(height: 8),
95+
Text(widget.info.intro),
96+
const SizedBox(height: 6),
97+
Row(
98+
mainAxisAlignment: MainAxisAlignment.center,
99+
children: widget.info.typeList
100+
.map<Widget>((type) => TagsBoxes(
101+
text: switch (type) {
102+
ClubType.tech => "技术",
103+
ClubType.acg => "晒你系",
104+
ClubType.union => "官方",
105+
ClubType.profit => "商业",
106+
ClubType.sport => "体育",
107+
ClubType.art => "文化",
108+
ClubType.unknown => "未知",
109+
}))
110+
.toList(),
111+
)
112+
],
113+
).padding(top: kToolbarHeight, bottom: 46),
114+
),
115+
bottom: PreferredSize(
116+
preferredSize: Size.fromHeight(46.0),
117+
child: [
118+
InkWell(
119+
onTap: () async {
126120
await Clipboard.setData(
127121
ClipboardData(text: widget.info.qq));
128122
if (context.mounted) {
129123
showToast(context: context, msg: "QQ 号已经复制到剪贴板");
130124
}
131125
},
132-
),
133-
TextButton(
134-
child: Text("邀请链接"),
135-
onPressed: () async {
126+
child: Ink(
127+
height: 46.0,
128+
child: Text(
129+
"QQ",
130+
style: TextStyle(
131+
fontSize: 16,
132+
fontWeight: FontWeight.w500,
133+
),
134+
).center(),
135+
),
136+
).expanded(),
137+
InkWell(
138+
onTap: () async {
136139
if (widget.info.qqlink.isEmpty) {
137140
showToast(context: context, msg: "未提供入群链接");
138141
}
139142
launchUrlString(widget.info.qqlink);
140143
},
141-
)
142-
].toRow(mainAxisAlignment: MainAxisAlignment.spaceAround),
143-
Divider(color: Colors.transparent),
144-
if (widget.info.pic > 0) ...[
145-
ListView.builder(
146-
scrollDirection: Axis.horizontal,
147-
shrinkWrap: true,
148-
physics: ClampingScrollPhysics(),
149-
itemCount: widget.info.pic,
150-
itemBuilder: (context, index) => CachedNetworkImage(
151-
imageUrl: getClubImage(widget.info.code, index),
152-
height: 300,
153-
).clipRRect(all: 12).padding(horizontal: 4),
154-
).clipRRect(all: 12).constrained(height: 300),
155-
Divider(color: Colors.transparent),
156-
],
157-
SelectionArea(
158-
child: FutureBuilder<String>(
159-
future: _content,
160-
builder: (context, snapshot) {
161-
if (snapshot.connectionState == ConnectionState.done) {
162-
try {
163-
return HtmlWidget(
164-
snapshot.data ?? '''<p>加载遇到问题</p>''',
165-
).padding(horizontal: 4);
166-
} catch (e) {
167-
return ReloadWidget(
168-
function: () {
169-
setState(() {
170-
_content = getClubArticle(widget.info.code);
171-
});
172-
},
144+
child: Ink(
145+
height: 46.0,
146+
child: Text(
147+
"邀请链接",
148+
style: TextStyle(
149+
fontSize: 16,
150+
fontWeight: FontWeight.w500,
151+
),
152+
).center(),
153+
),
154+
).expanded()
155+
]
156+
.toRow(mainAxisAlignment: MainAxisAlignment.spaceAround)
157+
.constrained(maxWidth: _maxWidth),
158+
),
159+
),
160+
SliverToBoxAdapter(
161+
child: ConstrainedBox(
162+
constraints: BoxConstraints(
163+
minHeight: MediaQuery.of(context).size.height,
164+
),
165+
child: [
166+
if (widget.info.pic > 0) ...[
167+
ListView.builder(
168+
scrollDirection: Axis.horizontal,
169+
shrinkWrap: true,
170+
physics: ClampingScrollPhysics(),
171+
itemCount: widget.info.pic,
172+
itemBuilder: (context, index) => CachedNetworkImage(
173+
imageUrl: getClubImage(widget.info.code, index),
174+
height: 300,
175+
).clipRRect(all: 12).padding(horizontal: 4),
176+
)
177+
.clipRRect(all: 12)
178+
.constrained(height: 300, maxWidth: 600),
179+
Divider(color: Colors.transparent),
180+
],
181+
SelectionArea(
182+
child: FutureBuilder<String>(
183+
future: _content,
184+
builder: (context, snapshot) {
185+
if (snapshot.connectionState == ConnectionState.done) {
186+
try {
187+
return HtmlWidget(
188+
snapshot.data ?? '''<p>加载遇到问题</p>''',
189+
).padding(horizontal: 4);
190+
} catch (e) {
191+
return ReloadWidget(
192+
function: () {
193+
setState(() {
194+
_content = getClubArticle(widget.info.code);
195+
});
196+
},
197+
);
198+
}
199+
} else {
200+
return const Center(
201+
child: CircularProgressIndicator(),
173202
);
174203
}
175-
} else {
176-
return const Center(child: CircularProgressIndicator());
177-
}
178-
},
179-
)),
180-
].toColumn(),
204+
},
205+
)).constrained(maxWidth: _maxWidth),
206+
Divider(color: Colors.transparent),
207+
].toColumn().padding(horizontal: 8),
208+
),
181209
),
182-
),
183-
)
184-
],
185-
),
186-
);
210+
],
211+
),
212+
));
187213
}
188214
}

0 commit comments

Comments
 (0)