collapsing_list_view improvement

pull/124/head
Sikander Saleem 4 weeks ago
parent 345e2a1fca
commit a78769df67

@ -6,6 +6,7 @@ import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_export.dart'; import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/context_extensions.dart';
import 'package:hmg_patient_app_new/extensions/route_extensions.dart'; import 'package:hmg_patient_app_new/extensions/route_extensions.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
@ -47,6 +48,8 @@ class CollapsingListView extends StatelessWidget {
this.physics, this.physics,
}); });
final ScrollController _controller = ScrollController();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
AppState appState = getIt.get<AppState>(); AppState appState = getIt.get<AppState>();
@ -56,20 +59,36 @@ class CollapsingListView extends StatelessWidget {
children: [ children: [
CustomScrollView( CustomScrollView(
physics: physics, physics: physics,
controller: _controller,
slivers: [ slivers: [
SliverAppBar( SliverAppBar(
automaticallyImplyLeading: false, automaticallyImplyLeading: isLeading,
pinned: true, pinned: true,
expandedHeight: MediaQuery.of(context).size.height * 0.11.h, toolbarHeight: isLeading ? 24.h : kToolbarHeight,
stretch: true, leadingWidth: isLeading ? null : double.infinity,
systemOverlayStyle: SystemUiOverlayStyle(statusBarBrightness: Brightness.light), systemOverlayStyle: SystemUiOverlayStyle(statusBarBrightness: Brightness.light),
surfaceTintColor: Colors.transparent, surfaceTintColor: Colors.transparent,
backgroundColor: AppColors.bgScaffoldColor, backgroundColor: AppColors.bgScaffoldColor,
bottom: isLeading
? ScrollAnimatedTitle(
title: title,
showBack: true,
controller: _controller,
search: search,
report: report,
logout: logout,
history: history,
instructions: instructions,
requests: requests,
bottomChild: bottomChild,
trailing: trailing,
)
: null,
leading: isLeading leading: isLeading
? Transform.flip( ? Transform.flip(
flipX: appState.isArabic(), flipX: appState.isArabic(),
child: IconButton( child: IconButton(
icon: Utils.buildSvgWithAssets(icon: isClose ? AppAssets.closeBottomNav : AppAssets.arrow_back, width: 32.h, height: 32.h), icon: Utils.buildSvgWithAssets(icon: isClose ? AppAssets.closeBottomNav : AppAssets.arrow_back, width: 24.h, height: 24.h),
padding: EdgeInsets.only(left: 12), padding: EdgeInsets.only(left: 12),
onPressed: () { onPressed: () {
if (leadingCallback != null) { if (leadingCallback != null) {
@ -81,67 +100,18 @@ class CollapsingListView extends StatelessWidget {
highlightColor: Colors.transparent, highlightColor: Colors.transparent,
), ),
) )
: SizedBox.shrink(), : ScrollAnimatedTitle(
flexibleSpace: LayoutBuilder( title: title,
builder: (context, constraints) { showBack: false,
final double maxHeight = 100.h; controller: _controller,
final double minHeight = kToolbarHeight; search: search,
double t = (constraints.maxHeight - minHeight) / (maxHeight - minHeight); report: report,
t = t - 1; logout: logout,
if (t < 0.7) t = 0.7; history: history,
t = t.clamp(0.0, 1.0); instructions: instructions,
requests: requests,
final double fontSize = lerpDouble(14, 18, t)!; bottomChild: bottomChild,
final double bottomPadding = lerpDouble(0, 0, t)!; trailing: trailing,
final double leftPadding = lerpDouble(150, 24, t)!;
return Stack(
children: [
Align(
alignment: Alignment.lerp(
Alignment.center,
Alignment.bottomLeft,
t,
)!,
child: Padding(
padding: EdgeInsets.only(
left: appState.isArabic() ? 0 : leftPadding, right: appState.isArabic() ? leftPadding : 0, bottom: bottomPadding),
child: Row(
spacing: 4.h,
children: [
Text(
title,
maxLines: 1,
style: TextStyle(
fontSize: (27 - (5 * (2 - t))).f,
fontWeight: FontWeight.lerp(
FontWeight.w300,
FontWeight.w600,
t,
)!,
color: AppColors.blackColor,
letterSpacing: -0.5),
).expanded,
if (logout != null)
actionButton(context, t, title: "Logout".needTranslation, icon: AppAssets.logout).onPress(logout!),
if (report != null)
actionButton(context, t, title: "Feedback".needTranslation, icon: AppAssets.report_icon).onPress(report!),
if (history != null)
actionButton(context, t, title: "History".needTranslation, icon: AppAssets.insurance_history_icon)
.onPress(history!),
if (instructions != null)
actionButton(context, t, title: "Instructions".needTranslation, icon: AppAssets.requests).onPress(instructions!),
if (requests != null)
actionButton(context, t, title: "Requests".needTranslation, icon: AppAssets.insurance_history_icon)
.onPress(requests!),
if (search != null) Utils.buildSvgWithAssets(icon: AppAssets.search_icon).onPress(search!).paddingOnly(right: 24),
if (trailing != null) trailing!,
],
)),
),
],
);
},
), ),
), ),
SliverList( SliverList(
@ -158,13 +128,161 @@ class CollapsingListView extends StatelessWidget {
); );
} }
// Widget actionButton(BuildContext context, double t, {required String title, required String icon}) {
// return AnimatedSize(
// duration: Duration(milliseconds: 150),
// child: Container(
// height: 40.h,
// padding: EdgeInsets.all(8.w),
// margin: EdgeInsets.only(right: 24.w),
// decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
// color: AppColors.secondaryLightRedColor,
// borderRadius: 10.r,
// ),
// child: Row(
// crossAxisAlignment: CrossAxisAlignment.center,
// mainAxisAlignment: MainAxisAlignment.center,
// mainAxisSize: MainAxisSize.min,
// spacing: 8.h,
// children: [
// Utils.buildSvgWithAssets(icon: icon, iconColor: AppColors.primaryRedColor),
// if (t == 1)
// Text(
// title,
// style: context.dynamicTextStyle(
// color: AppColors.primaryRedColor,
// letterSpacing: -0.4,
// fontSize: (12 - (2 * (1 - t))).f,
// fontWeight: FontWeight.lerp(
// FontWeight.w300,
// FontWeight.w500,
// t,
// )!,
// ),
// ),
// ],
// ),
// ),
// );
// }
}
//
// class ActionModel {
// bool requireT;
//
// }
class ScrollAnimatedTitle extends StatefulWidget implements PreferredSizeWidget {
final String title;
final bool showBack;
final ScrollController controller;
VoidCallback? search;
VoidCallback? report;
VoidCallback? logout;
VoidCallback? history;
VoidCallback? instructions;
VoidCallback? requests;
Widget? bottomChild;
Widget? trailing;
ScrollAnimatedTitle({
super.key,
required this.title,
required this.controller,
required this.showBack,
this.search,
this.report,
this.logout,
this.history,
this.instructions,
this.requests,
this.bottomChild,
this.trailing,
});
@override
Size get preferredSize => const Size.fromHeight(50);
@override
State<ScrollAnimatedTitle> createState() => _ScrollAnimatedTitleState();
}
class _ScrollAnimatedTitleState extends State<ScrollAnimatedTitle> {
static const double _maxFont = 24;
static const double _minFont = 14;
static const double _maxHeight = 80;
static const double _minHeight = 56;
double _fontSize = _maxFont;
@override
void initState() {
super.initState();
widget.controller.addListener(_onScroll);
}
@override
void dispose() {
widget.controller.removeListener(_onScroll);
super.dispose();
}
double t = 0;
void _onScroll() {
final double offset = widget.controller.offset;
// control animation range
const double range = 120;
final double t = (1 - (offset / range)).clamp(0.0, 1.0);
this.t = t;
setState(() {
_fontSize = _minFont + (_maxFont - _minFont) * t;
});
}
@override
Widget build(BuildContext context) {
final isRtl = Directionality.of(context) == TextDirection.rtl;
return Container(
height: (widget.preferredSize.height - _fontSize / 2).h,
alignment: isRtl ? (widget.showBack ? Alignment.topRight : Alignment.centerRight) : (widget.showBack ? Alignment.topLeft : Alignment.centerLeft),
padding: EdgeInsets.fromLTRB(24, 0, 24, 0),
child: Row(
spacing: 4.h,
children: [
Text(
widget.title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: _fontSize,
fontWeight: FontWeight.bold,
),
).expanded,
...[
if (widget.logout != null) actionButton(context, t, title: "Logout".needTranslation, icon: AppAssets.logout).onPress(widget.logout!),
if (widget.report != null) actionButton(context, t, title: "Feedback".needTranslation, icon: AppAssets.report_icon).onPress(widget.report!),
if (widget.history != null) actionButton(context, t, title: "History".needTranslation, icon: AppAssets.insurance_history_icon).onPress(widget.history!),
if (widget.instructions != null) actionButton(context, t, title: "Instructions".needTranslation, icon: AppAssets.requests).onPress(widget.instructions!),
if (widget.requests != null) actionButton(context, t, title: "Requests".needTranslation, icon: AppAssets.insurance_history_icon).onPress(widget.requests!),
if (widget.search != null) Utils.buildSvgWithAssets(icon: AppAssets.search_icon).onPress(widget.search!),
if (widget.trailing != null) widget.trailing!,
]
],
),
);
}
Widget actionButton(BuildContext context, double t, {required String title, required String icon}) { Widget actionButton(BuildContext context, double t, {required String title, required String icon}) {
return AnimatedSize( return AnimatedSize(
duration: Duration(milliseconds: 150), duration: Duration(milliseconds: 150),
child: Container( child: Container(
height: 40.h, height: 36.h + (4.h * t),
padding: EdgeInsets.all(8.w), padding: EdgeInsets.all(8.w),
margin: EdgeInsets.only(right: 24.w),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration( decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.secondaryLightRedColor, color: AppColors.secondaryLightRedColor,
borderRadius: 10.r, borderRadius: 10.r,
@ -176,7 +294,7 @@ class CollapsingListView extends StatelessWidget {
spacing: 8.h, spacing: 8.h,
children: [ children: [
Utils.buildSvgWithAssets(icon: icon, iconColor: AppColors.primaryRedColor), Utils.buildSvgWithAssets(icon: icon, iconColor: AppColors.primaryRedColor),
if (t == 1) if (t >= .5)
Text( Text(
title, title,
style: context.dynamicTextStyle( style: context.dynamicTextStyle(
@ -184,7 +302,7 @@ class CollapsingListView extends StatelessWidget {
letterSpacing: -0.4, letterSpacing: -0.4,
fontSize: (12 - (2 * (1 - t))).f, fontSize: (12 - (2 * (1 - t))).f,
fontWeight: FontWeight.lerp( fontWeight: FontWeight.lerp(
FontWeight.w300, FontWeight.w400,
FontWeight.w500, FontWeight.w500,
t, t,
)!, )!,

Loading…
Cancel
Save