-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
style: migrated to expandable page view for better layout
- Loading branch information
Showing
14 changed files
with
2,177 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import 'package:flutter/material.dart'; | ||
|
||
class iconWithName extends StatelessWidget { | ||
final IconData icon; | ||
final String name; | ||
final bool isVertical; | ||
final Color color; | ||
final double size; | ||
final Color backgroundColor; | ||
final BorderRadius? borderRadius; | ||
final Color TextColor; | ||
final double fontSize; | ||
final bool isGapped; | ||
const iconWithName({ | ||
super.key, | ||
required this.icon, | ||
required this.name, | ||
this.isVertical = true, | ||
this.color = Colors.black, | ||
this.size = 16.0, | ||
this.fontSize = 12.0, | ||
this.backgroundColor = Colors.white, | ||
this.borderRadius, | ||
this.TextColor = Colors.black, | ||
this.isGapped = true, | ||
}); | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return Container( | ||
padding: const EdgeInsets.symmetric(horizontal: 6), | ||
height: 20, | ||
decoration: BoxDecoration( | ||
color: backgroundColor, | ||
borderRadius: borderRadius, | ||
), | ||
child: isVertical | ||
? Column( | ||
mainAxisAlignment: MainAxisAlignment.center, | ||
crossAxisAlignment: CrossAxisAlignment.center, | ||
mainAxisSize: MainAxisSize.min, | ||
children: [ | ||
Icon(icon, size: size, color: color), | ||
const SizedBox(height: 8.0), | ||
Text(name, style: const TextStyle(fontSize: 14.0)), | ||
], | ||
) | ||
: Center( | ||
child: Row( | ||
children: [ | ||
Icon(icon, size: size, color: color), | ||
SizedBox(width: isGapped ? 2.0 : 0.0), | ||
Text(name, | ||
style: TextStyle( | ||
fontSize: fontSize, | ||
color: TextColor, | ||
fontWeight: FontWeight.bold)), | ||
], | ||
), | ||
), | ||
); | ||
} | ||
} |
138 changes: 138 additions & 0 deletions
138
lib/components/android/common/expandable_page_view.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import 'package:flutter/material.dart'; | ||
|
||
class ExpandablePageView extends StatefulWidget { | ||
final int itemCount; | ||
final Widget Function(BuildContext, int) itemBuilder; | ||
final PageController? controller; | ||
final ValueChanged<int>? onPageChanged; | ||
final bool reverse; | ||
final double defaultHeight; | ||
|
||
const ExpandablePageView({ | ||
required this.itemCount, | ||
required this.itemBuilder, | ||
this.controller, | ||
this.onPageChanged, | ||
this.reverse = false, | ||
this.defaultHeight = 1750, | ||
super.key, | ||
}); | ||
|
||
@override | ||
_ExpandablePageViewState createState() => _ExpandablePageViewState(); | ||
} | ||
|
||
class _ExpandablePageViewState extends State<ExpandablePageView> { | ||
PageController? _pageController; | ||
late List<double> _heights; | ||
int _currentPage = 0; | ||
|
||
double get _currentHeight => _heights[_currentPage]; | ||
|
||
@override | ||
void initState() { | ||
super.initState(); | ||
_heights = | ||
List.filled(widget.itemCount, widget.defaultHeight, growable: true); | ||
_pageController = widget.controller ?? PageController(); | ||
_pageController?.addListener(_updatePage); | ||
} | ||
|
||
@override | ||
void dispose() { | ||
_pageController?.removeListener(_updatePage); | ||
_pageController?.dispose(); | ||
super.dispose(); | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return TweenAnimationBuilder<double>( | ||
curve: Curves.easeInOutCubic, | ||
tween: Tween<double>(begin: _heights.first, end: _currentHeight), | ||
duration: const Duration(milliseconds: 300), | ||
builder: (context, value, child) => SizedBox(height: value, child: child), | ||
child: PageView.builder( | ||
controller: _pageController, | ||
itemCount: widget.itemCount, | ||
physics: const BouncingScrollPhysics(), | ||
itemBuilder: _itemBuilder, | ||
onPageChanged: widget.onPageChanged, | ||
reverse: widget.reverse, | ||
), | ||
); | ||
} | ||
|
||
Widget _itemBuilder(BuildContext context, int index) { | ||
final item = widget.itemBuilder(context, index); | ||
return OverflowBox( | ||
minHeight: 0, | ||
maxHeight: double.infinity, | ||
alignment: Alignment.topCenter, | ||
child: SizeReportingWidget( | ||
onSizeChange: (size) { | ||
WidgetsBinding.instance.addPostFrameCallback((_) { | ||
if (mounted) { | ||
setState(() { | ||
if ((size.height - widget.defaultHeight).abs() > 10) { | ||
_heights[index] = size.height; | ||
} | ||
}); | ||
} | ||
}); | ||
}, | ||
child: item, | ||
), | ||
); | ||
} | ||
|
||
void _updatePage() { | ||
final newPage = _pageController?.page?.round(); | ||
if (_currentPage != newPage) { | ||
// Use post-frame callback to defer state update | ||
WidgetsBinding.instance.addPostFrameCallback((_) { | ||
if (mounted) { | ||
setState(() { | ||
_currentPage = newPage ?? _currentPage; | ||
}); | ||
} | ||
}); | ||
} | ||
} | ||
} | ||
|
||
class SizeReportingWidget extends StatefulWidget { | ||
final Widget child; | ||
final ValueChanged<Size> onSizeChange; | ||
|
||
const SizeReportingWidget({ | ||
required this.child, | ||
required this.onSizeChange, | ||
super.key, | ||
}); | ||
|
||
@override | ||
_SizeReportingWidgetState createState() => _SizeReportingWidgetState(); | ||
} | ||
|
||
class _SizeReportingWidgetState extends State<SizeReportingWidget> { | ||
Size? _oldSize; | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
WidgetsBinding.instance.addPostFrameCallback((_) { | ||
_notifySize(); | ||
}); | ||
return widget.child; | ||
} | ||
|
||
void _notifySize() { | ||
if (mounted) { | ||
final size = context.size; | ||
if (_oldSize != size) { | ||
_oldSize = size; | ||
if (size != null) widget.onSizeChange(size); | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.