Build a Flutter Profile Card from a JSON Schema
Deconstruct how to compose Container, Row, Column, Text, and Icon widgets into an adaptive profile card with full standalone Dart code generation.
1. The Core Challenge & Problem
Mobile applications frequently need user profile teasers or social cards across feeds and drawer menus. Hardcoding separate layout variations for mobile and web leads to fragmented UI code. Furthermore, defining layouts dynamically via declarative backend schemas requires a disciplined, validated hierarchy to prevent layout crashes.
2. Architectural Principles & Resolution
This tutorial demonstrates how to construct a complete profile card using WidgetExamples' validated JSON schema (Version 1). The design employs a root Container acting as an elevated surface, an avatar badge composed of an Icon with circular borderRadius, a nested Column for typography, and an ElevatedButton for following/connecting.
Because WidgetExamples enforces strict schema validation, every numeric dimension, hex colour (#2563EB), and alignment enum is pre-checked before passing into the Flutter rendering pipeline. When exported, the schema maps directly to clean, standalone Flutter Material 3 widgets without any runtime dependencies on the schema engine.
3. Complete Flutter Code
main.dart (Flutter 3.x+ ready)import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Color(0xFFF1F5F9),
body: Center(
child: ProfileCardExample(),
),
),
));
}
class ProfileCardExample extends StatelessWidget {
const ProfileCardExample({super.key});
@override
Widget build(BuildContext context) {
return Container(
width: 320,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: const [
BoxShadow(
color: Color(0x1A000000),
blurRadius: 12,
offset: Offset(0, 4),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Avatar circle
Container(
width: 72,
height: 72,
decoration: BoxDecoration(
color: const Color(0xFFEFF6FF),
borderRadius: BorderRadius.circular(36),
),
child: const Center(
child: Icon(Icons.person, size: 40, color: Color(0xFF2563EB)),
),
),
const SizedBox(height: 12),
// User Name
const Text(
'Alex Mercer',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Color(0xFF0F172A),
),
),
const SizedBox(height: 4),
// Role subtitle
const Text(
'Principal Mobile Engineer',
style: TextStyle(
fontSize: 13,
color: Color(0xFF64748B),
),
),
const SizedBox(height: 16),
// Action button
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Connected with Alex Mercer!')),
);
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF2563EB),
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
child: const Text('Connect'),
),
),
],
),
);
}
} 4. Expected Visual & Behavioral Result
A clean 320px wide profile card centered on the screen. It features a soft drop shadow, rounded corners (16px), a light blue circular avatar with a person glyph, bold headline typography, muted subtitle text, and a full-width blue action button that shows a snackbar message when tapped.
5. Common Pitfalls & Traps
Pitfall #1: Using unbounded height inside Column without mainAxisSize: MainAxisSize.min
Pitfall #2: Applying double hex opacity strings without ARGB ordering (e.g. #2563EB80 vs Color(0x802563EB))
Pitfall #3: Deeply nesting multiple Center or Padding widgets when Container can specify both