runable
This commit is contained in:
274
lib/core/utils/responsive_helper.dart
Normal file
274
lib/core/utils/responsive_helper.dart
Normal file
@@ -0,0 +1,274 @@
|
||||
/// Responsive layout utilities for optimal performance across devices
|
||||
///
|
||||
/// Features:
|
||||
/// - Breakpoint-based layouts
|
||||
/// - Adaptive grid columns
|
||||
/// - Performance-optimized responsive widgets
|
||||
/// - Device-specific optimizations
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '../constants/performance_constants.dart';
|
||||
|
||||
/// Responsive helper for device-specific optimizations
|
||||
class ResponsiveHelper {
|
||||
/// Check if device is mobile
|
||||
static bool isMobile(BuildContext context) {
|
||||
return MediaQuery.of(context).size.width < PerformanceConstants.mobileBreakpoint;
|
||||
}
|
||||
|
||||
/// Check if device is tablet
|
||||
static bool isTablet(BuildContext context) {
|
||||
final width = MediaQuery.of(context).size.width;
|
||||
return width >= PerformanceConstants.mobileBreakpoint &&
|
||||
width < PerformanceConstants.desktopBreakpoint;
|
||||
}
|
||||
|
||||
/// Check if device is desktop
|
||||
static bool isDesktop(BuildContext context) {
|
||||
return MediaQuery.of(context).size.width >= PerformanceConstants.desktopBreakpoint;
|
||||
}
|
||||
|
||||
/// Get appropriate grid column count
|
||||
static int getGridColumns(BuildContext context) {
|
||||
final width = MediaQuery.of(context).size.width;
|
||||
return PerformanceConstants.getGridColumnCount(width);
|
||||
}
|
||||
|
||||
/// Get appropriate cache extent
|
||||
static double getCacheExtent(BuildContext context) {
|
||||
final height = MediaQuery.of(context).size.height;
|
||||
return PerformanceConstants.getCacheExtent(height);
|
||||
}
|
||||
|
||||
/// Check if high performance mode should be enabled
|
||||
static bool shouldUseHighPerformance(BuildContext context) {
|
||||
final width = MediaQuery.of(context).size.width;
|
||||
return PerformanceConstants.shouldUseHighPerformanceMode(width);
|
||||
}
|
||||
|
||||
/// Get value based on screen size
|
||||
static T getValue<T>(
|
||||
BuildContext context, {
|
||||
required T mobile,
|
||||
T? tablet,
|
||||
T? desktop,
|
||||
}) {
|
||||
if (isDesktop(context) && desktop != null) return desktop;
|
||||
if (isTablet(context) && tablet != null) return tablet;
|
||||
return mobile;
|
||||
}
|
||||
|
||||
/// Get responsive padding
|
||||
static EdgeInsets getResponsivePadding(BuildContext context) {
|
||||
if (isDesktop(context)) {
|
||||
return const EdgeInsets.all(24);
|
||||
} else if (isTablet(context)) {
|
||||
return const EdgeInsets.all(16);
|
||||
} else {
|
||||
return const EdgeInsets.all(12);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get responsive spacing
|
||||
static double getSpacing(BuildContext context) {
|
||||
if (isDesktop(context)) return 16;
|
||||
if (isTablet(context)) return 12;
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
|
||||
/// Responsive layout builder with performance optimization
|
||||
class ResponsiveLayout extends StatelessWidget {
|
||||
final Widget mobile;
|
||||
final Widget? tablet;
|
||||
final Widget? desktop;
|
||||
|
||||
const ResponsiveLayout({
|
||||
super.key,
|
||||
required this.mobile,
|
||||
this.tablet,
|
||||
this.desktop,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
if (constraints.maxWidth >= PerformanceConstants.desktopBreakpoint) {
|
||||
return desktop ?? tablet ?? mobile;
|
||||
} else if (constraints.maxWidth >= PerformanceConstants.mobileBreakpoint) {
|
||||
return tablet ?? mobile;
|
||||
} else {
|
||||
return mobile;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Responsive value builder
|
||||
class ResponsiveValue<T> extends StatelessWidget {
|
||||
final T mobile;
|
||||
final T? tablet;
|
||||
final T? desktop;
|
||||
final Widget Function(BuildContext context, T value) builder;
|
||||
|
||||
const ResponsiveValue({
|
||||
super.key,
|
||||
required this.mobile,
|
||||
this.tablet,
|
||||
this.desktop,
|
||||
required this.builder,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final value = ResponsiveHelper.getValue(
|
||||
context,
|
||||
mobile: mobile,
|
||||
tablet: tablet,
|
||||
desktop: desktop,
|
||||
);
|
||||
return builder(context, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// Adaptive grid configuration
|
||||
class AdaptiveGridConfig {
|
||||
final int crossAxisCount;
|
||||
final double childAspectRatio;
|
||||
final double spacing;
|
||||
final double cacheExtent;
|
||||
|
||||
const AdaptiveGridConfig({
|
||||
required this.crossAxisCount,
|
||||
required this.childAspectRatio,
|
||||
required this.spacing,
|
||||
required this.cacheExtent,
|
||||
});
|
||||
|
||||
factory AdaptiveGridConfig.fromContext(
|
||||
BuildContext context, {
|
||||
GridType type = GridType.products,
|
||||
}) {
|
||||
final width = MediaQuery.of(context).size.width;
|
||||
final height = MediaQuery.of(context).size.height;
|
||||
|
||||
return AdaptiveGridConfig(
|
||||
crossAxisCount: PerformanceConstants.getGridColumnCount(width),
|
||||
childAspectRatio: type == GridType.products
|
||||
? PerformanceConstants.productCardAspectRatio
|
||||
: PerformanceConstants.categoryCardAspectRatio,
|
||||
spacing: PerformanceConstants.gridSpacing,
|
||||
cacheExtent: PerformanceConstants.getCacheExtent(height),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
enum GridType {
|
||||
products,
|
||||
categories,
|
||||
}
|
||||
|
||||
/// Responsive grid view that adapts to screen size
|
||||
class AdaptiveGridView<T> extends StatelessWidget {
|
||||
final List<T> items;
|
||||
final Widget Function(BuildContext context, T item, int index) itemBuilder;
|
||||
final GridType type;
|
||||
final ScrollController? scrollController;
|
||||
final EdgeInsets? padding;
|
||||
|
||||
const AdaptiveGridView({
|
||||
super.key,
|
||||
required this.items,
|
||||
required this.itemBuilder,
|
||||
this.type = GridType.products,
|
||||
this.scrollController,
|
||||
this.padding,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final config = AdaptiveGridConfig.fromContext(context, type: type);
|
||||
|
||||
return GridView.builder(
|
||||
controller: scrollController,
|
||||
padding: padding ?? ResponsiveHelper.getResponsivePadding(context),
|
||||
physics: const BouncingScrollPhysics(
|
||||
parent: AlwaysScrollableScrollPhysics(),
|
||||
),
|
||||
cacheExtent: config.cacheExtent,
|
||||
itemCount: items.length,
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: config.crossAxisCount,
|
||||
crossAxisSpacing: config.spacing,
|
||||
mainAxisSpacing: config.spacing,
|
||||
childAspectRatio: config.childAspectRatio,
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
final item = items[index];
|
||||
return RepaintBoundary(
|
||||
key: ValueKey('adaptive_grid_item_$index'),
|
||||
child: itemBuilder(context, item, index),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Responsive container with adaptive sizing
|
||||
class ResponsiveContainer extends StatelessWidget {
|
||||
final Widget child;
|
||||
final double? mobileWidth;
|
||||
final double? tabletWidth;
|
||||
final double? desktopWidth;
|
||||
|
||||
const ResponsiveContainer({
|
||||
super.key,
|
||||
required this.child,
|
||||
this.mobileWidth,
|
||||
this.tabletWidth,
|
||||
this.desktopWidth,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final width = ResponsiveHelper.getValue(
|
||||
context,
|
||||
mobile: mobileWidth,
|
||||
tablet: tabletWidth,
|
||||
desktop: desktopWidth,
|
||||
);
|
||||
|
||||
return Container(
|
||||
width: width,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Extension for easier responsive values
|
||||
extension ResponsiveContextExtension on BuildContext {
|
||||
bool get isMobile => ResponsiveHelper.isMobile(this);
|
||||
bool get isTablet => ResponsiveHelper.isTablet(this);
|
||||
bool get isDesktop => ResponsiveHelper.isDesktop(this);
|
||||
|
||||
int get gridColumns => ResponsiveHelper.getGridColumns(this);
|
||||
double get cacheExtent => ResponsiveHelper.getCacheExtent(this);
|
||||
double get spacing => ResponsiveHelper.getSpacing(this);
|
||||
|
||||
EdgeInsets get responsivePadding => ResponsiveHelper.getResponsivePadding(this);
|
||||
|
||||
T responsive<T>({
|
||||
required T mobile,
|
||||
T? tablet,
|
||||
T? desktop,
|
||||
}) {
|
||||
return ResponsiveHelper.getValue(
|
||||
this,
|
||||
mobile: mobile,
|
||||
tablet: tablet,
|
||||
desktop: desktop,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user