map_themes 0.0.2+2
map_themes: ^0.0.2+2 copied to clipboard
A flutter plugin providing customizable Map themes.
Map Themes Plugin #
A Flutter plugin that provides easy-to-use map theming capabilities for Google Maps and other map implementations. Transform your maps with beautiful predefined themes or create custom styling with minimal code.
UI Shots #
|
|
|
|
|
|
|
|
Features #
5+ Built-in Themes: Standard, Dark, Night, Night Blue, and Retro themes
Easy Integration: Simple API with minimal setup required
Auto Persistence: Automatically saves and restores user's theme preference
Three Usage Patterns: Choose from MapThemeWidget, ThemeSelectorWidget, or MapThemeManager
Customizable UI: Dropdown or horizontal list layouts with custom styling
Highly Testable: Clean architecture with comprehensive test coverage
Flexible: Works with any map widget that accepts style JSON [Currently supporting Google maps at the moment]
Demo Video #
Installation #
Add this to your package's pubspec.yaml file:
dependencies:
map_themes: ^0.0.1
google_maps_flutter: ^2.5.0 # or your preferred map package [Only google_maps_flutter at the moment]
Then run:
flutter pub get
Platform Setup #
For Google Maps integration, follow the official setup guide:
Android (android/app/src/main/AndroidManifest.xml):
<meta-data android:name="com.google.android.geo.API_KEY"
android:value="YOUR_API_KEY"/>
iOS (ios/Runner/AppDelegate.swift):
GMSServices.provideAPIKey("YOUR_API_KEY")
Usage #
Quick Start #
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:map_themes/map_themes.dart';
class MapScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: MapThemeWidget(
builder: (mapStyle) {
return GoogleMap(
initialCameraPosition: CameraPosition(
target: LatLng(37.4219983, -122.084),
zoom: 14.0,
),
style: mapStyle.isEmpty ? null : mapStyle,
);
},
),
);
}
}
Three Usage Patterns #
1. MapThemeWidget (All-in-One)
Perfect for quick integration with built-in theme selector:
MapThemeWidget(
builder: (mapStyle) {
return GoogleMap(
initialCameraPosition: _initialPosition,
style: mapStyle.isEmpty ? null : mapStyle,
// ... other properties
);
},
showSelector: true,
selectorAlignment: Alignment.topRight,
selectorLayout: ThemeSelectorLayout.horizontalList,
)
2. ThemeSelectorWidget (Separate Selector)
When you want full control over map and selector placement:
class MapScreen extends StatefulWidget {
@override
_MapScreenState createState() => _MapScreenState();
}
class _MapScreenState extends State<MapScreen> {
String _currentMapStyle = '';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Map Themes'),
actions: [
ThemeSelectorWidget(
layout: ThemeSelectorLayout.dropdown,
onThemeChanged: (themeJson) async {
setState(() {
_currentMapStyle = themeJson;
});
},
),
],
),
body: GoogleMap(
initialCameraPosition: _initialPosition,
style: _currentMapStyle.isEmpty ? null : _currentMapStyle,
// ... other properties
),
);
}
}
3. MapThemeManager (Programmatic Control)
For advanced scenarios requiring direct theme management:
class MapScreen extends StatefulWidget {
@override
_MapScreenState createState() => _MapScreenState();
}
class _MapScreenState extends State<MapScreen> {
final MapThemeManager _themeManager = MapThemeManager();
@override
void initState() {
super.initState();
_themeManager.initialize();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListenableBuilder(
listenable: _themeManager,
builder: (context, _) {
return GoogleMap(
initialCameraPosition: _initialPosition,
style: _themeManager.currentStyleJson,
// ... other properties
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => _themeManager.setTheme(MapStyleTheme.dark),
child: Icon(Icons.palette),
),
);
}
@override
void dispose() {
_themeManager.dispose();
super.dispose();
}
}
Examples #
Custom Asset Themes #
Load your own custom theme JSON files:
ThemeSelectorWidget(
customAssetPaths: [
'assets/themes/custom_blue.json',
'assets/themes/custom_green.json',
],
onThemeChanged: (themeJson) async {
// Handle theme change
},
)
Custom Theme Selector UI #
Create completely custom selector UI:
ThemeSelectorWidget(
customBuilder: ({
required BuildContext context,
required MapStyleTheme? currentTheme,
required String? currentThemeName,
required List<String> allThemes,
required Function(String) onThemeSelected,
required bool isEnabled,
required ThemeSelectorStyle style,
}) {
return Wrap(
children: allThemes.map((theme) {
final isSelected = theme == currentThemeName;
return GestureDetector(
onTap: () => onThemeSelected(theme),
child: Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: isSelected ? Colors.blue : Colors.grey[300],
borderRadius: BorderRadius.circular(8),
),
child: Text(
theme.toUpperCase(),
style: TextStyle(
color: isSelected ? Colors.white : Colors.black,
fontWeight: FontWeight.bold,
),
),
),
);
}).toList(),
);
},
onThemeChanged: (themeJson) {
// Handle theme change
},
)
Shared Theme Manager #
Share one theme manager across multiple map widgets:
class MultiMapScreen extends StatefulWidget {
@override
_MultiMapScreenState createState() => _MultiMapScreenState();
}
class _MultiMapScreenState extends State<MultiMapScreen> {
final MapThemeManager _sharedManager = MapThemeManager();
@override
void initState() {
super.initState();
_sharedManager.initialize();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
// Theme selector
ThemeSelectorWidget(
themeManager: _sharedManager,
onThemeChanged: (style) {}, // Optional callback
),
// Multiple maps sharing the same theme
Expanded(
child: MapThemeWidget(
themeManager: _sharedManager,
showSelector: false,
builder: (style) => GoogleMap(/* ... */),
),
),
Expanded(
child: MapThemeWidget(
themeManager: _sharedManager,
showSelector: false,
builder: (style) => GoogleMap(/* ... */),
),
),
],
);
}
@override
void dispose() {
_sharedManager.dispose();
super.dispose();
}
}
Customization #
Theme Selector Styling #
Customize the appearance of theme selectors:
ThemeSelectorWidget(
style: ThemeSelectorStyle(
backgroundColor: Colors.white,
selectedBackgroundColor: Colors.blue,
textColor: Colors.black,
selectedTextColor: Colors.white,
borderRadius: 12.0,
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
margin: EdgeInsets.all(4),
elevation: 2.0,
),
layout: ThemeSelectorLayout.horizontalList,
onThemeChanged: (style) {
// Handle theme change
},
)
Map Widget Selector Positioning #
Control where the theme selector appears on your map:
MapThemeWidget(
builder: (style) => GoogleMap(/* ... */),
selectorAlignment: Alignment.bottomLeft,
selectorBackgroundDecoration: BoxDecoration(
color: Colors.black.withOpacity(0.7),
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.black26,
blurRadius: 4,
offset: Offset(0, 2),
),
],
),
)
Parameters #
MapThemeWidget Parameters #
| Parameter | Type | Default | Description |
|---|---|---|---|
builder |
Widget Function(String) |
Required | Builder function that receives map style JSON |
showSelector |
bool |
true |
Whether to show the theme selector overlay |
selectorAlignment |
AlignmentGeometry |
Alignment.topRight |
Position of the theme selector on the map |
selectorLayout |
ThemeSelectorLayout |
horizontalList |
Layout style for the theme selector |
selectorStyle |
ThemeSelectorStyle? |
null |
Custom styling for the theme selector |
themeManager |
MapThemeManager? |
null |
External theme manager instance |
onThemeChanged |
Function(String)? |
null |
Callback when theme changes |
selectorBackgroundDecoration |
BoxDecoration? |
null |
Custom background decoration for selector |
ThemeSelectorWidget Parameters #
| Parameter | Type | Default | Description |
|---|---|---|---|
onThemeChanged |
Future<void> Function(String) |
Required | Callback when theme is selected |
layout |
ThemeSelectorLayout |
dropdown |
Layout style (dropdown or horizontalList) |
style |
ThemeSelectorStyle? |
null |
Custom styling for the selector |
showLabels |
bool |
true |
Whether to show theme names |
enabled |
bool |
true |
Whether the selector is interactive |
themeManager |
MapThemeManager? |
null |
External theme manager instance |
customBuilder |
CustomBuilder? |
null |
Custom builder for complete UI control |
customAssetPaths |
List<String>? |
null |
Additional custom theme asset paths |
MapThemeManager Properties #
| Property | Type | Description |
|---|---|---|
currentTheme |
MapStyleTheme |
Currently selected predefined theme |
currentStyleJson |
String |
Current map style JSON string |
currentThemeName |
String? |
Name of current theme (including custom) |
isInitialized |
bool |
Whether the manager has been initialized |
isLoading |
bool |
Whether a theme change operation is in progress |
error |
String? |
Current error message, null if no error |
allThemes |
Map<String, String> |
All available themes (name -> asset path) |
MapThemeManager Methods #
| Method | Parameters | Returns | Description |
|---|---|---|---|
initialize() |
customAssetPaths: List<String>? |
Future<void> |
Initialize the manager and load themes |
setTheme() |
theme: String or MapStyleTheme |
Future<void> |
Change to specified theme |
dispose() |
- | void |
Clean up resources |
ThemeSelectorStyle Properties #
| Property | Type | Default | Description |
|---|---|---|---|
backgroundColor |
Color |
Colors.grey[200] |
Background color for unselected items |
selectedBackgroundColor |
Color |
Colors.blue |
Background color for selected item |
textColor |
Color |
Colors.black |
Text color for unselected items |
selectedTextColor |
Color |
Colors.white |
Text color for selected item |
borderRadius |
double |
8.0 |
Border radius for selector items |
padding |
EdgeInsets |
EdgeInsets.all(8.0) |
Internal padding for items |
margin |
EdgeInsets |
EdgeInsets.all(2.0) |
External margin for items |
elevation |
double |
1.0 |
Shadow elevation for items |
Contributing #
We welcome contributions! Please see our Contributing Guide for details.
Development Setup #
-
Fork and Clone
git clone https://github.com/Captured-Heart/map_themes.git cd map_themes -
Install Dependencies
flutter pub get cd example && flutter pub get -
Run Tests
flutter test -
Run Example
cd example flutter run
Contributing Guidelines #
- Code Style: Follow Dart's official style guide and use
flutter format - Testing: Maintain test coverage above 90% - add tests for new features
- Documentation: Update documentation for API changes
- Commit Messages: Use conventional commits (feat:, fix:, docs:, etc.)
Also, look at our Contributing guidelines
Reporting Issues #
When reposting an issue, provide us with additional information such as:
- Flutter version and platform
- Minimal reproduction code
- Expected vs actual behavior
- Relevant error messages or logs
License #
This project is licensed under the MIT License - see the LICENSE file for details.
More Information #
- Documentation: Usage Article
- Issues: GitHub Issues
- Examples: Check out the
/examplefolder for comprehensive usage examples
Related Packages #
- google_maps_flutter - Google Maps widget for Flutter
- shared_preferences - Platform-agnostic persistent storage
Built with 💜 by Nkpozi Marcel Kelechi (X: @Captured-Heart)
