Last active
February 23, 2024 05:53
-
-
Save BoltUIX/1f397fab579c68d0a2bc331a806da4dc to your computer and use it in GitHub Desktop.
Building adaptive apps
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import 'package:flutter/material.dart'; | |
| void main() => runApp(const MyApp()); | |
| class MyApp extends StatelessWidget { | |
| const MyApp({Key? key}) : super(key: key); | |
| @override | |
| Widget build(BuildContext context) { | |
| return MaterialApp( | |
| title: 'Adaptive Screen', | |
| home: const AdaptiveScreen(), | |
| theme: ThemeData( | |
| colorScheme: ColorScheme.fromSeed(seedColor: Colors.blueAccent), | |
| useMaterial3: true, | |
| ), | |
| ); | |
| } | |
| } | |
| class AdaptiveScreen extends StatefulWidget { | |
| const AdaptiveScreen({Key? key}) : super(key: key); | |
| @override | |
| AdaptiveScreenState createState() => AdaptiveScreenState(); | |
| } | |
| class AdaptiveScreenState extends State<AdaptiveScreen> { | |
| int _selectedIndex = 0; | |
| @override | |
| Widget build(BuildContext context) { | |
| return Scaffold( | |
| appBar: AppBar( | |
| title: const Text("Responsive and Adaptive"), | |
| ), | |
| bottomNavigationBar: MediaQuery.of(context).size.width < 640? | |
| BottomNavigationBar( | |
| currentIndex: _selectedIndex, | |
| unselectedItemColor: Colors.grey, | |
| selectedItemColor: Colors.indigoAccent, | |
| // called when one tab is selected | |
| onTap: (int index) { | |
| setState(() { | |
| _selectedIndex = index; | |
| }); | |
| }, | |
| // bottom tab items | |
| items: const [ | |
| BottomNavigationBarItem( | |
| icon: Icon(Icons.home), label: 'Home'), | |
| BottomNavigationBarItem( | |
| icon: Icon(Icons.feed), label: 'Feed'), | |
| BottomNavigationBarItem( | |
| icon: Icon(Icons.favorite), label: 'Favorites'), | |
| BottomNavigationBarItem( | |
| icon: Icon(Icons.settings), label: 'Settings') | |
| ]):null, | |
| body: Row( | |
| children: [ | |
| if (MediaQuery.of(context).size.width >= 640) | |
| NavigationRail( | |
| onDestinationSelected: (int index) { | |
| setState(() { | |
| _selectedIndex = index; | |
| }); | |
| }, | |
| selectedIndex: _selectedIndex, | |
| destinations: const [ | |
| NavigationRailDestination( | |
| icon: Icon(Icons.home), label: Text('Home')), | |
| NavigationRailDestination( | |
| icon: Icon(Icons.feed), label: Text('Feed')), | |
| NavigationRailDestination( | |
| icon: Icon(Icons.favorite), label: Text('Favorites')), | |
| NavigationRailDestination( | |
| icon: Icon(Icons.settings), label: Text('Settings')), | |
| ], | |
| labelType: NavigationRailLabelType.all, | |
| selectedLabelTextStyle: const TextStyle( | |
| color: Colors.teal, | |
| ), | |
| unselectedLabelTextStyle: const TextStyle(), | |
| // Called when one tab is selected | |
| leading: const Column( | |
| children: [ | |
| SizedBox( | |
| height: 8, | |
| ), | |
| CircleAvatar( | |
| radius: 20, | |
| child: Icon(Icons.person), | |
| ), | |
| ], | |
| ), | |
| ), | |
| const Expanded(child: MyResponsiveGridImage()) | |
| ], | |
| ), | |
| ); | |
| } | |
| } | |
| //.................................................................................. | |
| class MyResponsiveGridImage extends StatelessWidget { | |
| const MyResponsiveGridImage({Key? key}) : super(key: key); | |
| @override | |
| Widget build(BuildContext context) { | |
| final textTheme = Theme.of(context) | |
| .textTheme | |
| .apply(displayColor: Theme.of(context).colorScheme.onSurface); | |
| // Set the default number of columns to 3. | |
| int columnsCount = 3; | |
| // Use the ResponsiveUtils class to determine the device's screen size. | |
| if (ResponsiveUtils.isMobile(context)) { | |
| columnsCount = 2; | |
| } else if (ResponsiveUtils.isDesktop(context)) { | |
| columnsCount = 5; | |
| } | |
| // Build the grid view using the number of columns. | |
| return Scaffold( | |
| /*appBar: AppBar( | |
| title: const Text('Responsive Grid View'), | |
| ),*/ | |
| body: | |
| GridView.builder( | |
| // Set padding and spacing between cards. | |
| padding: const EdgeInsets.all(10), | |
| gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( | |
| // Set the number of columns based on the device's screen size. | |
| crossAxisCount: columnsCount, | |
| // Set the aspect ratio of each card. | |
| childAspectRatio: 3 / 2, | |
| crossAxisSpacing: 10, | |
| mainAxisSpacing: 10, | |
| ), | |
| // Set the number of items in the grid view. | |
| itemCount: 20, | |
| itemBuilder: (BuildContext context, int index) { | |
| // Build each card in the grid view. | |
| return Card( | |
| child: Column( | |
| crossAxisAlignment: CrossAxisAlignment.stretch, | |
| children: [ | |
| const Expanded( | |
| // Add an image to each card. | |
| child: | |
| Icon(Icons.category), | |
| /* Image.asset('assets/images/test.webp', | |
| fit: BoxFit.cover, | |
| ),*/ | |
| /* Image.network( | |
| 'https://picsum.photos/id/$index/400/300', | |
| fit: BoxFit.cover, | |
| ),*/ | |
| ), | |
| const SizedBox(height: 10), | |
| Padding( | |
| padding: const EdgeInsets.symmetric(horizontal: 10), | |
| child: Column( | |
| crossAxisAlignment: CrossAxisAlignment.start, | |
| children: [ | |
| // Add a title to each card. | |
| Text( | |
| 'Item $index', style: textTheme.titleMedium!.copyWith(fontWeight: FontWeight.bold), ), | |
| const SizedBox(height: 5), | |
| // Add a description to each card. | |
| Text( | |
| 'Description of item $index', style: textTheme.bodyMedium!), | |
| ], | |
| ), | |
| ), | |
| const SizedBox(height: 10), | |
| ], | |
| ), | |
| ); | |
| }, | |
| // Set the grid view to shrink wrap its contents. | |
| shrinkWrap: true, | |
| // Disable scrolling in the grid view. | |
| //physics: const NeverScrollableScrollPhysics(), | |
| ), | |
| ); | |
| } | |
| } | |
| //.................................................................................. | |
| class ResponsiveUtils { | |
| // Check if the device is considered as mobile based on screen width. | |
| static bool isMobile(BuildContext context) => | |
| MediaQuery.of(context).size.width <= 600; | |
| // Check if the device is considered as tablet based on screen width. | |
| static bool isTablet(BuildContext context) => | |
| MediaQuery.of(context).size.width > 600 && | |
| MediaQuery.of(context).size.width <= 1200; | |
| // Check if the device is considered as desktop based on screen width. | |
| static bool isDesktop(BuildContext context) => | |
| MediaQuery.of(context).size.width > 1200; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment