This guide provides detailed information about FlutterX adaptive widgets and their usage patterns.
- Core Concepts
- Widget Categories
- Platform-Specific Behavior
- Theming System
- Best Practices
- API Reference Details
FlutterX widgets automatically adapt their appearance and behavior based on the target platform:
- iOS: Uses Cupertino design system (rounded corners, blur effects, native iOS styling)
- Android/Web/Desktop: Uses Material Design (shadows, elevation, Material 3 styling)
All Fx widgets maintain the same API regardless of platform:
// This works identically on iOS and Android
FxButton(
onPressed: () => print('Pressed'),
child: Text('Press Me'),
)Widgets automatically use FxTheme.of(context) to apply consistent theming:
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = FxTheme.of(context);
return FxButton(
color: theme.buttonColor,
textColor: theme.buttonTextColor,
child: Text('Themed Button'),
);
}
}| Widget | Description | Example |
|---|---|---|
FxApp |
Root application widget with theming | FxApp(home: HomePage(), fxTheme: FxThemeData.light()) |
FxScaffold |
Screen layout with app bar and body | FxScaffold(appBar: FxAppBar(...), body: ...) |
FxSliverAppBar |
App bar with scroll effects | Used for collapsible headers |
| Widget | Description | Common Properties |
|---|---|---|
FxButton |
Primary action button | onPressed, color, textColor, disabled |
FxTextButton |
Secondary button | onPressed, color, padding |
FxIconButton |
Icon-only button | icon, onPressed, color |
| Widget | Description | Validation |
|---|---|---|
FxTextField |
Text input field | controller, validator, decoration |
FxSwitch |
Toggle switch | value, onChanged, activeColor |
FxSlider |
Value selection | value, onChanged, min, max |
FxCheckbox |
Multiple choice | value, onChanged |
FxRadio |
Single choice | value, onChanged, groupValue |
FxDropdownButton |
Select from list | value, items, onChanged |
| Widget | Description | Useful For |
|---|---|---|
FxAppBar |
Screen header with actions | All screens with headers |
FxTabBar |
Tab navigation | Multi-tab interfaces |
FxTabScaffold |
Tab-based layout | Tabbed applications |
FxBottomNavigationBar |
Bottom navigation | Mobile apps |
| Widget | Description | Use Case |
|---|---|---|
FxActivityIndicator |
Loading indicator | Asynchronous operations |
FxProgressBar |
Progress display | File uploads, long operations |
FxSnackBar |
Toast messages | User feedback |
| Widget | Description | Platform Adaptation |
|---|---|---|
FxAlertDialog |
Modal dialogs | Material AlertDialog vs CupertinoAlertDialog |
FxModalBottomSheet |
Bottom sheet modal | Platform-specific animations |
- Widgets use rounded corners and blur effects
- Buttons often use system colors like
CupertinoColors.activeBlue - Text selection uses iOS-style handles
- Gestures may use different thresholds
// iOS-specific considerations
FxButton(
onPressed: onPressed,
child: Text('Button'),
)
// Renders as CupertinoButton with iOS styling- Widgets use elevation and shadows
- Material 3 styling with dynamic colors (if enabled)
- Keyboard shortcuts and mouse interactions
- Consistent 4dp grid alignment
// Material-specific considerations
FxButton(
onPressed: onPressed,
child: Text('Button'),
)
// Renders as ElevatedButton with Material stylingUse FxPlatform for platform-specific logic:
import 'package:flutterx/flutterx.dart';
// Platform checks
if (FxPlatform.isIOS) {
// iOS-specific behavior
}
if (FxPlatform.useCupertino) {
// Show Cupertino-specific UI
} else {
// Show Material-specific UI
}
// Manual platform override (advanced)
if (FxPlatform.isWeb) {
return FxMaterial(child: myWidget); // Force Material on web
}FxThemeData(
// Color palette
primaryColor: Colors.blue,
backgroundColor: Colors.white,
surfaceColor: Colors.white,
// Component colors
buttonColor: Colors.blue,
buttonTextColor: Colors.white,
appBarColor: Colors.blue,
appBarTextColor: Colors.white,
// Text colors
textColor: Colors.black,
secondaryTextColor: Colors.grey[600],
disabledColor: Colors.grey,
// Dimensions
borderRadius: 8.0,
defaultPadding: EdgeInsets.all(16),
// Typography
headlineTextStyle: TextStyle(...),
bodyTextStyle: TextStyle(...),
)// Predefined themes
FxThemeData.light() // Light theme with blue accent
FxThemeData.dark() // Dark theme with blue accent
// Custom themes
FxThemeData(
primaryColor: Colors.green,
// ... customize other properties
)class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool _isDark = false;
void _toggleTheme() {
setState(() {
_isDark = !_isDark;
});
}
@override
Widget build(BuildContext context) {
return FxApp(
fxTheme: _isDark ? FxThemeData.dark() : FxThemeData.light(),
home: HomePage(onThemeToggle: _toggleTheme),
);
}
}// ✅ Good - Let FlutterX adapt
FxButton(onPressed: onPressed, child: Text('OK'))
// ❌ Bad - Manual platform switching
Platform.isIOS ? CupertinoButton(...) : ElevatedButton(...)// ✅ Good - Fx widgets use consistent APIs
FxTextField(placeholder: 'Enter name')
FxSlider(value: _value, onChanged: _onChanged)
// ❌ Bad - Platform-specific properties
FxTextField(hintText: 'Enter name') // Only works on Android// ✅ Good - Theme-based customization
class ThemedCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = FxTheme.of(context);
return Card(
color: theme.surfaceColor,
child: FxButton(
color: theme.primaryColor,
child: Text(
'Action',
style: TextStyle(color: theme.buttonTextColor),
),
),
);
}
}// ✅ Good - Platform-aware behavior
FxButton(
onPressed: isLoading ? null : _submit,
child: Text(isLoading ? 'Submitting...' : 'Submit'),
)
// ✅ Good - Platform-specific features
if (FxPlatform.isIOS) {
showFxCupertinoPickerDialog(context);
} else {
showFxMaterialDialog(context);
}padding: EdgeInsetsGeometry - Internal spacingmargin: EdgeInsetsGeometry - External spacingwidth: double - Fixed widthheight: double - Fixed heightconstraints: BoxConstraints - Size constraints
color: Color - Background colorforegroundColor: Color - Text and icon colorshadowColor: Color - Shadow colorborderRadius: BorderRadius - Corner radius
onPressed: VoidCallback - Press handleronChanged: ValueChanged - Value change handlerenabled: bool - Enable/disable widgetautofocus: bool - Auto-focus on build
FxButton(
onPressed: onPressed,
style: FxButtonStyle(
backgroundColor: Colors.red,
border: Border.all(color: Colors.white),
borderRadius: BorderRadius.circular(25),
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
),
child: Text('Styled Button'),
)FxButton(
onPressed: onPressed,
animationDuration: Duration(milliseconds: 200),
curve: Curves.easeInOut,
child: Text('Animated Button'),
)FxButton(
onPressed: onPressed,
semanticLabel: 'Submit form',
excludeFromSemantics: false,
child: Text('Submit'),
)class SafeFxButton extends StatelessWidget {
final VoidCallback? onPressed;
const SafeFxButton({required this.onPressed});
@override
Widget build(BuildContext context) {
try {
return FxButton(
onPressed: onPressed,
child: Text('Safe Button'),
);
} catch (e) {
// Fallback for any styling errors
return TextButton(
onPressed: onPressed,
child: Text('Safe Button'),
);
}
}
}ElevatedButton(
onPressed: onPressed,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
),
child: Text('Button'),
)FxButton(
onPressed: onPressed,
color: Colors.blue,
textColor: Colors.white,
child: Text('Button'),
)Theme(
data: ThemeData(
primaryColor: Colors.blue,
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
),
),
),
child: MyApp(),
)FxApp(
fxTheme: FxThemeData.light().copyWith(
primaryColor: Colors.blue,
buttonColor: Colors.blue,
),
child: MyApp(),
)- Ensure you're using Fx widgets (FxButton, not ElevatedButton)
- Check that
FxAppis used as the root widget
- Verify
FxTheme.of(context)is called inside build methods - Ensure
FxApp(fxTheme: ...)is set
FxPlatformusesdefaultTargetPlatform- Web detection requires
kIsWebflag
// Debug platform information
print('Platform: ${FxPlatform.isIOS ? "iOS" : "Android"}');
print('Using Cupertino: ${FxPlatform.useCupertino}');
// Debug theme information
final theme = FxTheme.of(context);
print('Theme primary color: ${theme.primaryColor}');
// Debug widget tree
debugDumpApp();class OptimizedWidget extends StatelessWidget {
const OptimizedWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
// ✅ Extract theme once
final theme = FxTheme.of(context);
final platform = FxPlatform.useCupertino;
return FxScaffold(
appBar: FxAppBar(
backgroundColor: theme.appBarColor,
title: Text(
'Title',
style: TextStyle(color: theme.appBarTextColor),
),
),
body: Column(
children: [
FxButton(
color: theme.buttonColor,
onPressed: () => debugPrint('Pressed on ${platform ? "iOS" : "Android"}'),
child: Text('Button'),
),
],
),
);
}
}class SmartFxButton extends StatelessWidget {
final String label;
final VoidCallback? onPressed;
const SmartFxButton({
Key? key,
required this.label,
this.onPressed,
}) : super(key: key);
@override
Widget build(BuildContext context) {
// Only rebuilds when theme changes, not every parent rebuild
final theme = FxTheme.of(context);
return FxButton(
color: theme.buttonColor,
onPressed: onPressed,
child: Text(label),
);
}
}This comprehensive guide covers the core concepts, usage patterns, and best practices for FlutterX. For more detailed API documentation, see the generated docs in the docs/ directory.