Skip to content

Commit 149388f

Browse files
committed
Add animated icon support to menu example
Introduces AnimatedIconGenerator for pixel-perfect animated menu icons using Flutter's Canvas API. Updates README and UI to document and demonstrate new animated icon features, including spinner, pulse, blink, progress, wave, and rotating square animations, with high DPI support and real-time updates.
1 parent a01b254 commit 149388f

3 files changed

Lines changed: 637 additions & 76 deletions

File tree

examples/menu_example/README.md

Lines changed: 128 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ A comprehensive Flutter application demonstrating all menu functionality provide
3535
- ✅ Remove icons and restore normal display
3636
- ✅ Load icons from Flutter assets
3737
- ✅ Convert Material Icons to native menu icons
38+
-**Animated Icons** - Create pixel-perfect animated icons using canvas
39+
- Spinner animation (rotating loader)
40+
- Pulse animation (expanding/contracting circle)
41+
- Blink animation (on/off blinking dot)
42+
- Progress animation (filling progress bar)
43+
- Wave animation (moving wave pattern)
44+
- Rotating square animation
3845

3946
#### Tooltips
4047
- ✅ Set tooltips on menu items
@@ -109,38 +116,36 @@ The application is divided into two main sections:
109116
### Left Panel - Test Controls
110117
Contains multiple test sections organized in cards:
111118

112-
1. **Menu Creation & Display**
119+
1. **Context Menu Demo**
113120
- Shows current menu state (item count, checkbox/radio states)
121+
- Placement selector for choosing menu placement strategy
114122
- Context menu region for right-click testing
115123

116-
2. **Menu Item Operations**
117-
- Change dynamic label
118-
- Add new menu items
119-
- Insert items at specific positions
120-
- Insert separators at specific positions
124+
2. **Item Management**
125+
- Add Item: adds new menu item at the end
126+
- Insert at Pos 2: inserts item at specific position
127+
- Insert Separator: adds visual divider
128+
- Remove First / Remove at Pos 2 / Remove Last: removes items
121129

122-
3. **Icon Management**
123-
- Set icon from asset file
124-
- Set icon from Flutter Icon widget (Material Icons)
125-
- Remove icon from menu item
130+
3. **Item Properties**
131+
- Update Label: changes menu item label dynamically
132+
- Checkbox Mixed: sets checkbox to indeterminate state
133+
- Add Submenu Item: adds item to submenu
134+
- Detach Submenu: toggles submenu attachment
126135

127-
4. **Menu Item Removal**
128-
- Remove first menu item
129-
- Remove item at specific position
130-
- Remove last menu item
136+
4. **Icon Management**
137+
- Set Asset Icon: loads icon from asset file
138+
- Set Widget Icon: converts Flutter Icon to native icon
139+
- Remove Icon: removes icon from menu item
131140

132-
5. **Positioning Strategy Tests**
133-
- Absolute positioning at different coordinates
134-
- Cursor position testing
141+
5. **Positioning**
142+
- Pos (100,100) / Pos (300,200): absolute positioning at specific coordinates
143+
- At Cursor: displays menu at current mouse position
135144

136-
6. **Placement Tests**
137-
- Buttons for all 8 placement options
138-
- Visual feedback for each placement
139-
140-
7. **Edge Cases & Stress Tests**
141-
- Add multiple items at once
142-
- Rapid open/close testing
143-
- Screen edge boundary testing
145+
6. **Test Cases**
146+
- Add 10 Items: adds multiple items at once
147+
- Rapid Open/Close: tests stability with fast operations
148+
- Top-Left Edge / Bottom-Right Edge: tests boundary handling
144149

145150
### Right Panel - Event History
146151
- Real-time event log with timestamps
@@ -182,33 +187,45 @@ flutter run -d linux
182187
4. Hover over **Submenu** - should expand and log open event
183188
5. Click items in submenu - should log submenu item clicks
184189

