Advanced Patterns
Explore advanced techniques for building complex, production-ready UIs with Primitive UI components.
Nested Layouts
Complex Form Layout
Complex Form Layout DemoOpen in new tab ↗
class ProfileForm extends StatefulWidget {
@override
State<ProfileForm> createState() => _ProfileFormState();
}
class _ProfileFormState extends State<ProfileForm> {
bool _emailNotifications = true;
bool _pushNotifications = false;
bool _smsNotifications = false;
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(16),
child: VStack(
spacing: 24.0,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Header
Text(
'Profile Settings',
style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
),
// Personal Info Section
_buildSection(
title: 'Personal Information',
children: [
TextField(
decoration: InputDecoration(labelText: 'Name'),
),
SizedBox(height: 16),
TextField(
decoration: InputDecoration(labelText: 'Email'),
),
],
),
// Notification Preferences
_buildSection(
title: 'Notifications',
children: [
_buildToggleRow(
'Email Notifications',
_emailNotifications,
(v) => setState(() => _emailNotifications = v),
),
_buildToggleRow(
'Push Notifications',
_pushNotifications,
(v) => setState(() => _pushNotifications = v),
),
_buildToggleRow(
'SMS Notifications',
_smsNotifications,
(v) => setState(() => _smsNotifications = v),
),
],
),
// Actions
ElevatedButton(
onPressed: _saveSettings,
style: ElevatedButton.styleFrom(
minimumSize: Size(double.infinity, 48),
),
child: Text('Save Changes'),
),
],
),
),
);
}
Widget _buildSection({
required String title,
required List<Widget> children,
}) {
return PrimitiveCard(
elevation: 2.0,
child: VStack(
spacing: 16.0,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
title,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
...children,
],
),
);
}
Widget _buildToggleRow(
String label,
bool value,
ValueChanged<bool> onChanged,
) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label),
PrimitiveToggleSwitch(value: value, onChanged: onChanged),
],
);
}
void _saveSettings() {
// Save settings logic
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Settings saved!')),
);
}
}Dynamic Content
Conditional Rendering
Conditional Rendering DemoOpen in new tab ↗
class DashboardView extends StatefulWidget {
@override
State<DashboardView> createState() => _DashboardViewState();
}
class _DashboardViewState extends State<DashboardView> {
bool _isLoading = false;
bool _hasError = false;
List<String> _items = ['Item 1', 'Item 2', 'Item 3'];
@override
Widget build(BuildContext context) {
return VStack(
spacing: 16.0,
children: [
// Conditionally show loading state
if (_isLoading)
PrimitiveCard(
child: Center(
child: CircularProgressIndicator(),
),
),
// Conditionally show error
if (_hasError)
PrimitiveCard(
color: Color(0xFFFFEBEE),
child: VStack(
spacing: 8.0,
children: [
Icon(Icons.error, color: Colors.red),
Text('Error loading data'),
ElevatedButton(
onPressed: _retry,
child: Text('Retry'),
),
],
),
),
// Show items if not loading and no error
if (!_isLoading && !_hasError)
..._items.map((item) => PrimitiveCard(
child: Text(item),
)),
// Show empty state
if (!_isLoading && !_hasError && _items.isEmpty)
PrimitiveCard(
child: VStack(
spacing: 12.0,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(Icons.inbox, size: 64, color: Colors.grey),
Text('No items yet'),
],
),
),
],
);
}
void _retry() {
setState(() {
_hasError = false;
_isLoading = true;
});
// Simulate loading
Future.delayed(Duration(seconds: 2), () {
setState(() => _isLoading = false);
});
}
}Advanced Layering
Image Card with Overlay
Image Card with Overlay DemoOpen in new tab ↗
Widget buildImageCard({
required String imageUrl,
required String title,
required String subtitle,
VoidCallback? onTap,
}) {
return GestureDetector(
onTap: onTap,
child: PrimitiveCard(
padding: EdgeInsets.zero,
child: ZStack(
fit: ZStackFit.expand,
children: [
// Background image
ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.network(
imageUrl,
fit: BoxFit.cover,
height: 200,
),
),
// Gradient overlay
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.transparent,
Colors.black.withOpacity(0.7),
],
),
),
),
// Text content
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Padding(
padding: EdgeInsets.all(16),
child: VStack(
spacing: 4.0,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
Text(
subtitle,
style: TextStyle(
color: Colors.white70,
fontSize: 14,
),
),
],
),
),
),
],
),
),
);
}Multi-Layer Status Indicator
Multi-Layer Status Indicator DemoOpen in new tab ↗
Widget buildStatusAvatar({
required String initials,
required bool isOnline,
required bool hasNotification,
Color backgroundColor = Colors.blue,
}) {
return ZStack(
children: [
// Main avatar
Container(
width: 64,
height: 64,
decoration: BoxDecoration(
color: backgroundColor,
shape: BoxShape.circle,
),
child: Center(q
child: Text(
initials,
style: TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
),
),
// Online status indicator
if (isOnline)
Positioned(
right: 0,
bottom: 0,
child: Container(
width: 18,
height: 18,
decoration: BoxDecoration(
color: Colors.green,
shape: BoxShape.circle,
border: Border.all(color: Colors.white, width: 2),
),
),
),
// Notification badge
if (hasNotification)
Positioned(
left: 0,
top: 0,
child: Container(
width: 20,
height: 20,
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
border: Border.all(color: Colors.white, width: 2),
),
child: Center(
child: Text(
'!',
style: TextStyle(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
),
),
),
],
);
}State Management Integration
With Provider
Provider State Management DemoOpen in new tab ↗
// Model
class Settings {
bool darkMode;
bool notifications;
Settings({
this.darkMode = false,
this.notifications = true,
});
}
class SettingsNotifier extends ChangeNotifier {
Settings _settings = Settings();
Settings get settings => _settings;
void toggleDarkMode() {
_settings.darkMode = !_settings.darkMode;
notifyListeners();
}
void toggleNotifications() {
_settings.notifications = !_settings.notifications;
notifyListeners();
}
}
// UI
class SettingsView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer<SettingsNotifier>(
builder: (context, notifier, child) {
return VStack(
spacing: 16.0,
children: [
PrimitiveCard(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Dark Mode'),
PrimitiveToggleSwitch(
value: notifier.settings.darkMode,
onChanged: (_) => notifier.toggleDarkMode(),
),
],
),
),
PrimitiveCard(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Notifications'),
PrimitiveToggleSwitch(
value: notifier.settings.notifications,
onChanged: (_) => notifier.toggleNotifications(),
),
],
),
),
],
);
},
);
}
}Responsive Layouts
Adaptive Grid
Adaptive Grid DemoOpen in new tab ↗
class ResponsiveGrid extends StatelessWidget {
final List<Widget> children;
const ResponsiveGrid({required this.children});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
// Determine column count based on width
int columns = 1;
if (constraints.maxWidth > 600) columns = 2;
if (constraints.maxWidth > 900) columns = 3;
return GridView.count(
crossAxisCount: columns,
padding: EdgeInsets.all(16),
mainAxisSpacing: 16,
crossAxisSpacing: 16,
children: children,
);
},
);
}
}
// Usage
ResponsiveGrid(
children: List.generate(
12,
(index) => PrimitiveCard(
child: Center(child: Text('Card ${index + 1}')),
),
),
)Custom Themes
Themed Components
Themed Components DemoOpen in new tab ↗
class AppTheme {
static const Color primaryColor = Color(0xFF2196F3);
static const Color surfaceColor = Color(0xFFFFFFFF);
static const Color errorColor = Color(0xFFF44336);
static PrimitiveCard buildPrimaryCard({required Widget child}) {
return PrimitiveCard(
color: primaryColor,
elevation: 4.0,
borderRadius: 12.0,
child: child,
);
}
static PrimitiveCard buildSurfaceCard({required Widget child}) {
return PrimitiveCard(
color: surfaceColor,
elevation: 2.0,
borderRadius: 8.0,
child: child,
);
}
static PrimitiveToggleSwitch buildPrimaryToggle({
required bool value,
required ValueChanged<bool> onChanged,
}) {
return PrimitiveToggleSwitch(
value: value,
onChanged: onChanged,
activeColor: primaryColor,
inactiveColor: Colors.grey[400]!,
);
}
}
// Usage
AppTheme.buildPrimaryCard(
child: Text('Themed Card'),
)Performance Optimization
Efficient Lists with Keys
Optimized List DemoOpen in new tab ↗
class OptimizedList extends StatefulWidget {
@override
State<OptimizedList> createState() => _OptimizedListState();
}
class _OptimizedListState extends State<OptimizedList> {
List<String> _items = List.generate(100, (i) => 'Item $i');
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: _items.length,
padding: EdgeInsets.all(16),
itemBuilder: (context, index) {
return Padding(
key: ValueKey(_items[index]), // Important for performance
padding: EdgeInsets.only(bottom: 16),
child: PrimitiveCard(
child: Text(_items[index]),
),
);
},
);
}
}Graceful Error Display
Graceful Error Display DemoOpen in new tab ↗
class SafeCard extends StatelessWidget {
final Widget? child;
final String? errorMessage;
const SafeCard({
this.child,
this.errorMessage,
});
@override
Widget build(BuildContext context) {
if (errorMessage != null) {
return PrimitiveCard(
color: Color(0xFFFFEBEE),
child: VStack(
spacing: 8.0,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(Icons.error_outline, color: Colors.red, size: 32),
Text(
'Error',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.red,
),
),
Text(
errorMessage!,
style: TextStyle(color: Colors.red[700]),
textAlign: TextAlign.center,
),
],
),
);
}
return PrimitiveCard(child: child ?? SizedBox.shrink());
}
}Real-World Example
Complete Dashboard
Complete Dashboard DemoOpen in new tab ↗
class Dashboard extends StatefulWidget {
@override
State<Dashboard> createState() => _DashboardState();
}
class _DashboardState extends State<Dashboard> {
bool _autoRefresh = true;
int _selectedTab = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Dashboard'),
actions: [
IconButton(
icon: Icon(Icons.settings),
onPressed: () {},
),
],
),
body: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(16),
child: VStack(
spacing: 24.0,
children: [
// Stats row
_buildStatsRow(),
// Settings
PrimitiveCard(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
VStack(
spacing: 4.0,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Auto Refresh',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Text(
'Refresh data every 30 seconds',
style: TextStyle(
fontSize: 12,
color: Colors.grey[600],
),
),
],
),
PrimitiveToggleSwitch(
value: _autoRefresh,
onChanged: (v) => setState(() => _autoRefresh = v),
),
],
),
),
// Recent activity
_buildRecentActivity(),
],
),
),
),
);
}
Widget _buildStatsRow() {
return Row(
children: [
Expanded(child: _buildStatCard('Users', '1,234', Icons.people)),
SizedBox(width: 16),
Expanded(child: _buildStatCard('Revenue', '$45K', Icons.attach_money)),
],
);
}
Widget _buildStatCard(String label, String value, IconData icon) {
return PrimitiveCard(
elevation: 3.0,
child: VStack(
spacing: 8.0,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(icon, size: 32, color: Colors.blue),
Text(
value,
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
Text(
label,
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
),
],
),
);
}
Widget _buildRecentActivity() {
return VStack(
spacing: 12.0,
children: [
Text(
'Recent Activity',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
...List.generate(
5,
(i) => PrimitiveCard(
child: Row(
children: [
Icon(Icons.circle, size: 8, color: Colors.blue),
SizedBox(width: 12),
Expanded(child: Text('Activity item ${i + 1}')),
Text(
'${i + 1}m ago',
style: TextStyle(color: Colors.grey[600], fontSize: 12),
),
],
),
),
),
],
);
}
}Next Steps
- Review Component Documentation for detailed API references
- Learn about Architecture to understand implementation details
- Explore the source code for more examples
Last updated on