custom_roi_cells 0.3.8
custom_roi_cells: ^0.3.8 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
- β Load server selections - Apply any list of indices (e.g. from API) to highlight cells instantly
- β 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

Grid cells with selection capability
Selection Functionality

Tap and drag to select multiple cells
Control Buttons

Save, Delete, and Clear buttons
Selection Result

Display selected indices as array
Video Demo #

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 3.2: Loading Server/Remote Selections #
final CellsController controller = CellsController(
screenWidth: 800.0,
screenHeight: 400.0,
cellsRows: 20,
cellsColumns: 20,
);
final List<int> serverSelection = [0, 1, 2, 15, 16, 30, 45, 60];
CellsWidget(
controller: controller,
enableSelection: true,
initialSelectedCells: serverSelection, // (optional) preselect on first render
selectedCellColor: Colors.red.withValues(alpha: 0.6),
);
// When server pushes a new selection list:
void onServerSelectionReceived(List<int> indices) {
controller.setSelectedCells(indices); // highlights instantly
final currentSelection = controller.getSelectedIndices(); // read-only copy
print('Applied selection: $currentSelection');
}
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))initialSelectedCells(ListunselectedCellColor(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 listsetSelectedCells(List<int> indices): Replace the current selection with the provided list (useful for server/API data)selectCellRange(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]