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

@ -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,9 +89,9 @@ 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,
@ -94,7 +101,16 @@ class _HomeScreenState extends State<HomeScreen> {
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(
cat,
style: TextStyle(
fontSize: 14,
color:
selected
? Colors.white
: const Color(0xFF666666),
),
),
selected: selected, selected: selected,
selectedColor: const Color(0xFF1976D2), selectedColor: const Color(0xFF1976D2),
backgroundColor: const Color(0xFFF5F5F5), backgroundColor: const Color(0xFFF5F5F5),
@ -104,10 +120,7 @@ class _HomeScreenState extends State<HomeScreen> {
}).toList(), }).toList(),
), ),
), ),
), Padding(
// Time filter
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Row( child: Row(
children: ['全部', '今天', '明天', '本周'].map((t) { children: ['全部', '今天', '明天', '本周'].map((t) {
@ -116,41 +129,48 @@ class _HomeScreenState extends State<HomeScreen> {
padding: const EdgeInsets.only(right: 12), padding: const EdgeInsets.only(right: 12),
child: GestureDetector( child: GestureDetector(
onTap: () => setState(() => _timeFilter = t), onTap: () => setState(() => _timeFilter = t),
child: Text(t, style: TextStyle( child: Text(
t,
style: TextStyle(
fontSize: 16, fontSize: 16,
color: selected ? const Color(0xFF1976D2) : const Color(0xFF999999), color:
fontWeight: selected ? FontWeight.w600 : FontWeight.normal, selected
)), ? const Color(0xFF1976D2)
: const Color(0xFF999999),
fontWeight:
selected
? FontWeight.w600
: FontWeight.normal,
),
),
), ),
); );
}).toList(), }).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(
key: ValueKey(activity.id),
activity: activity,
imageHeight: index.isOdd ? 160.0 : 210.0,
onTap: () => Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (_) => ActivityDetailScreen(activity: activity), builder:
(_) => ActivityDetailScreen(
activity: filteredActivities[i],
),
),
), ),
), ),
);
},
), ),
), ),
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,15 +206,23 @@ 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,
borderRadius: BorderRadius.circular(12),
child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
@ -204,6 +234,9 @@ class _ActivityCardState extends State<_ActivityCard> {
), ),
], ],
), ),
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.