fix: v1.1.8+10 - SliverMasonryGrid performance + signup restore + ripple fix

This commit is contained in:
Ubuntu 2026-02-17 22:43:32 +08:00
parent a28a844d1d
commit e7f9b21d06
4 changed files with 146 additions and 86 deletions

View File

@ -8,7 +8,7 @@ class Activity {
int currentParticipants; int currentParticipants;
String creatorName; String creatorName;
String description; String description;
Activity({ Activity({
required this.id, required this.id,
required this.title, required this.title,
@ -20,4 +20,6 @@ class Activity {
required this.creatorName, required this.creatorName,
this.description = '', this.description = '',
}); });
bool get isFull => currentParticipants >= maxParticipants;
} }

View File

@ -47,6 +47,7 @@ class _HomeScreenState extends State<HomeScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final filteredActivities = _filteredActivities;
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Row( title: Row(
@ -54,7 +55,10 @@ class _HomeScreenState extends State<HomeScreen> {
children: [ children: [
const Icon(Icons.location_on, size: 18, color: Color(0xFF1976D2)), const Icon(Icons.location_on, size: 18, color: Color(0xFF1976D2)),
const SizedBox(width: 4), const SizedBox(width: 4),
const Text('成都', style: TextStyle(fontSize: 16, color: Color(0xFF666666))), const Text(
'成都',
style: TextStyle(fontSize: 16, color: Color(0xFF666666)),
),
const SizedBox(width: 16), const SizedBox(width: 16),
Expanded( Expanded(
child: Container( child: Container(
@ -68,7 +72,10 @@ class _HomeScreenState extends State<HomeScreen> {
SizedBox(width: 12), SizedBox(width: 12),
Icon(Icons.search, size: 20, color: Color(0xFF999999)), Icon(Icons.search, size: 20, color: Color(0xFF999999)),
SizedBox(width: 8), SizedBox(width: 8),
Text('搜索活动', style: TextStyle(fontSize: 14, color: Color(0xFF999999))), Text(
'搜索活动',
style: TextStyle(fontSize: 14, color: Color(0xFF999999)),
),
], ],
), ),
), ),
@ -82,75 +89,88 @@ class _HomeScreenState extends State<HomeScreen> {
onRefresh: () async => _loadActivities(), onRefresh: () async => _loadActivities(),
child: CustomScrollView( child: CustomScrollView(
slivers: [ slivers: [
// Category chips SliverList(
SliverToBoxAdapter( delegate: SliverChildListDelegate([
child: SizedBox( SizedBox(
height: 48, height: 48,
child: ListView( child: ListView(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
children: AppConstants.activityCategories.map((cat) { children: AppConstants.activityCategories.map((cat) {
final selected = _selectedCategory == cat; final selected = _selectedCategory == cat;
return Padding( return Padding(
padding: const EdgeInsets.only(right: 8), padding: const EdgeInsets.only(right: 8),
child: ChoiceChip( child: ChoiceChip(
label: Text(cat, style: TextStyle(fontSize: 14, color: selected ? Colors.white : const Color(0xFF666666))), label: Text(
selected: selected, cat,
selectedColor: const Color(0xFF1976D2), style: TextStyle(
backgroundColor: const Color(0xFFF5F5F5), fontSize: 14,
onSelected: (_) => setState(() => _selectedCategory = cat), color:
), selected
); ? Colors.white
}).toList(), : const Color(0xFF666666),
),
),
selected: selected,
selectedColor: const Color(0xFF1976D2),
backgroundColor: const Color(0xFFF5F5F5),
onSelected: (_) => setState(() => _selectedCategory = cat),
),
);
}).toList(),
),
), ),
), Padding(
), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
// Time filter child: Row(
SliverToBoxAdapter( children: ['全部', '今天', '明天', '本周'].map((t) {
child: Padding( final selected = _timeFilter == t;
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), return Padding(
child: Row( padding: const EdgeInsets.only(right: 12),
children: ['全部', '今天', '明天', '本周'].map((t) { child: GestureDetector(
final selected = _timeFilter == t; onTap: () => setState(() => _timeFilter = t),
return Padding( child: Text(
padding: const EdgeInsets.only(right: 12), t,
child: GestureDetector( style: TextStyle(
onTap: () => setState(() => _timeFilter = t), fontSize: 16,
child: Text(t, style: TextStyle( color:
fontSize: 16, selected
color: selected ? const Color(0xFF1976D2) : const Color(0xFF999999), ? const Color(0xFF1976D2)
fontWeight: selected ? FontWeight.w600 : FontWeight.normal, : const Color(0xFF999999),
)), fontWeight:
), selected
); ? FontWeight.w600
}).toList(), : FontWeight.normal,
),
),
),
);
}).toList(),
),
), ),
), ]),
), ),
// Activity list SliverPadding(
SliverToBoxAdapter( padding: const EdgeInsets.all(12),
child: MasonryGridView.count( sliver: SliverMasonryGrid.count(
crossAxisCount: 2, crossAxisCount: 2,
mainAxisSpacing: 10, mainAxisSpacing: 10,
crossAxisSpacing: 10, crossAxisSpacing: 10,
padding: const EdgeInsets.all(12), childCount: filteredActivities.length,
shrinkWrap: true, itemBuilder: (ctx, i) => _ActivityCard(
physics: const NeverScrollableScrollPhysics(), key: ValueKey(filteredActivities[i].id),
itemCount: _filteredActivities.length, activity: filteredActivities[i],
itemBuilder: (ctx, index) { onTap:
final activity = _filteredActivities[index]; () => Navigator.push(
return _ActivityCard( context,
key: ValueKey(activity.id), MaterialPageRoute(
activity: activity, builder:
imageHeight: index.isOdd ? 160.0 : 210.0, (_) => ActivityDetailScreen(
onTap: () => Navigator.push( activity: filteredActivities[i],
context, ),
MaterialPageRoute( ),
builder: (_) => ActivityDetailScreen(activity: activity),
), ),
), ),
);
},
), ),
), ),
const SliverToBoxAdapter(child: SizedBox(height: 80)), const SliverToBoxAdapter(child: SizedBox(height: 80)),
@ -158,7 +178,11 @@ class _HomeScreenState extends State<HomeScreen> {
), ),
), ),
floatingActionButton: FloatingActionButton.extended( floatingActionButton: FloatingActionButton.extended(
onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const CreateActivityScreen())), onPressed:
() => Navigator.push(
context,
MaterialPageRoute(builder: (_) => const CreateActivityScreen()),
),
icon: const Icon(Icons.add), icon: const Icon(Icons.add),
label: const Text('发起活动', style: TextStyle(fontSize: 16)), label: const Text('发起活动', style: TextStyle(fontSize: 16)),
backgroundColor: const Color(0xFF1976D2), backgroundColor: const Color(0xFF1976D2),
@ -170,12 +194,10 @@ class _HomeScreenState extends State<HomeScreen> {
class _ActivityCard extends StatefulWidget { class _ActivityCard extends StatefulWidget {
final Activity activity; final Activity activity;
final double imageHeight;
final VoidCallback onTap; final VoidCallback onTap;
const _ActivityCard({ const _ActivityCard({
super.key, super.key,
required this.activity, required this.activity,
required this.imageHeight,
required this.onTap, required this.onTap,
}); });
@ -184,26 +206,37 @@ class _ActivityCard extends StatefulWidget {
} }
class _ActivityCardState extends State<_ActivityCard> { class _ActivityCardState extends State<_ActivityCard> {
bool _isJoined = false;
void _joinActivity() {
setState(() => _isJoined = true);
ScaffoldMessenger.of(context)
..hideCurrentSnackBar()
..showSnackBar(const SnackBar(content: Text("报名成功!")));
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final activity = widget.activity; final activity = widget.activity;
final canJoin = !activity.isFull && !_isJoined;
final imageHeight = activity.id.hashCode.isOdd ? 160.0 : 210.0;
return Material( return Material(
color: Colors.transparent, color: Colors.transparent,
child: InkWell( child: Ink(
onTap: widget.onTap, decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12), color: Colors.white,
child: Container( borderRadius: BorderRadius.circular(12),
decoration: BoxDecoration( boxShadow: [
color: Colors.white, BoxShadow(
borderRadius: BorderRadius.circular(12), color: Colors.black.withOpacity(0.06),
boxShadow: [ blurRadius: 6,
BoxShadow( offset: const Offset(0, 2),
color: Colors.black.withOpacity(0.06), ),
blurRadius: 6, ],
offset: const Offset(0, 2), ),
), child: InkWell(
], onTap: widget.onTap,
), borderRadius: BorderRadius.circular(12),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -214,11 +247,11 @@ class _ActivityCardState extends State<_ActivityCard> {
), ),
child: Image.network( child: Image.network(
"https://picsum.photos/seed/${activity.title.hashCode.abs()}/400/300", "https://picsum.photos/seed/${activity.title.hashCode.abs()}/400/300",
height: widget.imageHeight, height: imageHeight,
width: double.infinity, width: double.infinity,
fit: BoxFit.cover, fit: BoxFit.cover,
errorBuilder: (_, __, ___) => Container( errorBuilder: (_, __, ___) => Container(
height: widget.imageHeight, height: imageHeight,
color: const Color(0xFFE0E0E0), color: const Color(0xFFE0E0E0),
), ),
), ),
@ -265,6 +298,31 @@ class _ActivityCardState extends State<_ActivityCard> {
), ),
], ],
), ),
const SizedBox(height: 8),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: canJoin ? _joinActivity : null,
style: ElevatedButton.styleFrom(
minimumSize: const Size.fromHeight(36),
backgroundColor: const Color(0xFF1976D2),
foregroundColor: Colors.white,
disabledBackgroundColor: const Color(0xFFE0E0E0),
disabledForegroundColor: const Color(0xFF999999),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
textStyle: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w600,
),
padding: EdgeInsets.zero,
),
child: Text(
_isJoined ? "已报名" : activity.isFull ? "已满员" : "报名",
),
),
),
], ],
), ),
), ),

View File

@ -1,6 +1,6 @@
name: banxiang_app name: banxiang_app
description: 伴享 description: 伴享
version: 1.1.7+9 version: 1.1.8+10
environment: environment:
sdk: '>=3.0.0 <4.0.0' sdk: '>=3.0.0 <4.0.0'

Binary file not shown.