custom_roi_cells 0.3.5
custom_roi_cells: ^0.3.5 copied to clipboard
Flutter package for creating grid cells with customizable screen size and number of cells for ROI camera applications, data tables, Excel-like spreadsheets, and more!
custom_roi_cells #
Flutter package for creating grid cells with customizable screen size and number of cells. Useful for creating ROI (Region of Interest) in camera applications.
π Table of Contents #
- Features
- Demo
- Installation
- Quick Start
- Usage
- API Reference
- Testing Guide
- Publishing to pub.dev
- Contributing
- License
Features #
Core Features #
- β Customizable screen size (width and height)
- β Customizable number of cells (rows and columns)
- β Select cells by tap and drag - Tap to select/deselect, drag to select multiple cells
- β Highlight selected cells - Selected cells will be highlighted in red
- β Save selection as index array - Example: [0,1,2,3,...]
- β Custom row and column colors - Set different colors for specific rows and columns
- β Custom selected/unselected cell colors - Different colors for selected and unselected cells
- β Widget with form input to enter parameters
- β Controller to manage state
- β Callback when cell is selected
- β Customizable colors, border, and cell number display
- β Control buttons: Save, Delete, Clear selection
- β Responsive and easy to use
Excel-like Features (NEW!) #
- β Editable cells - Click to edit text in cells
- β
Data binding - Load data from
List<List<String>>orList<Map<String, dynamic>> - β Display data as table - Show data in table format with headers
- β Cell formatting - Customize text color, background color, font size, font weight, text alignment per cell
- β Search functionality - Search text in cells
- β Sort functionality - Sort data by column(s)
- β Filter functionality - Filter rows by condition
- β Export/Import - Export to CSV, JSON and import from CSV, JSON
- β Header rows - Display header row with custom styling
- β
Cell data management - Manage cell data with
CellsDataController
Demo #
Screenshots #
ROI Camera Application Example

