chatapp3-flutter/lib/modules/home/popular/mine/sc_home_mine_skeleton.dart
2026-04-15 11:44:49 +08:00

294 lines
8.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
const Duration _kHomeMineSkeletonAnimationDuration = Duration(
milliseconds: 1450,
);
const Color _kHomeMineSkeletonShell = Color(0xFF0F3730);
const Color _kHomeMineSkeletonShellStrong = Color(0xFF1A4A41);
const Color _kHomeMineSkeletonBoneBase = Color(0xFF2B5C53);
const Color _kHomeMineSkeletonBoneHighlight = Color(0xFF5F8177);
const Color _kHomeMineSkeletonBorder = Color(0x66D8B57B);
class SCHomeSkeletonShimmer extends StatefulWidget {
const SCHomeSkeletonShimmer({super.key, required this.builder});
final Widget Function(BuildContext context, double progress) builder;
@override
State<SCHomeSkeletonShimmer> createState() => _SCHomeSkeletonShimmerState();
}
class _SCHomeSkeletonShimmerState extends State<SCHomeSkeletonShimmer>
with SingleTickerProviderStateMixin {
late final AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: _kHomeMineSkeletonAnimationDuration,
)..repeat();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) => widget.builder(context, _controller.value),
);
}
}
BoxDecoration buildHomeSkeletonShellDecoration({
required double radius,
EdgeInsetsGeometry? padding,
}) {
return BoxDecoration(
borderRadius: BorderRadius.circular(radius),
border: Border.all(color: _kHomeMineSkeletonBorder, width: 1.w),
gradient: const LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [_kHomeMineSkeletonShellStrong, _kHomeMineSkeletonShell],
),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.16),
blurRadius: 16.w,
offset: Offset(0, 8.w),
),
],
);
}
Widget buildHomeSkeletonBlock(
double progress, {
double? width,
required double height,
BorderRadius? borderRadius,
BoxShape shape = BoxShape.rectangle,
}) {
final double slideOffset = (progress * 2) - 1;
return Container(
width: width,
height: height,
decoration: BoxDecoration(
shape: shape,
borderRadius:
shape == BoxShape.circle
? null
: (borderRadius ?? BorderRadius.circular(10.w)),
gradient: LinearGradient(
begin: Alignment(-1.4 + slideOffset, -0.2),
end: Alignment(1.4 + slideOffset, 0.2),
colors: const [
_kHomeMineSkeletonBoneBase,
_kHomeMineSkeletonBoneBase,
_kHomeMineSkeletonBoneHighlight,
_kHomeMineSkeletonBoneBase,
],
stops: const [0.0, 0.36, 0.54, 1.0],
),
),
);
}
Widget buildHomeMyRoomSkeleton(double progress) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 12.w),
width: double.infinity,
height: 85.w,
decoration: buildHomeSkeletonShellDecoration(radius: 16.w),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 8.w),
child: Row(
children: [
buildHomeSkeletonBlock(
progress,
width: 70.w,
height: 70.w,
borderRadius: BorderRadius.circular(10.w),
),
SizedBox(width: 10.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
children: [
buildHomeSkeletonBlock(
progress,
width: 18.w,
height: 14.w,
borderRadius: BorderRadius.circular(3.w),
),
SizedBox(width: 5.w),
buildHomeSkeletonBlock(
progress,
width: 110.w,
height: 14.w,
borderRadius: BorderRadius.circular(999.w),
),
],
),
SizedBox(height: 9.w),
buildHomeSkeletonBlock(
progress,
width: 170.w,
height: 12.w,
borderRadius: BorderRadius.circular(999.w),
),
SizedBox(height: 8.w),
buildHomeSkeletonBlock(
progress,
width: 76.w,
height: 10.w,
borderRadius: BorderRadius.circular(999.w),
),
],
),
),
SizedBox(width: 10.w),
buildHomeSkeletonBlock(
progress,
width: 24.w,
height: 24.w,
shape: BoxShape.circle,
),
],
),
),
);
}
Widget buildHomeRoomGridSkeleton(
double progress, {
int itemCount = 6,
EdgeInsetsGeometry? padding,
}) {
return GridView.builder(
shrinkWrap: true,
padding: padding ?? EdgeInsets.symmetric(horizontal: 5.w),
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 1,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
),
itemCount: itemCount,
itemBuilder: (context, index) => buildHomeRoomCardSkeleton(progress),
);
}
Widget buildHomeRoomCardSkeleton(double progress) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 5.w, vertical: 5.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(14.w),
border: Border.all(color: _kHomeMineSkeletonBorder, width: 1.w),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.16),
blurRadius: 16.w,
offset: Offset(0, 8.w),
),
],
),
child: ClipRRect(
borderRadius: BorderRadius.circular(14.w),
child: Stack(
alignment: Alignment.bottomCenter,
children: [
Positioned.fill(
child: DecoratedBox(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
_kHomeMineSkeletonShellStrong,
_kHomeMineSkeletonShell,
],
),
),
),
),
Positioned.fill(
child: Padding(
padding: EdgeInsets.only(bottom: 34.w),
child: buildHomeSkeletonBlock(
progress,
height: double.infinity,
borderRadius: BorderRadius.vertical(top: Radius.circular(14.w)),
),
),
),
Positioned(
top: 12.w,
right: 12.w,
child: buildHomeSkeletonBlock(
progress,
width: 30.w,
height: 12.w,
borderRadius: BorderRadius.circular(999.w),
),
),
Positioned(
left: 0,
right: 0,
bottom: 0,
child: Container(
height: 34.w,
padding: EdgeInsets.symmetric(horizontal: 10.w),
decoration: BoxDecoration(
color: Colors.black.withValues(alpha: 0.24),
border: Border(
top: BorderSide(
color: Colors.white.withValues(alpha: 0.05),
width: 1.w,
),
),
),
child: Row(
children: [
buildHomeSkeletonBlock(
progress,
width: 20.w,
height: 13.w,
borderRadius: BorderRadius.circular(3.w),
),
SizedBox(width: 6.w),
Expanded(
child: buildHomeSkeletonBlock(
progress,
height: 10.w,
borderRadius: BorderRadius.circular(999.w),
),
),
SizedBox(width: 8.w),
buildHomeSkeletonBlock(
progress,
width: 18.w,
height: 10.w,
borderRadius: BorderRadius.circular(999.w),
),
],
),
),
),
],
),
),
);
}