custom_roi_cells 0.2.2
custom_roi_cells: ^0.2.2 copied to clipboard
Flutter package for creating grid cells with customizable screen size and number of cells for ROI camera applications.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:custom_roi_cells/custom_roi_cells.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Custom ROI Camera Cells Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final CellsController controller = CellsController(
screenWidth: 600.0,
screenHeight: 400.0,
cellsRows: 25,
cellsColumns: 15,
);
List<int> selectedIndices = [];
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text('Custom ROI Camera Cells'),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header với hướng dẫn
Container(
padding: const EdgeInsets.all(16.0),
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.blue),
),
child: const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'📱 Custom ROI Camera Cells',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
SizedBox(height: 8),
Text(
'• Tap để chọn/bỏ chọn một cell',
style: TextStyle(fontSize: 14),
),
Text(
'• Drag từ cell chưa chọn → Chọn nhiều cells',
style: TextStyle(fontSize: 14),
),
Text(
'• Drag từ cell đã chọn → Bỏ chọn các cells',
style: TextStyle(fontSize: 14),
),
Text(
'• Cells được chọn sẽ hiển thị màu đỏ',
style: TextStyle(fontSize: 14),
),
],
),
),
const SizedBox(height: 24),
// Cells Grid với Selection
Text(
'Grid Cells (${controller.cellsRows}x${controller.cellsColumns}):',
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
Center(
child: Container(
padding: const EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Colors.grey[100],
border: Border.all(color: Colors.grey[300]!, width: 2),
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 5),
),
],
),
child: CellsWidget(
controller: controller,
enableSelection: true,
borderColor: Colors.blue[300]!,
borderWidth: 0.5,
cellColor: Colors.white,
selectedCellColor: Colors.red.withOpacity(0.7),
showCellNumbers: false,
onSelectionChanged: (indices) {
setState(() {
selectedIndices = indices;
});
},
),
),
),
const SizedBox(height: 20),
// Nút điều khiển
CellsSelectionButtons(
controller: controller,
onSave: (indices) {
setState(() {
selectedIndices = indices;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('✅ Đã lưu ${indices.length} cells'),
backgroundColor: Colors.green,
duration: const Duration(seconds: 2),
),
);
},
onDelete: (indices) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('🗑️ Đã xóa ${indices.length} cells'),
backgroundColor: Colors.orange,
duration: const Duration(seconds: 1),
),
);
},
onClear: () {
setState(() {
selectedIndices = [];
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('🧹 Đã xóa tất cả selection'),
duration: Duration(seconds: 1),
),
);
},
),
// Hiển thị kết quả selection
if (selectedIndices.isNotEmpty) ...[
const SizedBox(height: 20),
Container(
padding: const EdgeInsets.all(16.0),
decoration: BoxDecoration(
color: Colors.green[50],
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.green[300]!, width: 2),
boxShadow: [
BoxShadow(
color: Colors.green.withOpacity(0.1),
blurRadius: 8,
offset: const Offset(0, 4),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
const Icon(Icons.check_circle, color: Colors.green),
const SizedBox(width: 8),
Text(
'Đã chọn ${selectedIndices.length} cells',
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.green,
),
),
],
),
const SizedBox(height: 12),
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.grey[300]!),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Danh sách index:',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
selectedIndices.length > 30
? '${selectedIndices.take(30).join(", ")}... (và ${selectedIndices.length - 30} cells khác)'
: selectedIndices.join(", "),
style: const TextStyle(fontSize: 12),
),
const SizedBox(height: 12),
const Text(
'Mảng JSON:',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(4),
),
child: SelectableText(
'[${selectedIndices.join(",")}]',
style: const TextStyle(
fontSize: 12,
fontFamily: 'monospace',
color: Colors.blue,
),
),
),
],
),
),
],
),
),
] else ...[
const SizedBox(height: 20),
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(8),
),
child: const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.info_outline, color: Colors.grey),
SizedBox(width: 8),
Text(
'Chưa có cells nào được chọn',
style: TextStyle(
fontSize: 14,
color: Colors.grey,
fontStyle: FontStyle.italic,
),
),
],
),
),
],
],
),
),
);
}
}