Skip to content

Commit 7ca4f7c

Browse files
committed
feat(wordcard): enhance wordcard overview page
实现了通过课程分类看卡片 Signed-off-by: OctagonalStar <[email protected]>
1 parent d342cbe commit 7ca4f7c

File tree

2 files changed

+146
-74
lines changed

2 files changed

+146
-74
lines changed

lib/funcs/ui.dart

Lines changed: 64 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -412,79 +412,78 @@ class WordCard extends StatelessWidget {
412412
Widget build(BuildContext context) {
413413
MediaQueryData mediaQuery = MediaQuery.of(context);
414414
bool hide = useMask;
415-
return Container(
416-
margin: const EdgeInsets.all(16.0),
417-
//padding: const EdgeInsets.all(16.0),
418-
width: width ?? (mediaQuery.size.width * 0.9),
419-
height: height ?? (mediaQuery.size.height * 0.5),
420-
decoration: BoxDecoration(
421-
color: Theme.of(context).colorScheme.onInverseSurface.withAlpha(150),
422-
borderRadius: StaticsVar.br,
423-
),
424-
child: Column(
425-
mainAxisAlignment: MainAxisAlignment.start,
426-
children: [
427-
ElevatedButton.icon(
428-
style: ElevatedButton.styleFrom(
429-
fixedSize: Size(width ?? (mediaQuery.size.width * 0.9), height == null ? (mediaQuery.size.height * 0.2) : height! * 0.4),
430-
backgroundColor: Theme.of(context).colorScheme.onPrimary.withAlpha(150),
431-
shape: RoundedRectangleBorder(borderRadius: StaticsVar.br),
432-
padding: const EdgeInsets.all(16.0),
433-
),
434-
icon: const Icon(Icons.volume_up, size: 24.0),
435-
label: FittedBox(child: Text(word["arabic"], style: TextStyle(fontSize: 64.0, fontFamily: context.read<Global>().arFont))),
436-
onPressed: (){
437-
playTextToSpeech(word["arabic"], context);
438-
},
415+
double useWidth = width ?? mediaQuery.size.width * 0.9;
416+
double useHeight = height ?? mediaQuery.size.height * 0.5;
417+
return Column(
418+
mainAxisAlignment: MainAxisAlignment.start,
419+
children: [
420+
ElevatedButton.icon(
421+
style: ElevatedButton.styleFrom(
422+
fixedSize: Size(useWidth, useHeight * 0.3),
423+
backgroundColor: Theme.of(context).colorScheme.onPrimary.withAlpha(150),
424+
shape: RoundedRectangleBorder(borderRadius: BorderRadiusGeometry.vertical(top: Radius.circular(25.0))),
425+
padding: const EdgeInsets.all(16.0),
439426
),
440-
Stack(
441-
children: [
442-
Center(
427+
icon: const Icon(Icons.volume_up, size: 24.0),
428+
label: FittedBox(child: Text(word["arabic"], style: TextStyle(fontSize: 64.0, fontFamily: context.read<Global>().arFont))),
429+
onPressed: (){
430+
playTextToSpeech(word["arabic"], context);
431+
},
432+
),
433+
Stack(
434+
children: [
435+
Container(
436+
width: useWidth,
437+
height: useHeight * 0.6,
438+
decoration: BoxDecoration(
439+
color: Theme.of(context).colorScheme.onInverseSurface.withAlpha(150),
440+
borderRadius: BorderRadius.vertical(bottom: Radius.circular(25.0)),
441+
),
442+
child: Center(
443443
child: Text(' 中文:${word["chinese"]}\n 示例:${word["explanation"]}\n 归属课程:${word["subClass"]}',
444444
style: Theme.of(context).textTheme.bodyLarge,
445445
textAlign: TextAlign.left,
446446
),
447447
),
448-
StatefulBuilder(
449-
builder: (context, setLocalState) {
450-
return TweenAnimationBuilder<double>(
451-
tween: Tween(
452-
begin: 1.0,
453-
end: hide ? 1.0 : 0.0
454-
),
455-
duration: Duration(milliseconds: 500),
456-
curve: StaticsVar.curve,
457-
builder: (context, value, child) {
458-
return ClipRRect(
459-
borderRadius: BorderRadiusGeometry.vertical(bottom: Radius.circular(25.0)),
460-
child: BackdropFilter(
461-
filter: ImageFilter.blur(sigmaX: 10.0 * value,sigmaY: 10.0 * value),
462-
enabled: true,
463-
child: value == 0.0 ? null : ElevatedButton(
464-
style: ElevatedButton.styleFrom(
465-
fixedSize: Size(width ?? (mediaQuery.size.width * 0.9), height == null ? (mediaQuery.size.height * 0.3) : height! * 0.6),
466-
backgroundColor: Colors.transparent,
467-
shadowColor: Colors.transparent,
468-
shape: RoundedRectangleBorder(borderRadius: BorderRadiusGeometry.vertical(bottom: Radius.circular(25.0)))
469-
),
470-
onPressed: (){
471-
setLocalState(() {
472-
hide = false;
473-
},);
474-
},
475-
child: hide ? Text("点此查看释义") : SizedBox()
448+
),
449+
StatefulBuilder(
450+
builder: (context, setLocalState) {
451+
return TweenAnimationBuilder<double>(
452+
tween: Tween(
453+
begin: 1.0,
454+
end: hide ? 1.0 : 0.0
455+
),
456+
duration: Duration(milliseconds: 500),
457+
curve: StaticsVar.curve,
458+
builder: (context, value, child) {
459+
return ClipRRect(
460+
borderRadius: BorderRadiusGeometry.vertical(bottom: Radius.circular(25.0)),
461+
child: BackdropFilter(
462+
filter: ImageFilter.blur(sigmaX: 10.0 * value,sigmaY: 10.0 * value),
463+
enabled: true,
464+
child: value == 0.0 ? null : ElevatedButton(
465+
style: ElevatedButton.styleFrom(
466+
fixedSize: Size(useWidth, useHeight * 0.6),
467+
backgroundColor: Colors.transparent,
468+
shadowColor: Colors.transparent,
469+
shape: RoundedRectangleBorder(borderRadius: BorderRadiusGeometry.vertical(bottom: Radius.circular(25.0)))
476470
),
471+
onPressed: (){
472+
setLocalState(() {
473+
hide = false;
474+
},);
475+
},
476+
child: hide ? Text("点此查看释义") : SizedBox()
477477
),
478-
);
479-
},
480-
);
481-
}
482-
)
483-
],
484-
)
485-
486-
],
487-
)
478+
),
479+
);
480+
},
481+
);
482+
}
483+
)
484+
],
485+
)
486+
],
488487
);
489488
}
490489
}

lib/sub_pages_builder/learning_pages/learning_pages_build.dart

Lines changed: 82 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'dart:convert';
12
import 'dart:math';
23

34
import 'package:arabic_learning/funcs/ui.dart';
@@ -569,6 +570,10 @@ class WordCardOverViewPage extends StatefulWidget {
569570
}
570571

571572
class _WordCardOverViewPage extends State<WordCardOverViewPage> {
573+
ScrollController jsonController = ScrollController();
574+
ScrollController classController = ScrollController();
575+
bool allowJsonScorll = true;
576+
bool allowClassScorll = false;
572577

573578
@override
574579
Widget build(BuildContext context) {
@@ -577,17 +582,85 @@ class _WordCardOverViewPage extends State<WordCardOverViewPage> {
577582
appBar: AppBar(
578583
title: Text("单词总览"),
579584
),
580-
body: GridView.builder(
581-
itemCount: context.read<Global>().wordData["Words"].length,
582-
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
583-
itemBuilder: (context, index) {
584-
return WordCard(
585-
word: context.read<Global>().wordData["Words"][index],
586-
useMask: false,
587-
height: mediaQuery.size.height * 0.4,
585+
body: ListView.builder(
586+
physics: allowJsonScorll ? null : NeverScrollableScrollPhysics(),
587+
controller: jsonController,
588+
itemCount: context.read<Global>().wordData["Classes"].length + 1,
589+
itemBuilder: (context, jsonIndex) {
590+
if(jsonIndex == context.read<Global>().wordData["Classes"].length) {
591+
return SizedBox(height: mediaQuery.size.height);
592+
}
593+
594+
final String jsonName = context.read<Global>().wordData["Classes"].keys.elementAt(jsonIndex);
595+
return ExpansionTile(
596+
title: Text(jsonName.trim()),
597+
minTileHeight: 64,
598+
onExpansionChanged: (value) {
599+
setState(() {
600+
allowClassScorll = value;
601+
allowJsonScorll = !value; // 展开json后锁定首个ListView,禁止滑动
602+
});
603+
jsonController.animateTo(
604+
(66 * jsonIndex).toDouble(),
605+
duration: Duration(milliseconds: 200),
606+
curve: StaticsVar.curve
607+
);
608+
},
609+
children: [
610+
SizedBox(
611+
height: mediaQuery.size.height * 0.9,
612+
child: ListView.builder(
613+
physics: allowClassScorll ? null : NeverScrollableScrollPhysics(),
614+
controller: classController,
615+
itemCount: context.read<Global>().wordData["Classes"][jsonName].length + 1,
616+
itemBuilder: (context, classIndex) {
617+
if(classIndex == context.read<Global>().wordData["Classes"][jsonName].length) {
618+
return SizedBox(height: mediaQuery.size.height); // 避免0.9空间估计不足
619+
}
620+
621+
final String className = context.read<Global>().wordData["Classes"][jsonName].keys.elementAt(classIndex);
622+
return ExpansionTile(
623+
title: Text(className.trim()),
624+
minTileHeight: 62,
625+
onExpansionChanged: (value) {
626+
setState(() {
627+
allowClassScorll = !value;
628+
});
629+
classController.animateTo(
630+
(64 * classIndex).toDouble(),
631+
duration: Duration(milliseconds: 200),
632+
curve: StaticsVar.curve
633+
);
634+
},
635+
children: [
636+
SizedBox(
637+
height: mediaQuery.size.height * 0.8,
638+
child: GridView.builder(
639+
itemCount: context.read<Global>().wordData["Classes"][jsonName][className].length,
640+
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: mediaQuery.size.width ~/ 300),
641+
itemBuilder: (context, index) {
642+
return Container(
643+
margin: EdgeInsets.all(8.0),
644+
child: WordCard(
645+
word: context.read<Global>().wordData["Words"][context.read<Global>().wordData["Classes"][jsonName][className][index]],
646+
useMask: false,
647+
width: mediaQuery.size.width / (mediaQuery.size.width ~/ 300),
648+
height: mediaQuery.size.width / (mediaQuery.size.width ~/ 300),
649+
),
650+
);
651+
}
652+
),
653+
),
654+
SizedBox(height: mediaQuery.size.height * 0.5)
655+
],
656+
);
657+
}
658+
),
659+
),
660+
],
588661
);
589662
}
590-
),
663+
)
591664
);
592665

593666
}

0 commit comments

Comments
 (0)