reis-mobile 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +24 -0
- package/.claude-plugin/plugin.json +12 -0
- package/CHANGELOG.md +103 -0
- package/LICENSE +21 -0
- package/README.md +631 -0
- package/THIRD_PARTY_NOTICES.md +105 -0
- package/agents/flutter-architect.md +92 -0
- package/agents/flutter-performance-engineer.md +103 -0
- package/agents/flutter-test-engineer.md +100 -0
- package/agents/lead-mobile.md +107 -0
- package/agents/mobile-code-reviewer.md +66 -0
- package/agents/mobile-staff-engineer.md +85 -0
- package/agents/plugin-native-expert.md +97 -0
- package/bin/reis-mobile.mjs +256 -0
- package/commands/debate.md +135 -0
- package/commands/doctor.md +23 -0
- package/commands/reis-mobile.md +50 -0
- package/commands/review.md +53 -0
- package/core/config/language.mjs +83 -0
- package/core/context/context-engine.mjs +113 -0
- package/core/detection/project-probe.mjs +104 -0
- package/core/detection/stack-detector.mjs +204 -0
- package/core/diagnostics/doctor.mjs +181 -0
- package/core/install/claude-plugin.mjs +76 -0
- package/core/paths.mjs +4 -0
- package/core/registry/frontmatter.mjs +81 -0
- package/core/registry/registry.mjs +140 -0
- package/core/router/intent-detector.mjs +75 -0
- package/core/router/intents.mjs +91 -0
- package/core/router/router.mjs +83 -0
- package/core/security/redact.mjs +24 -0
- package/package.json +35 -0
- package/skills/architecture-feature-first/SKILL.md +116 -0
- package/skills/bloc/SKILL.md +354 -0
- package/skills/code-review/SKILL.md +89 -0
- package/skills/dart-3-updates/SKILL.md +223 -0
- package/skills/dart-add-unit-test/SKILL.md +126 -0
- package/skills/dart-collect-coverage/SKILL.md +145 -0
- package/skills/dart-fix-runtime-errors/SKILL.md +170 -0
- package/skills/dart-generate-test-mocks/SKILL.md +159 -0
- package/skills/dart-migrate-to-checks-package/SKILL.md +532 -0
- package/skills/dart-resolve-package-conflicts/SKILL.md +120 -0
- package/skills/dart-run-static-analysis/SKILL.md +108 -0
- package/skills/dart-use-pattern-matching/SKILL.md +240 -0
- package/skills/dart-use-pattern-matching/examples/json_patterns.dart +85 -0
- package/skills/detect-mobile-stack/SKILL.md +33 -0
- package/skills/effective-dart/SKILL.md +187 -0
- package/skills/firebase-ai/SKILL.md +93 -0
- package/skills/firebase-analytics/SKILL.md +129 -0
- package/skills/firebase-app-check/SKILL.md +124 -0
- package/skills/firebase-auth/SKILL.md +224 -0
- package/skills/firebase-cloud-firestore/SKILL.md +165 -0
- package/skills/firebase-cloud-functions/SKILL.md +148 -0
- package/skills/firebase-crashlytics/SKILL.md +182 -0
- package/skills/firebase-data-connect/SKILL.md +80 -0
- package/skills/firebase-database/SKILL.md +224 -0
- package/skills/firebase-in-app-messaging/SKILL.md +111 -0
- package/skills/firebase-messaging/SKILL.md +201 -0
- package/skills/firebase-remote-config/SKILL.md +131 -0
- package/skills/firebase-storage/SKILL.md +158 -0
- package/skills/flutter-add-integration-test/SKILL.md +167 -0
- package/skills/flutter-add-widget-preview/SKILL.md +149 -0
- package/skills/flutter-add-widget-test/SKILL.md +158 -0
- package/skills/flutter-adding-home-screen-widgets/SKILL.md +205 -0
- package/skills/flutter-animating-apps/SKILL.md +185 -0
- package/skills/flutter-app-architecture/SKILL.md +80 -0
- package/skills/flutter-apply-architecture-best-practices/SKILL.md +166 -0
- package/skills/flutter-build-responsive-layout/SKILL.md +143 -0
- package/skills/flutter-building-forms/SKILL.md +125 -0
- package/skills/flutter-building-layouts/SKILL.md +131 -0
- package/skills/flutter-building-plugins/SKILL.md +209 -0
- package/skills/flutter-caching-data/SKILL.md +171 -0
- package/skills/flutter-change-notifier/SKILL.md +138 -0
- package/skills/flutter-embedding-native-views/SKILL.md +200 -0
- package/skills/flutter-errors/SKILL.md +126 -0
- package/skills/flutter-fix-layout-issues/SKILL.md +134 -0
- package/skills/flutter-handling-concurrency/SKILL.md +182 -0
- package/skills/flutter-implement-json-serialization/SKILL.md +157 -0
- package/skills/flutter-improving-accessibility/SKILL.md +113 -0
- package/skills/flutter-interoperating-with-native-apis/SKILL.md +130 -0
- package/skills/flutter-login-usecase/SKILL.md +38 -0
- package/skills/flutter-managing-state/SKILL.md +206 -0
- package/skills/flutter-project-audit/SKILL.md +66 -0
- package/skills/flutter-reducing-app-size/SKILL.md +103 -0
- package/skills/flutter-secure-token-store/SKILL.md +35 -0
- package/skills/flutter-setting-up-on-macos/SKILL.md +78 -0
- package/skills/flutter-setup-declarative-routing/SKILL.md +259 -0
- package/skills/flutter-setup-localization/SKILL.md +214 -0
- package/skills/flutter-theming-apps/SKILL.md +163 -0
- package/skills/flutter-use-http-package/SKILL.md +178 -0
- package/skills/flutter-widget-review/SKILL.md +54 -0
- package/skills/flutter-working-with-databases/SKILL.md +203 -0
- package/skills/flutterfire-configure/SKILL.md +143 -0
- package/skills/mobile-security-audit/SKILL.md +101 -0
- package/skills/mockito/SKILL.md +149 -0
- package/skills/mocktail/SKILL.md +122 -0
- package/skills/patrol-e2e-testing/SKILL.md +224 -0
- package/skills/provider/SKILL.md +139 -0
- package/skills/riverpod/SKILL.md +246 -0
- package/skills/testing/SKILL.md +50 -0
- package/stacks/android/stack.json +8 -0
- package/stacks/flutter/stack.json +8 -0
- package/stacks/ios/stack.json +8 -0
- package/stacks/kotlin-multiplatform/stack.json +8 -0
- package/stacks/react-native/stack.json +8 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: flutter-change-notifier
|
|
3
|
+
description: Implements state management with ChangeNotifier and Provider in Flutter. Use when setting up ChangeNotifier models, providing them to the widget tree, consuming state with Consumer or Provider.of, or optimizing rebuilds.
|
|
4
|
+
routing: manual
|
|
5
|
+
stacks: [flutter]
|
|
6
|
+
source: https://github.com/evanca/flutter-ai-rules
|
|
7
|
+
license: MIT
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Flutter ChangeNotifier Skill
|
|
11
|
+
|
|
12
|
+
This skill defines how to correctly use `ChangeNotifier` with the `provider` package for state management in Flutter.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 1. Model
|
|
17
|
+
|
|
18
|
+
Extend `ChangeNotifier` to manage state. Keep internal state **private** and expose **unmodifiable views**. Call `notifyListeners()` on every state change.
|
|
19
|
+
|
|
20
|
+
```dart
|
|
21
|
+
class CartModel extends ChangeNotifier {
|
|
22
|
+
final List<Item> _items = [];
|
|
23
|
+
|
|
24
|
+
UnmodifiableListView<Item> get items => UnmodifiableListView(_items);
|
|
25
|
+
|
|
26
|
+
void add(Item item) {
|
|
27
|
+
_items.add(item);
|
|
28
|
+
notifyListeners();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
void removeAll() {
|
|
32
|
+
_items.clear();
|
|
33
|
+
notifyListeners();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- Place shared state **above** the widgets that use it in the widget tree.
|
|
39
|
+
- Never directly mutate widgets or call methods on them to change state — rebuild widgets with new data instead.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 2. Providing the Model
|
|
44
|
+
|
|
45
|
+
```dart
|
|
46
|
+
ChangeNotifierProvider(
|
|
47
|
+
create: (context) => CartModel(),
|
|
48
|
+
child: MyApp(),
|
|
49
|
+
)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
- `ChangeNotifierProvider` **automatically disposes** of the model when it is no longer needed.
|
|
53
|
+
- Use `MultiProvider` when you need to provide multiple models:
|
|
54
|
+
|
|
55
|
+
```dart
|
|
56
|
+
MultiProvider(
|
|
57
|
+
providers: [
|
|
58
|
+
ChangeNotifierProvider(create: (_) => CartModel()),
|
|
59
|
+
ChangeNotifierProvider(create: (_) => UserModel()),
|
|
60
|
+
],
|
|
61
|
+
child: MyApp(),
|
|
62
|
+
)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 3. Consuming State
|
|
68
|
+
|
|
69
|
+
### Consumer
|
|
70
|
+
|
|
71
|
+
```dart
|
|
72
|
+
Consumer<CartModel>(
|
|
73
|
+
builder: (context, cart, child) => Stack(
|
|
74
|
+
children: [
|
|
75
|
+
if (child != null) child,
|
|
76
|
+
Text('Total price: ${cart.totalPrice}'),
|
|
77
|
+
],
|
|
78
|
+
),
|
|
79
|
+
child: const SomeExpensiveWidget(), // rebuilt only once
|
|
80
|
+
)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
- Always specify the generic type (`Consumer<CartModel>`, not `Consumer`).
|
|
84
|
+
- Use the `child` parameter to pass **widgets that don't depend on the model** — they are built once and reused.
|
|
85
|
+
- Place `Consumer` widgets **as deep in the widget tree as possible** to minimize the scope of rebuilds:
|
|
86
|
+
|
|
87
|
+
```dart
|
|
88
|
+
HumongousWidget(
|
|
89
|
+
child: AnotherMonstrousWidget(
|
|
90
|
+
child: Consumer<CartModel>(
|
|
91
|
+
builder: (context, cart, child) {
|
|
92
|
+
return Text('Total price: ${cart.totalPrice}');
|
|
93
|
+
},
|
|
94
|
+
),
|
|
95
|
+
),
|
|
96
|
+
)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Provider.of with listen: false
|
|
100
|
+
|
|
101
|
+
Use `Provider.of<T>(context, listen: false)` when you only need to **call methods** on the model, not react to state changes:
|
|
102
|
+
|
|
103
|
+
```dart
|
|
104
|
+
Provider.of<CartModel>(context, listen: false).removeAll();
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 4. Optimization Rules
|
|
110
|
+
|
|
111
|
+
- Do **not** wrap large widget subtrees in a `Consumer` if only a small part depends on the model.
|
|
112
|
+
- Avoid rebuilding widgets unnecessarily — structure your widget tree and provider usage carefully.
|
|
113
|
+
- Use `listen: false` in callbacks (e.g., `onPressed`) where you trigger actions but don't need rebuilds.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 5. Testing
|
|
118
|
+
|
|
119
|
+
Write **unit tests** for your `ChangeNotifier` models to verify state changes and notifications:
|
|
120
|
+
|
|
121
|
+
```dart
|
|
122
|
+
test('adding item updates total', () {
|
|
123
|
+
final cart = CartModel();
|
|
124
|
+
var notified = false;
|
|
125
|
+
cart.addListener(() => notified = true);
|
|
126
|
+
|
|
127
|
+
cart.add(Item('Book'));
|
|
128
|
+
|
|
129
|
+
expect(cart.items.length, 1);
|
|
130
|
+
expect(notified, isTrue);
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## References
|
|
137
|
+
|
|
138
|
+
- [Flutter Website GitHub Repository](https://github.com/flutter/website)
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: flutter-embedding-native-views
|
|
3
|
+
description: Embeds native Android, iOS, or macOS views into a Flutter app. Use when integrating complex native components like maps or web views.
|
|
4
|
+
metadata:
|
|
5
|
+
model: models/gemini-3.1-pro-preview
|
|
6
|
+
last_modified: Thu, 12 Mar 2026 22:20:28 GMT
|
|
7
|
+
routing: manual
|
|
8
|
+
stacks: [flutter]
|
|
9
|
+
source: https://github.com/flutter/skills
|
|
10
|
+
license: BSD-3-Clause
|
|
11
|
+
---
|
|
12
|
+
# Integrating Platform Views and Web Content
|
|
13
|
+
|
|
14
|
+
## Contents
|
|
15
|
+
- [Platform Views Architecture](#platform-views-architecture)
|
|
16
|
+
- [Web Embedding Architecture](#web-embedding-architecture)
|
|
17
|
+
- [Workflow: Implementing Android Platform Views](#workflow-implementing-android-platform-views)
|
|
18
|
+
- [Workflow: Implementing iOS Platform Views](#workflow-implementing-ios-platform-views)
|
|
19
|
+
- [Workflow: Embedding Flutter in Web Applications](#workflow-embedding-flutter-in-web-applications)
|
|
20
|
+
- [Examples](#examples)
|
|
21
|
+
|
|
22
|
+
## Platform Views Architecture
|
|
23
|
+
|
|
24
|
+
Platform Views allow embedding native views (Android, iOS, macOS) directly into a Flutter application, enabling the application of transforms, clips, and opacity from Dart.
|
|
25
|
+
|
|
26
|
+
### Android Implementations (API 23+)
|
|
27
|
+
Choose the appropriate implementation based on your performance and fidelity requirements:
|
|
28
|
+
* **Hybrid Composition:** Renders Flutter content into a texture and uses `SurfaceFlinger` to compose both.
|
|
29
|
+
* *Pros:* Best performance and fidelity for Android views.
|
|
30
|
+
* *Cons:* Lowers overall application FPS. Certain Flutter widget transformations will not work.
|
|
31
|
+
* **Texture Layer (Texture Layer Hybrid Composition):** Renders Platform Views into a texture. Flutter draws them via the texture and renders its own content directly into a Surface.
|
|
32
|
+
* *Pros:* Best performance for Flutter rendering. All transformations work correctly.
|
|
33
|
+
* *Cons:* Quick scrolling (e.g., WebViews) can be janky. `SurfaceView` is problematic (breaks accessibility). Text magnifiers break unless Flutter is rendered into a `TextureView`.
|
|
34
|
+
|
|
35
|
+
### iOS & macOS Implementations
|
|
36
|
+
* **iOS:** Uses Hybrid Composition exclusively. The native `UIView` is appended to the view hierarchy.
|
|
37
|
+
* *Limitations:* `ShaderMask` and `ColorFiltered` widgets are not supported. `BackdropFilter` has composition limitations.
|
|
38
|
+
* **macOS:** Uses Hybrid Composition (`NSView`).
|
|
39
|
+
* *Limitations:* Not fully functional in current releases (e.g., gesture support is unavailable).
|
|
40
|
+
|
|
41
|
+
### Performance Mitigation
|
|
42
|
+
Mitigate performance drops during complex Dart animations by rendering a screenshot of the native view as a placeholder texture while the animation runs.
|
|
43
|
+
|
|
44
|
+
## Web Embedding Architecture
|
|
45
|
+
|
|
46
|
+
Embed Flutter into existing web applications (Vanilla JS, React, Angular, etc.) using either Full Page mode or Embedded (Multi-view) mode.
|
|
47
|
+
|
|
48
|
+
* **Full Page Mode:** Flutter takes over the entire browser window. Use an `iframe` if you need to constrain the Flutter app without modifying the Flutter bootstrap process.
|
|
49
|
+
* **Embedded Mode (Multi-view):** Render Flutter into specific HTML elements (`div`s). Requires `multiViewEnabled: true` during engine initialization.
|
|
50
|
+
* Manage views from JavaScript using `app.addView()` and `app.removeView()`.
|
|
51
|
+
* In Dart, replace `runApp` with `runWidget`.
|
|
52
|
+
* Manage the dynamic list of views using `WidgetsBinding.instance.platformDispatcher.views` and render them using `ViewCollection` and `View` widgets.
|
|
53
|
+
|
|
54
|
+
## Workflow: Implementing Android Platform Views
|
|
55
|
+
|
|
56
|
+
Follow this sequential workflow to implement a Platform View on Android.
|
|
57
|
+
|
|
58
|
+
**Task Progress:**
|
|
59
|
+
- [ ] 1. Determine the composition mode (Hybrid vs. Texture Layer).
|
|
60
|
+
- [ ] 2. Implement the Dart widget.
|
|
61
|
+
- [ ] 3. Implement the native Android View and Factory.
|
|
62
|
+
- [ ] 4. Register the Platform View in the Android host.
|
|
63
|
+
- [ ] 5. Run validator -> review rendering -> fix manual invalidation issues.
|
|
64
|
+
|
|
65
|
+
### 1. Dart Implementation
|
|
66
|
+
If using **Hybrid Composition**, use `PlatformViewLink`, `AndroidViewSurface`, and `PlatformViewsService.initSurfaceAndroidView`.
|
|
67
|
+
If using **Texture Layer**, use the `AndroidView` widget.
|
|
68
|
+
|
|
69
|
+
### 2. Native Implementation
|
|
70
|
+
Create a class implementing `io.flutter.plugin.platform.PlatformView` that returns your native `android.view.View`.
|
|
71
|
+
Create a factory extending `PlatformViewFactory` to instantiate your view.
|
|
72
|
+
|
|
73
|
+
### 3. Registration
|
|
74
|
+
Register the factory in your `MainActivity.kt` (or plugin) using `flutterEngine.platformViewsController.registry.registerViewFactory`.
|
|
75
|
+
|
|
76
|
+
*Note: If your native view uses `SurfaceView` or `SurfaceTexture`, manually call `invalidate` on the View or its parent when content changes, as they do not invalidate themselves automatically.*
|
|
77
|
+
|
|
78
|
+
## Workflow: Implementing iOS Platform Views
|
|
79
|
+
|
|
80
|
+
Follow this sequential workflow to implement a Platform View on iOS.
|
|
81
|
+
|
|
82
|
+
**Task Progress:**
|
|
83
|
+
- [ ] 1. Implement the Dart widget using `UiKitView`.
|
|
84
|
+
- [ ] 2. Implement the native iOS View (`FlutterPlatformView`) and Factory (`FlutterPlatformViewFactory`).
|
|
85
|
+
- [ ] 3. Register the Platform View in `AppDelegate.swift` or the plugin registrar.
|
|
86
|
+
- [ ] 4. Run validator -> review composition limitations -> fix unsupported filters.
|
|
87
|
+
|
|
88
|
+
## Workflow: Embedding Flutter in Web Applications
|
|
89
|
+
|
|
90
|
+
Follow this sequential workflow to embed Flutter into an existing web DOM.
|
|
91
|
+
|
|
92
|
+
**Task Progress:**
|
|
93
|
+
- [ ] 1. Update `flutter_bootstrap.js` to enable multi-view.
|
|
94
|
+
- [ ] 2. Update `main.dart` to use `runWidget` and `ViewCollection`.
|
|
95
|
+
- [ ] 3. Implement JavaScript logic to add/remove host elements.
|
|
96
|
+
- [ ] 4. Run validator -> review view constraints -> fix CSS conflicts.
|
|
97
|
+
|
|
98
|
+
### 1. JavaScript Configuration
|
|
99
|
+
In `flutter_bootstrap.js`, initialize the engine with `multiViewEnabled: true`.
|
|
100
|
+
Use the returned `app` object to add views: `app.addView({ hostElement: document.getElementById('my-div') })`.
|
|
101
|
+
|
|
102
|
+
### 2. Dart Configuration
|
|
103
|
+
Replace `runApp()` with `runWidget()`.
|
|
104
|
+
Create a root widget that listens to `WidgetsBindingObserver.didChangeMetrics`.
|
|
105
|
+
Map over `WidgetsBinding.instance.platformDispatcher.views` to create a `View` widget for each attached `FlutterView`, and wrap them all in a `ViewCollection`.
|
|
106
|
+
|
|
107
|
+
## Examples
|
|
108
|
+
|
|
109
|
+
### Example: Android Texture Layer (Dart)
|
|
110
|
+
```dart
|
|
111
|
+
import 'package:flutter/material.dart';
|
|
112
|
+
import 'package:flutter/services.dart';
|
|
113
|
+
|
|
114
|
+
class NativeAndroidView extends StatelessWidget {
|
|
115
|
+
@override
|
|
116
|
+
Widget build(BuildContext context) {
|
|
117
|
+
const String viewType = 'my_native_view';
|
|
118
|
+
final Map<String, dynamic> creationParams = <String, dynamic>{};
|
|
119
|
+
|
|
120
|
+
return AndroidView(
|
|
121
|
+
viewType: viewType,
|
|
122
|
+
layoutDirection: TextDirection.ltr,
|
|
123
|
+
creationParams: creationParams,
|
|
124
|
+
creationParamsCodec: const StandardMessageCodec(),
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Example: Web Multi-View Initialization (JavaScript)
|
|
131
|
+
```javascript
|
|
132
|
+
_flutter.loader.load({
|
|
133
|
+
onEntrypointLoaded: async function(engineInitializer) {
|
|
134
|
+
let engine = await engineInitializer.initializeEngine({
|
|
135
|
+
multiViewEnabled: true,
|
|
136
|
+
});
|
|
137
|
+
let app = await engine.runApp();
|
|
138
|
+
|
|
139
|
+
// Add a view to a specific DOM element
|
|
140
|
+
let viewId = app.addView({
|
|
141
|
+
hostElement: document.querySelector('#flutter-host-container'),
|
|
142
|
+
initialData: { customData: 'Hello from JS' }
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Example: Web Multi-View Root Widget (Dart)
|
|
149
|
+
```dart
|
|
150
|
+
import 'dart:ui' show FlutterView;
|
|
151
|
+
import 'package:flutter/widgets.dart';
|
|
152
|
+
|
|
153
|
+
void main() {
|
|
154
|
+
runWidget(MultiViewApp(viewBuilder: (context) => const MyEmbeddedWidget()));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
class MultiViewApp extends StatefulWidget {
|
|
158
|
+
final WidgetBuilder viewBuilder;
|
|
159
|
+
const MultiViewApp({super.key, required this.viewBuilder});
|
|
160
|
+
|
|
161
|
+
@override
|
|
162
|
+
State<MultiViewApp> createState() => _MultiViewAppState();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
class _MultiViewAppState extends State<MultiViewApp> with WidgetsBindingObserver {
|
|
166
|
+
Map<Object, Widget> _views = {};
|
|
167
|
+
|
|
168
|
+
@override
|
|
169
|
+
void initState() {
|
|
170
|
+
super.initState();
|
|
171
|
+
WidgetsBinding.instance.addObserver(this);
|
|
172
|
+
_updateViews();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
@override
|
|
176
|
+
void didChangeMetrics() => _updateViews();
|
|
177
|
+
|
|
178
|
+
void _updateViews() {
|
|
179
|
+
final newViews = <Object, Widget>{};
|
|
180
|
+
for (final FlutterView view in WidgetsBinding.instance.platformDispatcher.views) {
|
|
181
|
+
newViews[view.viewId] = _views[view.viewId] ?? View(
|
|
182
|
+
view: view,
|
|
183
|
+
child: Builder(builder: widget.viewBuilder),
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
setState(() => _views = newViews);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
@override
|
|
190
|
+
void dispose() {
|
|
191
|
+
WidgetsBinding.instance.removeObserver(this);
|
|
192
|
+
super.dispose();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
@override
|
|
196
|
+
Widget build(BuildContext context) {
|
|
197
|
+
return ViewCollection(views: _views.values.toList(growable: false));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: flutter-errors
|
|
3
|
+
description: Diagnoses and fixes common Flutter errors. Use when encountering layout errors (RenderFlex overflow, unbounded constraints, RenderBox not laid out), scroll errors, or setState-during-build errors.
|
|
4
|
+
intents: [debug]
|
|
5
|
+
stacks: [flutter]
|
|
6
|
+
source: https://github.com/evanca/flutter-ai-rules
|
|
7
|
+
license: MIT
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Flutter Errors Skill
|
|
11
|
+
|
|
12
|
+
This skill provides solutions for the most common Flutter runtime and layout errors.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## RenderFlex Overflowed
|
|
17
|
+
|
|
18
|
+
**Error:** `A RenderFlex overflowed by X pixels on the right/bottom.`
|
|
19
|
+
|
|
20
|
+
**Cause:** A `Row` or `Column` contains children that are wider/taller than the available space.
|
|
21
|
+
|
|
22
|
+
**Fix:** Wrap the overflowing child in `Flexible` or `Expanded`, or constrain its size:
|
|
23
|
+
|
|
24
|
+
```dart
|
|
25
|
+
Row(
|
|
26
|
+
children: [
|
|
27
|
+
Expanded(child: Text('Long text that might overflow')),
|
|
28
|
+
Icon(Icons.info),
|
|
29
|
+
],
|
|
30
|
+
)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Vertical Viewport Given Unbounded Height
|
|
36
|
+
|
|
37
|
+
**Error:** `Vertical viewport was given unbounded height.`
|
|
38
|
+
|
|
39
|
+
**Cause:** A `ListView` (or other scrollable) is placed inside a `Column` without a bounded height.
|
|
40
|
+
|
|
41
|
+
**Fix:** Wrap the `ListView` in `Expanded` or give it a fixed height with `SizedBox`:
|
|
42
|
+
|
|
43
|
+
```dart
|
|
44
|
+
Column(
|
|
45
|
+
children: [
|
|
46
|
+
Text('Header'),
|
|
47
|
+
Expanded(
|
|
48
|
+
child: ListView(children: [...]),
|
|
49
|
+
),
|
|
50
|
+
],
|
|
51
|
+
)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## InputDecorator Cannot Have Unbounded Width
|
|
57
|
+
|
|
58
|
+
**Error:** `An InputDecorator...cannot have an unbounded width.`
|
|
59
|
+
|
|
60
|
+
**Cause:** A `TextField` or similar widget is placed in a context without width constraints.
|
|
61
|
+
|
|
62
|
+
**Fix:** Wrap it in `Expanded`, `SizedBox`, or any parent that provides width constraints:
|
|
63
|
+
|
|
64
|
+
```dart
|
|
65
|
+
Row(
|
|
66
|
+
children: [
|
|
67
|
+
Expanded(child: TextField()),
|
|
68
|
+
],
|
|
69
|
+
)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## setState Called During Build
|
|
75
|
+
|
|
76
|
+
**Error:** `setState() or markNeedsBuild() called during build.`
|
|
77
|
+
|
|
78
|
+
**Cause:** `setState` or `showDialog` is called directly inside the `build` method.
|
|
79
|
+
|
|
80
|
+
**Fix:** Trigger state changes in response to user actions, or defer to after the frame using `addPostFrameCallback`:
|
|
81
|
+
|
|
82
|
+
```dart
|
|
83
|
+
@override
|
|
84
|
+
void initState() {
|
|
85
|
+
super.initState();
|
|
86
|
+
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
87
|
+
// Safe to call setState or showDialog here
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## ScrollController Attached to Multiple Scroll Views
|
|
95
|
+
|
|
96
|
+
**Error:** `The ScrollController is attached to multiple scroll views.`
|
|
97
|
+
|
|
98
|
+
**Cause:** A single `ScrollController` instance is shared across more than one scrollable widget simultaneously.
|
|
99
|
+
|
|
100
|
+
**Fix:** Ensure each scrollable widget has its own dedicated `ScrollController` instance.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## RenderBox Was Not Laid Out
|
|
105
|
+
|
|
106
|
+
**Error:** `RenderBox was not laid out: ...`
|
|
107
|
+
|
|
108
|
+
**Cause:** A widget is missing or has unbounded constraints — commonly `ListView` or `Column` without proper size constraints.
|
|
109
|
+
|
|
110
|
+
**Fix:** Review your widget tree for missing constraints. Common patterns:
|
|
111
|
+
|
|
112
|
+
- Wrap `ListView` in `Expanded` inside a `Column`.
|
|
113
|
+
- Give widgets an explicit `width` or `height` via `SizedBox` or `ConstrainedBox`.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Debugging Layout Issues
|
|
118
|
+
|
|
119
|
+
- Use the **Flutter Inspector** (in DevTools) to visualize widget constraints.
|
|
120
|
+
- Enable **"Show guidelines"** to see layout boundaries.
|
|
121
|
+
- Add `debugPaintSizeEnabled = true;` temporarily in your `main()` to paint layout bounds.
|
|
122
|
+
- Refer to the [Flutter constraints documentation](https://docs.flutter.dev/ui/layout/constraints) for a deeper understanding of how constraints propagate.
|
|
123
|
+
|
|
124
|
+
## References
|
|
125
|
+
|
|
126
|
+
- [Flutter Website GitHub Repository](https://github.com/flutter/website)
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: flutter-fix-layout-issues
|
|
3
|
+
description: Fixes Flutter layout errors (overflows, unbounded constraints) using Dart and Flutter MCP tools. Use when addressing "RenderFlex overflowed", "Vertical viewport was given unbounded height", or similar layout issues.
|
|
4
|
+
metadata:
|
|
5
|
+
model: models/gemini-3.1-pro-preview
|
|
6
|
+
last_modified: Tue, 21 Apr 2026 19:45:59 GMT
|
|
7
|
+
intents: [debug]
|
|
8
|
+
stacks: [flutter]
|
|
9
|
+
source: https://github.com/flutter/skills
|
|
10
|
+
license: BSD-3-Clause
|
|
11
|
+
---
|
|
12
|
+
# Resolving Flutter Layout Errors
|
|
13
|
+
|
|
14
|
+
## Contents
|
|
15
|
+
- [Constraint Violation Diagnostics](#constraint-violation-diagnostics)
|
|
16
|
+
- [Layout Error Resolution Workflow](#layout-error-resolution-workflow)
|
|
17
|
+
- [Examples](#examples)
|
|
18
|
+
|
|
19
|
+
## Constraint Violation Diagnostics
|
|
20
|
+
|
|
21
|
+
Flutter layout operates on a strict rule: **Constraints go down. Sizes go up. Parent sets position.** Layout errors occur when this negotiation fails, typically due to unbounded constraints or unconstrained children.
|
|
22
|
+
|
|
23
|
+
Diagnose layout failures using the following error signatures:
|
|
24
|
+
|
|
25
|
+
* **"Vertical viewport was given unbounded height"**: Triggered when a scrollable widget (`ListView`, `GridView`) is placed inside an unconstrained vertical parent (`Column`). The parent provides infinite height, and the child attempts to expand infinitely.
|
|
26
|
+
* **"An InputDecorator...cannot have an unbounded width"**: Triggered when a `TextField` or `TextFormField` is placed inside an unconstrained horizontal parent (`Row`). The text field attempts to determine its width based on infinite available space.
|
|
27
|
+
* **"RenderFlex overflowed"**: Triggered when a child of a `Row` or `Column` requests a size larger than the parent's allocated constraints. Visually indicated by yellow and black warning stripes.
|
|
28
|
+
* **"Incorrect use of ParentData widget"**: Triggered when a `ParentDataWidget` is not a direct descendant of its required ancestor. (e.g., `Expanded` outside a `Flex`, `Positioned` outside a `Stack`).
|
|
29
|
+
* **"RenderBox was not laid out"**: A cascading side-effect error. Ignore this and look further up the stack trace for the primary constraint violation (usually an unbounded height/width error).
|
|
30
|
+
|
|
31
|
+
## Layout Error Resolution Workflow
|
|
32
|
+
|
|
33
|
+
Copy and use this checklist to systematically resolve layout constraint violations.
|
|
34
|
+
|
|
35
|
+
### Task Progress
|
|
36
|
+
- [ ] Run the application in debug mode to capture the exact layout exception in the console.
|
|
37
|
+
- [ ] Identify the primary error message (ignore cascading "RenderBox was not laid out" errors).
|
|
38
|
+
- [ ] Apply the conditional fix based on the specific error type:
|
|
39
|
+
- **If "Vertical viewport was given unbounded height"**: Wrap the scrollable child (`ListView`, `GridView`) in an `Expanded` widget to consume remaining space, or wrap it in a `SizedBox` to provide an absolute height constraint.
|
|
40
|
+
- **If "An InputDecorator...cannot have an unbounded width"**: Wrap the `TextField` or `TextFormField` in an `Expanded` or `Flexible` widget.
|
|
41
|
+
- **If "RenderFlex overflowed"**: Constrain the overflowing child by wrapping it in an `Expanded` widget (to force it to fit) or a `Flexible` widget (to allow it to be smaller than the allocated space).
|
|
42
|
+
- **If "Incorrect use of ParentData widget"**: Move the `ParentDataWidget` to be a direct child of its required parent. Ensure `Expanded`/`Flexible` are direct children of `Row`/`Column`/`Flex`. Ensure `Positioned` is a direct child of `Stack`.
|
|
43
|
+
- [ ] Execute Flutter hot reload.
|
|
44
|
+
- [ ] Run validator -> review errors -> fix: Inspect the UI to verify the red/grey error screen or yellow/black overflow stripes are resolved. If new layout errors appear, repeat the workflow.
|
|
45
|
+
|
|
46
|
+
## Examples
|
|
47
|
+
|
|
48
|
+
### Fixing Unbounded Height (ListView in Column)
|
|
49
|
+
|
|
50
|
+
**Input (Error State):**
|
|
51
|
+
```dart
|
|
52
|
+
// Throws "Vertical viewport was given unbounded height"
|
|
53
|
+
Column(
|
|
54
|
+
children: <Widget>[
|
|
55
|
+
const Text('Header'),
|
|
56
|
+
ListView(
|
|
57
|
+
children: const <Widget>[
|
|
58
|
+
ListTile(title: Text('Item 1')),
|
|
59
|
+
ListTile(title: Text('Item 2')),
|
|
60
|
+
],
|
|
61
|
+
),
|
|
62
|
+
],
|
|
63
|
+
)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Output (Resolved State):**
|
|
67
|
+
```dart
|
|
68
|
+
// Wrap ListView in Expanded to constrain its height to the remaining Column space
|
|
69
|
+
Column(
|
|
70
|
+
children: <Widget>[
|
|
71
|
+
const Text('Header'),
|
|
72
|
+
Expanded(
|
|
73
|
+
child: ListView(
|
|
74
|
+
children: const <Widget>[
|
|
75
|
+
ListTile(title: Text('Item 1')),
|
|
76
|
+
ListTile(title: Text('Item 2')),
|
|
77
|
+
],
|
|
78
|
+
),
|
|
79
|
+
),
|
|
80
|
+
],
|
|
81
|
+
)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Fixing Unbounded Width (TextField in Row)
|
|
85
|
+
|
|
86
|
+
**Input (Error State):**
|
|
87
|
+
```dart
|
|
88
|
+
// Throws "An InputDecorator...cannot have an unbounded width"
|
|
89
|
+
Row(
|
|
90
|
+
children: [
|
|
91
|
+
const Icon(Icons.search),
|
|
92
|
+
TextField(),
|
|
93
|
+
],
|
|
94
|
+
)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Output (Resolved State):**
|
|
98
|
+
```dart
|
|
99
|
+
// Wrap TextField in Expanded to constrain its width to the remaining Row space
|
|
100
|
+
Row(
|
|
101
|
+
children: [
|
|
102
|
+
const Icon(Icons.search),
|
|
103
|
+
Expanded(
|
|
104
|
+
child: TextField(),
|
|
105
|
+
),
|
|
106
|
+
],
|
|
107
|
+
)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Fixing RenderFlex Overflow
|
|
111
|
+
|
|
112
|
+
**Input (Error State):**
|
|
113
|
+
```dart
|
|
114
|
+
// Throws "A RenderFlex overflowed by X pixels on the right"
|
|
115
|
+
Row(
|
|
116
|
+
children: [
|
|
117
|
+
const Icon(Icons.info),
|
|
118
|
+
const Text('This is a very long text string that will definitely overflow the available screen width and cause a RenderFlex error.'),
|
|
119
|
+
],
|
|
120
|
+
)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Output (Resolved State):**
|
|
124
|
+
```dart
|
|
125
|
+
// Wrap the Text widget in Expanded to force it to wrap within the available constraints
|
|
126
|
+
Row(
|
|
127
|
+
children: [
|
|
128
|
+
const Icon(Icons.info),
|
|
129
|
+
Expanded(
|
|
130
|
+
child: const Text('This is a very long text string that will definitely overflow the available screen width and cause a RenderFlex error.'),
|
|
131
|
+
),
|
|
132
|
+
],
|
|
133
|
+
)
|
|
134
|
+
```
|