185-
### Dynamic Operations Testing
186-
1. Click **Change Dynamic Label** - label should update with timestamp
187-
2. Click **Add New Menu Item** - item count should increase
188-
3. Click **Insert Item at Position 2** - new item appears at position 2
189-
4. Click **Insert Separator at Position 3** - separator appears at position 3
190+
### Item Properties Testing
191+
1. Click **Update Label** - label should update with timestamp
192+
2. Click **Checkbox Mixed** - checkbox item shows indeterminate state
193+
3. Click **Add Submenu Item** - adds a new item to the submenu
194+
4. Click **Detach Submenu** - toggles submenu attachment on/off
195+
196+
### Item Management Testing
197+
1. Click **Add Item** - item count should increase
198+
2. Click **Insert at Pos 2** - new item appears at position 2
199+
3. Click **Insert Separator** - separator appears at next position
200+
4. Click **Remove First** / **Remove at Pos 2** / **Remove Last** - removes items
190201

191202
### Icon Management Testing
192-
1. Click **Set Icon from Asset** - first menu item displays icon from asset file
203+
1. Click **Set Asset Icon** - first menu item displays icon from asset file
193204
2. Right-click the context menu region to verify icon appears
194-
3. Click **Set Icon from Widget** - first menu item displays a star icon (converted from Material Icons)
205+
3. Click **Set Widget Icon** - first menu item displays a star icon (converted from Material Icons)
195206
4. Right-click to verify the widget-based icon appears
196-
5. Click **Remove Icon from First Item** - icon should disappear
207+
5. Click **Remove Icon** - icon should disappear
197208
6. Right-click again to verify icon is removed
198209

199-
**Note:** The "Set Icon from Widget" feature demonstrates converting Flutter's Material Icons to native menu icons using base64 encoding.
210+
**Note:** The "Set Widget Icon" feature demonstrates converting Flutter's Material Icons to native menu icons using base64 encoding.
200211

201-
### Menu Item Removal Testing
202-
1. Click **Remove First Menu Item** - first item should be removed, count decreases
203-
2. Click **Remove Item at Position 2** - item at position 2 removed
204-
3. Click **Remove Last Menu Item** - last item removed
205-
4. Verify item count updates correctly after each removal
206-
5. Right-click to verify items are actually removed from menu
212+
### Animated Icons Testing
213+
1. Click **Spinner** - first menu item displays a rotating spinner animation
214+
2. Right-click to see the animation in action
215+
3. Click **Pulse** - switches to pulsing circle animation
216+
4. Click **Blink** - switches to blinking dot animation
217+
5. Click **Progress** - switches to filling progress bar animation
218+
6. Click **Wave** - switches to moving wave pattern animation
219+
7. Click **Rotate** - switches to rotating square animation
220+
8. Click **Stop** - stops any running animation
221+
9. Right-click to verify the icon updates in real-time
222+
223+
**Note:** The animated icons are generated pixel-by-pixel using Flutter's Canvas API and converted to native images. Each animation type provides different visual feedback suitable for loading states, notifications, or progress indicators.
207224

208225
### Positioning Testing
209-
1. Click **Absolute (100, 100)** - menu appears at top-left
210-
2. Click **Absolute (300, 200)** - menu appears at center-left
211-
3. Click **Cursor Position** - menu appears at mouse location
226+
1. Click **Pos (100,100)** - menu appears at top-left coordinates
227+
2. Click **Pos (300,200)** - menu appears at center-left coordinates
228+
3. Click **At Cursor** - menu appears at mouse location
212229

213230
### Placement Testing
214231
1. Click each placement button (topStart, bottomEnd, etc.)
@@ -217,8 +234,8 @@ flutter run -d linux
217234

218235
### Edge Cases Testing
219236
1. Click **Add 10 Items** - verify menu handles many items
220-
2. Click **Rapid Open/Close Test** - verify stability
221-
3. Click **Test Screen Edge** buttons - verify boundary handling
237+
2. Click **Rapid Open/Close** - verify stability with fast operations
238+
3. Click **Top-Left Edge** and **Bottom-Right Edge** buttons - verify boundary handling
222239
4. Open menu, switch window focus, return - verify menu state
223240

