flutter_ios_preview 1.0.0
flutter_ios_preview: ^1.0.0 copied to clipboard
A premium Flutter tool for high-fidelity iOS simulation. Featuring the curated iphone Collection, dynamic notch/island hardware, and proportional scaling for cross-platform design testing.
import 'package:flutter/material.dart';
import 'package:flutter_ios_preview/flutter_ios_preview.dart';
void main() {
runApp(const ExampleApp());
}
class ExampleApp extends StatefulWidget {
const ExampleApp({super.key});
@override
State<ExampleApp> createState() => _ExampleAppState();
}
class _ExampleAppState extends State<ExampleApp> {
// Flagship default: iPhone 16 Pro Max (6.9")
DeviceModel _selectedModel = DeviceModel.iPhone16ProMax;
bool _enableInspector = true;
bool _useFrame = true;
bool _showPreview = true;
// Explicit controller to resolve the 'Attached to more than one ScrollView' conflict
final ScrollController _mainScrollController = ScrollController();
@override
void dispose() {
_mainScrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
colorSchemeSeed: const Color(0xFF007AFF),
),
home: Builder(
builder: (context) => Scaffold(
appBar: AppBar(
title: const Text('iOS Hub'),
actions: [
IconButton(
icon: Icon(
_showPreview ? Icons.visibility_off : Icons.visibility,
),
onPressed: () => setState(() => _showPreview = !_showPreview),
tooltip: 'Toggle Preview',
),
],
),
drawer: _buildSettingsDrawer(),
body: _showPreview
? IosPreview(
deviceModel: _selectedModel,
enableInspector: _enableInspector,
useFrame: _useFrame,
child: MySampleApp(controller: _mainScrollController),
)
: MySampleApp(controller: _mainScrollController),
floatingActionButton: (_showPreview && _useFrame)
? FloatingActionButton(
child: const Icon(Icons.camera_alt),
onPressed: () async {
final path = await ScreenshotHandler.captureAndSave(
IosPreview.boundaryKey,
);
if (path != null && context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Screenshot saved: $path')),
);
}
},
)
: null,
),
),
);
}
Widget _buildSettingsDrawer() {
return Drawer(
child: Column(
children: [
const DrawerHeader(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xFF000000), Color(0xFF1A1A1A)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.apple, color: Colors.white, size: 48),
SizedBox(height: 8),
Text(
'IOS COLLECTION',
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
letterSpacing: 1,
),
),
Text(
'Elite Flagship Simulator',
style: TextStyle(color: Colors.white70, fontSize: 12),
),
],
),
),
),
Expanded(
child: ListView(
padding: EdgeInsets.zero,
children: [
SwitchListTile(
title: const Text('Device Frame'),
subtitle: Text(
_useFrame
? 'Showing Flagship Frame'
: 'Full Screen Simulation',
),
value: _useFrame,
onChanged: (v) => setState(() => _useFrame = v),
),
const Divider(),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'FLAGSHIP GENERATION',
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.bold,
color: Colors.blueAccent,
),
),
const SizedBox(height: 8),
Container(
padding: const EdgeInsets.symmetric(horizontal: 12),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.grey[300]!),
borderRadius: BorderRadius.circular(12),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<DeviceModel>(
value: _selectedModel,
isExpanded: true,
borderRadius: BorderRadius.circular(12),
onChanged: (m) =>
setState(() => _selectedModel = m!),
items: DeviceModel.values.map((m) {
final isSE = m.name.contains('SE');
return DropdownMenuItem(
value: m,
child: Text(
m.name,
style: TextStyle(
fontWeight: m.name.contains('Max')
? FontWeight.bold
: FontWeight.normal,
color: isSE
? Colors.deepOrange
: Colors.black87,
),
),
);
}).toList(),
),
),
),
],
),
),
_buildDeviceSpecs(),
const Divider(),
SwitchListTile(
title: const Text('Widget Inspector'),
subtitle: const Text('Analyze elite UI metrics'),
value: _enableInspector,
onChanged: (v) => setState(() => _enableInspector = v),
),
const Divider(),
const AboutListTile(
icon: Icon(Icons.info_outline),
applicationName: 'Flutter iOS Preview',
applicationVersion: '1.0.0 (Flagship Edition)',
),
],
),
),
],
),
);
}
Widget _buildDeviceSpecs() {
final info = DeviceInfo.fromModel(_selectedModel);
final isUltra =
_selectedModel.name.contains('16') ||
_selectedModel.name.contains('17') ||
_selectedModel.name.contains('18');
return Container(
margin: const EdgeInsets.all(16),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: isUltra ? Colors.blue.withAlpha(10) : Colors.grey[50],
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: isUltra ? Colors.blue.withAlpha(40) : Colors.grey[200]!,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
isUltra
? Icons.workspace_premium
: Icons.dashboard_customize_outlined,
size: 16,
color: isUltra ? Colors.blue : Colors.blueAccent,
),
const SizedBox(width: 8),
Text(
isUltra ? 'ULTRA-MAX SPECS' : 'FLAGSHIP SPECS',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: isUltra ? Colors.blue : Colors.blueAccent,
),
),
],
),
const SizedBox(height: 12),
_specRow('Model', _selectedModel.name),
_specRow(
'Logical Size',
'${info.screenSize.width.toInt()} x ${info.screenSize.height.toInt()}',
),
_specRow('Top Inset', '${info.safeArea.top.toInt()}pt'),
_specRow('Side Insets', '${info.landscapeSideInset.toInt()}pt'),
_specRow('Bezel Width', '${info.bezelThickness}pt'),
_specRow('Curvature', '${info.cornerRadius.toInt()}pt'),
if (info.category == DeviceCategory.dynamicIsland)
_specRow(
'Island Width',
'${info.islandWidth.toInt()}pt',
isHighlight: _selectedModel == DeviceModel.iPhone18ProMax,
),
],
),
);
}
Widget _specRow(String label, String value, {bool isHighlight = false}) {
return Padding(
padding: const EdgeInsets.only(bottom: 6),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label, style: const TextStyle(fontSize: 11, color: Colors.grey)),
Text(
value,
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.bold,
color: isHighlight ? Colors.blue : Colors.black87,
),
),
],
),
);
}
}
class MySampleApp extends StatelessWidget {
final ScrollController? controller;
const MySampleApp({super.key, this.controller});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Pro Max Flagship'),
centerTitle: true,
backgroundColor: Colors.white,
elevation: 0,
leading: const Icon(Icons.menu, color: Colors.black),
actions: const [
Icon(Icons.shopping_bag_outlined, color: Colors.black),
SizedBox(width: 16),
],
),
body: CustomScrollView(
controller: controller,
slivers: [
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'iPhone 18 Pro Max',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.blueAccent,
),
),
const Text(
'Big. Bold. Brilliant.',
style: TextStyle(
fontSize: 36,
fontWeight: FontWeight.w900,
letterSpacing: -1,
),
),
const SizedBox(height: 12),
const Text(
'Experience the elite 6.9-inch flagship simulation.',
style: TextStyle(color: Colors.grey, fontSize: 16),
),
const SizedBox(height: 24),
_buildClassicCard(
'Ultra Power.',
'Titanium Refined.',
Colors.black,
),
],
),
),
),
SliverPadding(
padding: const EdgeInsets.symmetric(horizontal: 24),
sliver: SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => _buildProductItem(index),
childCount: 8,
),
),
),
],
),
bottomNavigationBar: BottomNavigationBar(
elevation: 10,
selectedItemColor: Colors.blueAccent,
unselectedItemColor: Colors.grey,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.shop_outlined),
label: 'Shop',
),
BottomNavigationBarItem(icon: Icon(Icons.search), label: 'Search'),
BottomNavigationBarItem(
icon: Icon(Icons.person_pin),
label: 'Account',
),
],
),
);
}
Widget _buildClassicCard(String title, String subtitle, Color bgColor) {
return Container(
width: double.infinity,
height: 380,
decoration: BoxDecoration(
color: bgColor,
borderRadius: BorderRadius.circular(32),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(77),
blurRadius: 20,
offset: const Offset(0, 10),
),
],
),
child: Stack(
children: [
Positioned(
top: 50,
left: 30,
right: 30,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
title,
style: const TextStyle(
color: Colors.white,
fontSize: 40,
fontWeight: FontWeight.w900,
),
),
const SizedBox(height: 10),
Text(
subtitle,
style: const TextStyle(color: Colors.white70, fontSize: 18),
textAlign: TextAlign.center,
),
],
),
),
const Positioned(
bottom: -20,
left: 0,
right: 0,
child: Center(
child: Icon(Icons.auto_awesome, size: 220, color: Colors.white10),
),
),
],
),
);
}
Widget _buildProductItem(int index) {
return Container(
margin: const EdgeInsets.only(bottom: 16),
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(20),
),
child: Row(
children: [
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
),
child: const Icon(Icons.star_outline, color: Colors.blueAccent),
),
const SizedBox(width: 20),
const Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Pro Max Feature',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
),
Text(
'Elite precision simulation.',
style: TextStyle(color: Colors.grey, fontSize: 13),
),
],
),
),
const Icon(Icons.arrow_forward_ios, color: Colors.grey, size: 14),
],
),
);
}
}