Files
infinite_lazy_grid/example/lib/render_callbacks_example.dart
2025-08-16 20:55:50 +00:00

227 lines
7.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:infinite_lazy_grid/infinite_lazy_grid.dart';
import 'widgets/fps.dart';
class RenderCallbacksExample extends StatefulWidget {
const RenderCallbacksExample({super.key});
@override
State<RenderCallbacksExample> createState() => _RenderCallbacksExampleState();
}
class _RenderCallbacksExampleState extends State<RenderCallbacksExample> {
late final LazyCanvasController controller;
final List<CanvasChildId> childIds = [];
final List<String> logs = [];
final ScrollController logScrollController = ScrollController();
void onWidgetEnteredRender(CanvasChildId id) {
_addLog('Widget $id entered render area', Colors.green);
}
void onWidgetExitedRender(CanvasChildId id) {
_addLog('Widget $id exited render area', Colors.red);
}
@override
void initState() {
super.initState();
// Initialize controller with render callbacks
controller = LazyCanvasController(
debug: true,
onWidgetEnteredRender: onWidgetEnteredRender,
onWidgetExitedRender: onWidgetExitedRender,
);
_createGrid();
}
void _createGrid() {
// Create a 10x10 grid of widgets
for (int row = 0; row < 4; row++) {
for (int col = 0; col < 4; col++) {
final id = controller.addChild(
Offset(col * 180.0, row * 180.0),
GridItem(row: row, col: col, color: Colors.primaries[(row * 10 + col) % Colors.primaries.length]),
);
childIds.add(id);
}
}
}
void _addLog(String message, Color color) {
setState(() {
logs.insert(0, message);
// Keep only the last 50 logs
if (logs.length > 50) {
logs.removeRange(50, logs.length);
}
});
// Auto-scroll to top of logs
WidgetsBinding.instance.addPostFrameCallback((_) {
if (logScrollController.hasClients) {
logScrollController.animateTo(0, duration: const Duration(milliseconds: 300), curve: Curves.easeOut);
}
});
}
void _clearLogs() {
setState(() {
logs.clear();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Render Callbacks Example')),
body: Stack(
children: [
LazyCanvas(controller: controller),
// FPS counter
const Positioned(bottom: 16, left: 16, child: Fps()),
// Logs panel
Positioned(
top: 16,
right: 16,
child: Container(
width: 350,
height: 400,
decoration: BoxDecoration(
color: Colors.black.withValues(alpha: 0.8),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.grey),
),
child: Column(
children: [
// Header
Container(
padding: const EdgeInsets.all(8),
decoration: const BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.only(topLeft: Radius.circular(8), topRight: Radius.circular(8)),
),
child: Row(
children: [
const Expanded(
child: Text(
'Render Callbacks Log',
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
),
),
IconButton(
onPressed: _clearLogs,
icon: const Icon(Icons.clear, color: Colors.white),
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
),
],
),
),
// Logs list
Expanded(
child: logs.isEmpty
? const Center(
child: Text(
'Pan around to see render callbacks',
style: TextStyle(color: Colors.grey),
textAlign: TextAlign.center,
),
)
: ListView.builder(
controller: logScrollController,
padding: const EdgeInsets.all(8),
itemCount: logs.length,
itemBuilder: (context, index) {
final log = logs[index];
final isEntered = log.contains('entered');
return Padding(
padding: const EdgeInsets.only(bottom: 4),
child: Row(
children: [
Icon(
isEntered ? Icons.add_circle : Icons.remove_circle,
color: isEntered ? Colors.green : Colors.red,
size: 16,
),
const SizedBox(width: 8),
Expanded(
child: Text(
log,
style: TextStyle(
color: isEntered ? Colors.green : Colors.red,
fontSize: 12,
fontFamily: 'monospace',
),
),
),
],
),
);
},
),
),
],
),
),
),
],
),
);
}
@override
void dispose() {
logScrollController.dispose();
super.dispose();
}
}
class GridItem extends StatelessWidget {
final int row;
final int col;
final Color color;
const GridItem({super.key, required this.row, required this.col, required this.color});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Tapped grid item ($row, $col)'), duration: const Duration(seconds: 1)));
},
child: Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: color,
border: Border.all(color: Colors.black, width: 1),
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'$row',
style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 16),
),
Text(
'$col',
style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 16),
),
],
),
),
),
);
}
}