224241
### Event Verification
@@ -296,6 +313,52 @@ Future<Image?> _iconToImage(IconData iconData, {
296313

297314
This allows you to use any Flutter Icon (Material Icons, Cupertino Icons, custom icon fonts) as native menu icons.
298315

316+
### Using Animated Icons
317+
318+
Create pixel-perfect animated icons using the `AnimatedIconGenerator` class:
319+
320+
```dart
321+
import 'animated_icon_generator.dart';
322+
323+
// Create an animated icon generator with high DPI support
324+
final generator = AnimatedIconGenerator(
325+
size: 32, // Higher resolution for better quality
326+
foregroundColor: Colors.blue,
327+
);
328+
329+
// Create a menu item
330+
final menuItem = MenuItem('Loading...');
331+
332+
// Start a spinner animation
333+
generator.startSpinner(
334+
onFrame: (image) async {
335+
menuItem.icon = image;
336+
},
337+
);
338+
339+
// Switch to pulse animation
340+
generator.startPulse(
341+
onFrame: (image) async {
342+
menuItem.icon = image;
343+
},
344+
);
345+
346+
// Stop animation when done
347+
generator.stop();
348+
```
349+
350+
Available animation types:
351+
- `startSpinner()` - Rotating circular loader
352+
- `startPulse()` - Expanding/contracting circle
353+
- `startBlink()` - On/off blinking dot
354+
- `startProgress()` - Filling progress bar
355+
- `startWave()` - Moving wave pattern
356+
- `startRotatingSquare()` - Rotating square icon
357+
358+
The animations are generated using Flutter's Canvas API and converted to native images, providing smooth pixel-perfect animations suitable for menu icons.
359+
360+
**High DPI Support:** The `AnimatedIconGenerator` automatically scales icons for high DPI displays (Retina, HiDPI). Default size is 32x32 logical pixels, which produces crisp icons on all displays including Retina displays (64x64 or 96x96 physical pixels).
361+
299362
## Platform-Specific Notes
300363

301364
### macOS
@@ -343,24 +406,33 @@ main.dart
343406
├── _iconToImage() - Converts Flutter Icon widget to base64 image
344407
├── _setupContextMenu() - Creates main context menu
345408
├── _setupPositioningMenu() - Creates positioning test menu
346-
├── _setupPlacementMenu() - Creates placement test menu
347409
├── _addToHistory() - Logs events to history
410+
├── Item Management Methods
411+
│ ├── _addNewMenuItem() - Adds item to end
412+
│ ├── _insertMenuItemAtPosition() - Inserts item at specific position
413+
│ ├── _insertSeparatorAtPosition() - Inserts separator at position
414+
│ ├── _removeFirstMenuItem() - Removes first item
415+
│ ├── _removeMenuItemAtPosition() - Removes item at position
416+
│ └── _removeLastMenuItem() - Removes last item
417+
├── Item Properties Methods
418+
│ ├── _changeDynamicLabel() - Changes menu item label
419+
│ ├── _setCheckboxMixed() - Sets checkbox to mixed state
420+
│ ├── _addSubmenuItem() - Adds item to submenu
421+
│ └── _toggleSubmenu() - Toggles submenu attachment
348422
├── Icon Management Methods
349423
│ ├── _setIconOnFirstItem() - Sets icon from asset file
350424
│ ├── _setIconFromWidget() - Sets icon from Flutter Icon widget
351425
│ └── _removeIconFromFirstItem() - Removes icon from first item
352-
├── Menu Item Removal Methods
353-
│ ├── _removeFirstMenuItem() - Removes first item
354-
│ ├── _removeMenuItemAtPosition() - Removes item at position 2
355-
│ └── _removeLastMenuItem() - Removes last item
426+
├── Positioning Methods
427+
│ ├── _showMenuAtAbsolutePosition() - Shows menu at absolute coordinates
428+
│ └── _showMenuAtCursorPosition() - Shows menu at cursor position
356429
└── UI Sections
357-
├── Menu Creation & Display
358-
├── Menu Item Operations
430+
├── Context Menu Demo
431+
├── Item Management
432+
├── Item Properties
359433
├── Icon Management
360-
├── Menu Item Removal
361-
├── Positioning Strategy Tests
362-
├── Placement Tests
363-
├── Edge Cases & Stress Tests
434+
├── Positioning
435+
├── Test Cases
364436
└── Event History Panel
365437
```
366438

0 commit comments

Comments
 (0)