Last active
September 10, 2024 09:51
-
-
Save rohan20/869492358cbb15311538f069a0c749af to your computer and use it in GitHub Desktop.
Flutter Google Maps Bottom Sheet
This file contains 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'; | |
class GoogleMapsClonePage extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
body: Stack( | |
children: <Widget>[ | |
CustomGoogleMap(), | |
CustomHeader(), | |
DraggableScrollableSheet( | |
initialChildSize: 0.30, | |
minChildSize: 0.15, | |
builder: (BuildContext context, ScrollController scrollController) { | |
return SingleChildScrollView( | |
controller: scrollController, | |
child: CustomScrollViewContent(), | |
); | |
}, | |
), | |
], | |
), | |
); | |
} | |
} | |
/// Google Map in the background | |
class CustomGoogleMap extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
color: Colors.blue[50], | |
child: Center(child: Text("Google Map here")), | |
); | |
} | |
} | |
/// Search text field plus the horizontally scrolling categories below the text field | |
class CustomHeader extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Column( | |
children: <Widget>[ | |
CustomSearchContainer(), | |
CustomSearchCategories(), | |
], | |
); | |
} | |
} | |
class CustomSearchContainer extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Padding( | |
padding: const EdgeInsets.fromLTRB(16, 40, 16, 8), //adjust "40" according to the status bar size | |
child: Container( | |
height: 50, | |
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(6)), | |
child: Row( | |
children: <Widget>[ | |
CustomTextField(), | |
Icon(Icons.mic), | |
SizedBox(width: 16), | |
CustomUserAvatar(), | |
SizedBox(width: 16), | |
], | |
), | |
), | |
); | |
} | |
} | |
class CustomTextField extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Expanded( | |
child: TextFormField( | |
maxLines: 1, | |
decoration: InputDecoration( | |
contentPadding: const EdgeInsets.all(16), | |
hintText: "Search here", | |
border: InputBorder.none, | |
), | |
), | |
); | |
} | |
} | |
class CustomUserAvatar extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
height: 32, | |
width: 32, | |
decoration: BoxDecoration(color: Colors.grey[500], borderRadius: BorderRadius.circular(16)), | |
); | |
} | |
} | |
class CustomSearchCategories extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return SingleChildScrollView( | |
scrollDirection: Axis.horizontal, | |
child: Row( | |
children: <Widget>[ | |
SizedBox(width: 16), | |
CustomCategoryChip(Icons.fastfood, "Takeout"), | |
SizedBox(width: 12), | |
CustomCategoryChip(Icons.directions_bike, "Delivery"), | |
SizedBox(width: 12), | |
CustomCategoryChip(Icons.local_gas_station, "Gas"), | |
SizedBox(width: 12), | |
CustomCategoryChip(Icons.shopping_cart, "Groceries"), | |
SizedBox(width: 12), | |
CustomCategoryChip(Icons.local_pharmacy, "Pharmacies"), | |
SizedBox(width: 12), | |
], | |
), | |
); | |
} | |
} | |
class CustomCategoryChip extends StatelessWidget { | |
final IconData iconData; | |
final String title; | |
CustomCategoryChip(this.iconData, this.title); | |
@override | |
Widget build(BuildContext context) { | |
return Chip( | |
label: Row( | |
children: <Widget>[Icon(iconData, size: 16), SizedBox(width: 8), Text(title)], | |
), | |
backgroundColor: Colors.grey[50], | |
); | |
} | |
} | |
/// Content of the DraggableBottomSheet's child SingleChildScrollView | |
class CustomScrollViewContent extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Card( | |
elevation: 12.0, | |
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)), | |
margin: const EdgeInsets.all(0), | |
child: Container( | |
decoration: BoxDecoration( | |
borderRadius: BorderRadius.circular(24), | |
), | |
child: CustomInnerContent(), | |
), | |
); | |
} | |
} | |
class CustomInnerContent extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Column( | |
children: <Widget>[ | |
SizedBox(height: 12), | |
CustomDraggingHandle(), | |
SizedBox(height: 16), | |
CustomExploreBerlin(), | |
SizedBox(height: 16), | |
CustomHorizontallyScrollingRestaurants(), | |
SizedBox(height: 24), | |
CustomFeaturedListsText(), | |
SizedBox(height: 16), | |
CustomFeaturedItemsGrid(), | |
SizedBox(height: 24), | |
CustomRecentPhotosText(), | |
SizedBox(height: 16), | |
CustomRecentPhotoLarge(), | |
SizedBox(height: 12), | |
CustomRecentPhotosSmall(), | |
SizedBox(height: 16), | |
], | |
); | |
} | |
} | |
class CustomDraggingHandle extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
height: 5, | |
width: 30, | |
decoration: BoxDecoration(color: Colors.grey[200], borderRadius: BorderRadius.circular(16)), | |
); | |
} | |
} | |
class CustomExploreBerlin extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Row( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: <Widget>[ | |
Text("Explore Berlin", style: TextStyle(fontSize: 22, color: Colors.black45)), | |
SizedBox(width: 8), | |
Container( | |
height: 24, | |
width: 24, | |
child: Icon(Icons.arrow_forward_ios, size: 12, color: Colors.black54), | |
decoration: BoxDecoration(color: Colors.grey[200], borderRadius: BorderRadius.circular(16)), | |
), | |
], | |
); | |
} | |
} | |
class CustomHorizontallyScrollingRestaurants extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Padding( | |
padding: const EdgeInsets.only(left: 16), | |
child: SingleChildScrollView( | |
scrollDirection: Axis.horizontal, | |
child: Row( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: <Widget>[ | |
CustomRestaurantCategory(), | |
SizedBox(width: 12), | |
CustomRestaurantCategory(), | |
SizedBox(width: 12), | |
CustomRestaurantCategory(), | |
SizedBox(width: 12), | |
CustomRestaurantCategory(), | |
SizedBox(width: 12), | |
], | |
), | |
), | |
); | |
} | |
} | |
class CustomFeaturedListsText extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Padding( | |
padding: const EdgeInsets.only(left: 16), | |
//only to left align the text | |
child: Row( | |
children: <Widget>[Text("Featured Lists", style: TextStyle(fontSize: 14))], | |
), | |
); | |
} | |
} | |
class CustomFeaturedItemsGrid extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Padding( | |
padding: const EdgeInsets.symmetric(horizontal: 16), | |
child: GridView.count( | |
//to avoid scrolling conflict with the dragging sheet | |
physics: NeverScrollableScrollPhysics(), | |
padding: const EdgeInsets.all(0), | |
crossAxisCount: 2, | |
mainAxisSpacing: 12, | |
crossAxisSpacing: 12, | |
shrinkWrap: true, | |
children: <Widget>[ | |
CustomFeaturedItem(), | |
CustomFeaturedItem(), | |
CustomFeaturedItem(), | |
CustomFeaturedItem(), | |
], | |
), | |
); | |
} | |
} | |
class CustomRecentPhotosText extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Padding( | |
padding: const EdgeInsets.only(left: 16), | |
child: Row( | |
children: <Widget>[ | |
Text("Recent Photos", style: TextStyle(fontSize: 14)), | |
], | |
), | |
); | |
} | |
} | |
class CustomRecentPhotoLarge extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Padding( | |
padding: const EdgeInsets.symmetric(horizontal: 16), | |
child: CustomFeaturedItem(), | |
); | |
} | |
} | |
class CustomRecentPhotosSmall extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return CustomFeaturedItemsGrid(); | |
} | |
} | |
class CustomRestaurantCategory extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
height: 100, | |
width: 100, | |
decoration: BoxDecoration( | |
color: Colors.grey[500], | |
borderRadius: BorderRadius.circular(8), | |
), | |
); | |
} | |
} | |
class CustomFeaturedItem extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
height: 200, | |
decoration: BoxDecoration( | |
color: Colors.grey[500], | |
borderRadius: BorderRadius.circular(8), | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Dear Sir
if i use Stack+Positioned (or Stack+? )
i want resize Google map area like attach image
the top & bottom widget is fix Positioned
other empty area i want put re-size Google map
how to do ?
THX