GenUI & Adaptive UIs
The next evolution of mobile interfaces combines Generative User Interfaces (GenUI)βwhere LLMs dynamically generate personalized UI layouts at runtimeβwith Adaptive UIs that seamlessly adjust across form factors (mobile, tablet, foldable, desktop, and web).
1. Generative UI (GenUI) Architecture
ββββββββββββββββββ 1. User Prompt ("Show my expense breakdown") ββββββββββββββββββ
β Mobile App UI β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββΊ β Gemini AI Modelβ
βββββββββ²βββββββββ βββββββββ¬βββββββββ
β β
β 4. Render Dynamic Widget Subtree β 2. Return JSON
β β Schema
βββββββββ΄βββββββββ βΌ
β Component β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Registry β 3. Validate & Map Schema -> Pre-tested Widgets
ββββββββββββββββββHow GenUI Operates
- User Intent Query: User prompts the system (e.g. βShow my monthly spending by category as a pie chart with a breakdown listβ).
- Structured LLM Output: The LLM (e.g. Gemini 1.5 Pro using
responseSchema) generates a structured JSON payload defining UI components. - Component Registry Mapping: The Flutter app validates the JSON and maps schema nodes to native, pre-tested Flutter widgets.
2. Secure Component Registry Pattern
Never execute arbitrary raw code strings generated by AI models! Instead, route JSON schemas through a strict, type-safe Component Registry:
typedef WidgetBuilderFunction = Widget Function(Map<String, dynamic> props);
class ComponentRegistry {
static final Map<String, WidgetBuilderFunction> _registry = {
'stat_card': (props) => StatCard(
title: props['title'] ?? '',
value: props['value'] ?? '',
icon: props['icon'],
),
'chart_pie': (props) => PieChartWidget(
dataPoints: List<double>.from(props['data'] ?? []),
),
'action_button': (props) => ElevatedButton(
onPressed: () => handleAction(props['action']),
child: Text(props['label'] ?? 'Action'),
),
};
static Widget render(Map<String, dynamic> json) {
final String type = json['type'] ?? '';
final builder = _registry[type];
if (builder == null) {
return const SizedBox.shrink(); // Fallback for unknown AI component types!
}
return builder(json['props'] ?? {});
}
}3. Multi-Form Factor Adaptive UIs
Flutter apps run across diverse screen sizes. Adaptive UIs adjust layout structures dynamically based on breakpoint constraints:
class AdaptiveScaffold extends StatelessWidget {
final Widget body;
final int selectedIndex;
const AdaptiveScaffold({
super.key,
required this.body,
required this.selectedIndex,
});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
// Desktop / Wide Screen: Show NavigationRail
if (constraints.maxWidth >= 800) {
return Scaffold(
body: Row(
children: [
NavigationRail(
selectedIndex: selectedIndex,
destinations: const [
NavigationRailDestination(icon: Icon(Icons.home), label: Text('Home')),
NavigationRailDestination(icon: Icon(Icons.person), label: Text('Profile')),
],
),
Expanded(child: body),
],
),
);
}
// Mobile Screen: Show BottomNavigationBar
return Scaffold(
body: body,
bottomNavigationBar: BottomNavigationBar(
currentIndex: selectedIndex,
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
],
),
);
},
);
}
}4. Trade-offs & Production Considerations
- LLM Latency & Skeleton Loaders: Generating structured JSON via LLMs takes 500ms to 2s. Always display shimmer skeleton loaders while streaming or awaiting GenUI schemas.
- Strict Schema Enforcement: Use Geminiβs
responseSchemaor OpenAPI JSON schemas to enforce valid LLM output structure, preventing missing field errors.