Grid cells overlay on camera feed for defining warning zones (CαΊ£nh bΓ‘o vΓΉng)
Main Interface
[Main Interface]
Grid cells with selection capability
Selection Functionality
[Selection]
Tap and drag to select multiple cells
Control Buttons
[Control Buttons]
Save, Delete, and Clear buttons
Selection Result
[Selection Result]
Display selected indices as array
Video Demo #
[Drag Selection]
Drag to select multiple cells
Installation #
Add to your pubspec.yaml:
dependencies:
custom_roi_cells: ^0.2.0
Then run:
flutter pub get
Quick Start #
π Running the Example App #
Method 1: Android Studio (Recommended) β
- Open Android Studio
- File β Open β Select the
examplefolder - Wait for Android Studio to sync dependencies (1-2 minutes)
- Select device/emulator from dropdown at the top
- Press Run button (βΆ) or press Shift + F10
- App will build and run automatically
Method 2: Terminal
Windows (PowerShell or CMD):
cd example
flutter pub get
flutter run
Mac/Linux:
cd example
flutter pub get
flutter run
Method 3: Web (If supported)
cd example
flutter run -d chrome
π± What You'll See #
The app displays a 15x15 grid with the following interface:
βββββββββββββββββββββββββββββββββββββββββββ
β Custom ROI Camera Cells β
βββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββββββββββββββββββββββββ β
β β π± Custom ROI Camera Cells β β
β β β’ Tap to select/deselect a cell β β
β β β’ Drag to select multiple cells β β
β β β’ Selected cells will display in β β
β β red β β
β βββββββββββββββββββββββββββββββββββββ β
β β
β Grid Cells (15x15): β
β βββββββββββββββββββββββββββββββββββ β
β β β¬ β¬ β¬ β¬ β¬ β¬ β¬ β¬ β¬ β¬ β¬ β¬ β¬ β β
β β β¬ π΄ π΄ π΄ β¬ β¬ β¬ β¬ β¬ β¬ β¬ β¬ β¬ β β
β β β¬ π΄ π΄ π΄ β¬ β¬ β¬ β¬ β¬ β¬ β¬ β¬ β¬ β β
β β β¬ π΄ π΄ π΄ β¬ β¬ β¬ β¬ β¬ β¬ β¬ β¬ β¬ β β
β β β¬ β¬ β¬ β¬ β¬ β¬ β¬ β¬ β¬ β¬ β¬ β¬ β¬ β β
β β ... (15x15 grid) β β
β βββββββββββββββββββββββββββββββββββ β
β β
β [Save] [Delete] [Clear] β
β β
β β
Selected 9 cells: β
β List: 16, 17, 18, 31, 32, ... β
β Array: [16,17,18,31,32,33,46,47,48] β
β β
βββββββββββββββββββββββββββββββββββββββββββ
π¨ Interface Details #
Colors:
- Header: Light blue (#E3F2FD)
- Grid background: White
- Unselected cells: White
- Selected cells: Red (70% opacity)
- Cell borders: Light blue (#90CAF9)
- Save button: Blue (#2196F3)
- Delete button: Black (#424242)
- Clear button: Gray (#9E9E9E)
Sizes:
- Grid: 600px x 400px
- Cells: ~40px x ~27px (auto-calculated)
- Border: 0.5px
β¨ How to Use #
- Tap on cell: Select/deselect (red = selected)
- Drag mouse/finger: Select multiple cells at once
- Save button: Save selected index list
- Delete button: Delete selected cells
- Clear button: Clear all selection
Usage #
Method 1: Using with Controller #
import 'package:custom_roi_cells/custom_roi_cells.dart';
class MyWidget extends StatefulWidget {
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
// Initialize controller with custom parameters
final CellsController controller = CellsController(
screenWidth: 2048.0,
screenHeight: 500.0,
cellsRows: 32,
cellsColumns: 23,
);
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return CellsWidget(
controller: controller,
borderColor: Colors.blue,
borderWidth: 1.0,
cellColor: Colors.grey.withOpacity(0.1),
onCellTap: (row, column) {
print('Cell selected: Row $row, Column $column');
},
);
}
}
Method 2: Using directly with parameters #
CellsWidget(
screenWidth: 2048.0,
screenHeight: 500.0,
cellsRows: 32,
cellsColumns: 23,
borderColor: Colors.blue,
borderWidth: 0.5,
showCellNumbers: true,
onCellTap: (row, column) {
print('Cell at row $row, column $column');
},
)
Method 3: Using with Selection (Tap and Drag to select cells) #
final CellsController controller = CellsController(
screenWidth: 800.0,
screenHeight: 400.0,
cellsRows: 20,
cellsColumns: 20,
);
List<int> selectedIndices = [];
CellsWidget(
controller: controller,
enableSelection: true, // Enable selection feature
selectedCellColor: Colors.red.withOpacity(0.6),
unselectedCellColor: Colors.white, // Color for unselected cells
showCellNumbers: true, // Display cell indices
onSelectionChanged: (indices) {
selectedIndices = indices;
print('Selected: $indices');
},
)
// Selection control buttons
CellsSelectionButtons(
controller: controller,
onSave: (indices) {
print('Saved: $indices');
// indices is an array [0,1,2,3,...]
},
onDelete: (indices) {
print('Deleted: $indices');
},
onClear: () {
print('Cleared all selection');
},
)
Method 3.1: Using with Custom Row and Column Colors #
final CellsController controller = CellsController(
screenWidth: 800.0,
screenHeight: 400.0,
cellsRows: 20,
cellsColumns: 20,
);
CellsWidget(
controller: controller,
enableSelection: true,
// Color for selected cells
selectedCellColor: Colors.blue.withOpacity(0.5),
// Color for unselected cells
unselectedCellColor: Colors.white,
// Custom colors for specific rows
rowColors: {
0: Colors.yellow.withOpacity(0.3), // Row 0: yellow
1: Colors.green.withOpacity(0.3), // Row 1: green
5: Colors.orange.withOpacity(0.3), // Row 5: orange
},
// Custom colors for specific columns
columnColors: {
0: Colors.red.withOpacity(0.3), // Column 0: red
2: Colors.purple.withOpacity(0.3), // Column 2: purple
10: Colors.cyan.withOpacity(0.3), // Column 10: cyan
},
onSelectionChanged: (indices) {
print('Selected: $indices');
},
)
Note: Color priority: Selected cells > Row colors > Column colors > Unselected cell color
Method 4: Using Widget with Form Input #
CellsInputWidget(
controller: controller,
showCellsPreview: true,
onChanged: (width, height, rows, columns) {
print('Width: $width, Height: $height');
print('Rows: $rows, Columns: $columns');
},
)
Method 5: Using as Excel-like Table (NEW!) #
Display Data from List<List
final CellsController controller = CellsController(
screenWidth: 800.0,
screenHeight: 600.0,
cellsRows: 10,
cellsColumns: 5,
);
final data = [
['Name', 'Age', 'City', 'Email', 'Phone'],
['John', '25', 'New York', '[email protected]', '123-456-7890'],
['Jane', '30', 'London', '[email protected]', '098-765-4321'],
['Bob', '35', 'Paris', '[email protected]', '555-123-4567'],
];
CellsTableWidget(
controller: controller,
data: data,
enableEdit: true, // Allow editing cells
showHeader: true, // Show header row
headerBackgroundColor: Colors.blue[100],
onDataChanged: (newData) {
print('Data changed: $newData');
},
)
Display Data from List
final mapData = [
{'name': 'John', 'age': '25', 'city': 'New York'},
{'name': 'Jane', 'age': '30', 'city': 'London'},
{'name': 'Bob', 'age': '35', 'city': 'Paris'},
];
CellsTableWidget(
controller: controller,
mapData: mapData,
columns: ['name', 'age', 'city'], // Column order
enableEdit: true,
showHeader: true,
)
Using CellsDataController for Advanced Features
final CellsController controller = CellsController(
screenWidth: 800.0,
screenHeight: 600.0,
cellsRows: 20,
cellsColumns: 10,
);
final CellsDataController dataController = CellsDataController(controller);
// Load data
dataController.loadData([
['Header1', 'Header2', 'Header3'],
['Data1', 'Data2', 'Data3'],
['Data4', 'Data5', 'Data6'],
]);
// Edit cell
dataController.setCellText(5, 'New Text');
// Get cell text
final text = dataController.getCellText(5);
// Format cell
dataController.setCellData(5, CellData(
text: 'Formatted Text',
backgroundColor: Colors.yellow,
textColor: Colors.red,
fontWeight: FontWeight.bold,
textAlign: TextAlign.center,
));
// Display with CellsDataWidget
CellsDataWidget(
controller: controller,
dataController: dataController,
enableEdit: true,
)
Search, Sort, and Filter
// Search
final searchResults = CellsSearch.searchCells(
dataController,
controller,
'search text',
caseSensitive: false,
);
// Sort by column
CellsSort.sortByColumn(
dataController,
controller,
0, // Column index
ascending: true,
startRow: 1, // Skip header row
);
// Filter rows
final matchingRows = CellsFilter.filterRows(
dataController,
controller,
(rowData) => rowData[0].contains('John'), // Filter condition
);
// Export to CSV
final csvString = CellsExportImport.exportToCsv(dataController, controller);
// Export to JSON
final jsonData = CellsExportImport.exportToJson(dataController, controller);
// Import from CSV
CellsExportImport.importFromCsv(dataController, controller, csvString);
// Import from JSON
CellsExportImport.importFromJson(dataController, controller, jsonData);
API Reference #
CellsWidget #
Main widget to display grid cells.
Parameters:
controller(CellsController?): Controller to manage statescreenWidth(double?): Screen widthscreenHeight(double?): Screen heightcellsRows(int?): Number of cell rowscellsColumns(int?): Number of cell columnsborderColor(Color?): Border color (default: Colors.grey)borderWidth(double?): Border width (default: 1.0)cellColor(Color?): Cell background color (default: Colors.transparent)onCellTap(void Function(int row, int column)?): Callback when cell is tappedshowCellNumbers(bool): Show cell numbers (default: false)numberColor(Color?): Number text colornumberFontSize(double?): Number font sizeenableSelection(bool): Enable cell selection by tap and drag (default: false)selectedCellColor(Color?): Selected cell color (default: Colors.red.withOpacity(0.5))unselectedCellColor(Color?): Unselected cell color (takes priority over cellColor when enableSelection = true)rowColors(Map<int, Color>?): Map of row index to color for customizing row colorscolumnColors(Map<int, Color>?): Map of column index to color for customizing column colorsonSelectionChanged(void Function(ListonSaveSelection(void Function(List
CellsSelectionButtons #
Widget displaying selection control buttons (Save, Delete, Clear).
Parameters:
controller(CellsController): Controller to manage (required)onSave(void Function(ListonDelete(void Function(ListonClear(VoidCallback?): Callback when Clear button is pressedsaveButtonColor(Color?): Save button background color (default: Colors.blue)deleteButtonColor(Color?): Delete button background color (default: Colors.black87)clearButtonColor(Color?): Clear button background color (default: Colors.grey)showSelectionCount(bool): Show number of selected cells (default: true)
CellsInputWidget #
Widget with form input to enter parameters and display preview.
Parameters:
controller(CellsController?): Controller to manageonChanged(void Function(double width, double height, int rows, int columns)?): Callback when values changeshowCellsPreview(bool): Show cells preview (default: true)
CellsDataWidget #
Widget to display and edit data in cells (Excel-like).
Parameters:
controller(CellsController): Controller to manage grid (required)dataController(CellsDataController?): Data controller to manage cell dataenableEdit(bool): Allow editing cells (default: false)showHeader(bool): Show header row (default: false)headerBackgroundColor(Color?): Header background colorheaderTextStyle(TextStyle?): Header text styleborderColor(Color?): Cell border colorborderWidth(double?): Cell border widthdefaultCellColor(Color?): Default cell background coloreditingCellBorderColor(Color?): Border color when editingonCellTextChanged(void Function(int index, String text)?): Callback when cell text changesonCellTap(void Function(int index)?): Callback when cell is tapped
CellsTableWidget #
Widget to display data as a table (Excel-like) with support for List<List<String>> or List<Map>.
Parameters:
controller(CellsController): Controller to manage grid (required)dataController(CellsDataController?): Data controller to manage cell datadata(List<ListmapData(List<Map<String, dynamic>>?): Data as list of mapscolumns(ListenableEdit(bool): Allow editing cells (default: false)showHeader(bool): Show header row (default: true)headerBackgroundColor(Color?): Header background colorheaderTextStyle(TextStyle?): Header text styleborderColor(Color?): Cell border colorborderWidth(double?): Cell border widthdefaultCellColor(Color?): Default cell background coloronDataChanged(void Function(List<List
CellsDataController #
Controller to manage cell data (text, formatting, etc.).
Properties:
getCellText(int index): Get cell text by indexsetCellText(int index, String text): Set cell text by indexgetCellData(int index): Get CellData by indexsetCellData(int index, CellData cellData): Set CellData by indexloadData(List<List<String>> data): Load data from List<ListloadDataFromMaps(List<Map<String, dynamic>> data, {List<String>? columns}): Load data from ListexportData(): Export data as List<ListexportToJson(): Export data as JSONexportToCsv(): Export data as CSV stringimportFromJson(Map<String, dynamic> json): Import data from JSONclearData(): Clear all dataclearCell(int index): Clear cell data
CellData #
Class to store cell data and formatting.
Properties:
text(String): Cell textbackgroundColor(Color?): Background colortextColor(Color?): Text colorfontSize(double?): Font sizefontWeight(FontWeight?): Font weighttextAlign(TextAlign?): Text alignmentisMerged(bool): Is cell mergedrowSpan(int): Row span if mergedcolSpan(int): Column span if merged
CellsController #
Controller to manage cells state.
Constructor:
CellsController({
required double screenWidth, // Required, must be > 0
required double screenHeight, // Required, must be > 0
required int cellsRows, // Required, must be > 0
required int cellsColumns, // Required, must be > 0
})
Note: All parameters are required and must be greater than 0. If a value <= 0 is passed, an ArgumentError will be thrown.
Properties:
screenWidth(double): Screen widthscreenHeight(double): Screen heightcellsRows(int): Number of cell rowscellsColumns(int): Number of cell columnscellWidth(double): Width of each cell (read-only)cellHeight(double): Height of each cell (read-only)totalCells(int): Total number of cells (read-only)selectedCellIndices(SetselectedCellsCount(int): Number of selected cells (read-only)
Methods:
isCellSelected(int index): Check if a cell is selectedselectCell(int index): Select a cell by indexdeselectCell(int index): Deselect a cell by indexselectCells(List<int> indices): Select multiple cells by index listselectCellRange(int startIndex, int endIndex): Select a range of cellsselectRow(int row): Select an entire rowselectColumn(int column): Select an entire columnclearSelection(): Clear all selectiondeleteSelectedCells(): Delete selected cellsgetSelectedIndices(): Get list of selected indices as sorted arrayaddListener(void Function() listener): Register listenerremoveListener(void Function() listener): Unregister listenerdispose(): Dispose resources
CellsSearch #
Utility class for searching text in cells.
Methods:
searchCells(CellsDataController, CellsController, String searchText, {bool caseSensitive, bool matchWholeWord}): Search for text in cells, returns list of matching cell indicesreplaceAll(CellsDataController, CellsController, String searchText, String replaceText, {bool caseSensitive}): Replace all occurrences of search text, returns count of replacements
CellsSort #
Utility class for sorting data in cells.
Methods:
sortByColumn(CellsDataController, CellsController, int columnIndex, {bool ascending, int startRow}): Sort data by columnsortByMultipleColumns(CellsDataController, CellsController, List<int> columnIndexes, {List<bool>? ascending, int startRow}): Sort data by multiple columns
CellsFilter #
Utility class for filtering data in cells.
Methods:
filterRows(CellsDataController, CellsController, bool Function(List<String> rowData) filterFunction): Filter rows by condition, returns list of matching row indices
CellsExportImport #
Utility class for exporting and importing data.
Methods:
exportToCsv(CellsDataController, CellsController): Export data to CSV stringimportFromCsv(CellsDataController, CellsController, String csvString): Import data from CSV stringexportToJson(CellsDataController, CellsController): Export data to JSONimportFromJson(CellsDataController, CellsController, Map<String, dynamic> json): Import data from JSON
Testing Guide #
π§ͺ Test Cases #
Test 1: Select one cell
1. Tap on cell at position (0,0) - index 0
2. Expected: Cell turns red
3. Check: selectedIndices = [0]
Test 2: Select multiple individual cells
1. Tap on cell 0
2. Tap on cell 5
3. Tap on cell 10
4. Expected: 3 red cells
5. Check: selectedIndices = [0, 5, 10]
Test 3: Drag to select range
1. Press and hold cell 20
2. Drag to cell 25
3. Expected: Cells 20-25 all red
4. Check: selectedIndices = [20, 21, 22, 23, 24, 25]
Test 4: Select rectangle
1. Press and hold cell 30 (row 2, column 0)
2. Drag to cell 45 (row 3, column 0)
3. Expected: Select both row 2 and row 3
4. Check: selectedIndices contains cells from 30-44
Test 5: Save selection
1. Select some cells
2. Press Save button
3. Expected: Display SnackBar "β
Saved X cells"
4. Check: Index array displays correctly
Test 6: Delete selection
1. Select some cells
2. Press Delete button
3. Expected: Cells deselect, display SnackBar
4. Check: selectedIndices = []
Test 7: Clear selection
1. Select multiple cells
2. Press Clear button
3. Expected: All cells deselect
4. Check: selectedIndices = []
β Functionality Checklist #
Basic Interface
- β App opens
- β Header displays correctly
- β Grid cells display 15x15
- β Save, Delete, Clear buttons display
Selection Functionality
- β Tap on cell β Cell turns red
- β Tap again β Cell deselects (returns to white)
- β Drag from one cell to another β Select range
- β Drag diagonally β Select rectangle
Result Display
- β Select cells β Display count
- β Select cells β Display index list
- β Select cells β Display JSON array:
[0,1,2,3,...]
Control Buttons
- β Press Save β Save selection and display array
- β Press Delete β Delete selected cells
- β Press Clear β Clear all selection
β Troubleshooting #
Error "Flutter not found"
- Ensure Flutter SDK is installed
- Add Flutter to PATH
- Check installation:
flutter --version
Error "No devices found"
- Start Android Emulator in Android Studio
- Or connect phone and enable USB Debugging
- Create emulator: Tools β Device Manager β Create Device
Build error
- Run
flutter clean - Run
flutter pub getagain - Delete
.dart_toolandbuildfolders
Cells can't be selected
- Check
enableSelection: truein code - Ensure controller is properly initialized
Publishing to pub.dev #
Step 1: Preparation #
- Ensure Flutter SDK is installed
- Log in to pub.dev with Google account
- Check all required files:
pubspec.yaml- updated description and versionREADME.md- has complete documentationCHANGELOG.md- has changelogLICENSE- has license (MIT)example/- has example app
Step 2: Code Check #
Run the following commands to check:
# Format code
flutter format .
# Analyze code
flutter analyze
# Run tests
flutter test
# Run example app
cd example
flutter run
Step 3: Update Information in pubspec.yaml #
Ensure the following information is correct:
name: Package name (must be unique on pub.dev)description: Brief description (maximum 60 characters)version: Current versionhomepage: GitHub repository URLrepository: GitHub repository URLissue_tracker: GitHub issues URL
Note: Update GitHub URLs in pubspec.yaml with your actual repository.
Step 4: Create pub.dev Account #
- Visit https://pub.dev
- Log in with Google account
- Go to "Publisher" section to create publisher (if not already created)
Step 5: Publish Package #
# Check package before publishing
flutter pub publish --dry-run
# Publish package
flutter pub publish
Step 6: After Publishing #
- Check package on pub.dev
- Update README if needed
- Create tags on GitHub:
git tag v0.2.0 git push origin v0.2.0
Important Notes #
- Version: Must increment version for each publish
- Changelog: Always update CHANGELOG.md when there are changes
- Tests: Ensure all tests pass
- Documentation: Ensure README.md is complete and clear
- License: Must have license file
Update Package After Publishing #
- Update version in
pubspec.yaml - Update
CHANGELOG.md - Commit and push code
- Run
flutter pub publish - Create new tag on GitHub
Publishing Troubleshooting #
- Error "Package already exists": Package name is already in use, need to change name
- Error "Invalid version": Version format is incorrect (must be x.y.z)
- Error "Missing files": Missing required files (README, LICENSE, etc.)
Contributing #
Contributions and suggestions are welcome! Please create an issue or pull request on GitHub.
License #
MIT License - see the LICENSE file for details.
Author #
Created by [Your Name]