How to cancel map marker drag action in Flutter - flutter

Is there a way to return Google maps marker to it's original position after dragging it to a new location? For example, onDragEnd => if (condition) => do something => else => go back to original position...

import 'package:google_maps_place_picker/google_maps_place_picker.dart';
Add This Package and then try this :
import 'package:flutter/material.dart';
import 'package:google_maps_place_picker/google_maps_place_picker.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
// Your api key storage.
import 'keys.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// Light Theme
final ThemeData lightTheme = ThemeData.light().copyWith(
// Background color of the FloatingCard
cardColor: Colors.white,
buttonTheme: ButtonThemeData(
// Select here's button color
buttonColor: Colors.black,
textTheme: ButtonTextTheme.primary,
),
);
// Dark Theme
final ThemeData darkTheme = ThemeData.dark().copyWith(
// Background color of the FloatingCard
cardColor: Colors.grey,
buttonTheme: ButtonThemeData(
// Select here's button color
buttonColor: Colors.yellow,
textTheme: ButtonTextTheme.primary,
),
);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Google Map Place Picker Demo',
theme: lightTheme,
darkTheme: darkTheme,
themeMode: ThemeMode.light,
home: HomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key key}) : super(key: key);
static final kInitialPosition = LatLng(-33.8567844, 151.213108);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
PickResult selectedPlace;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Google Map Place Picer Demo"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text("Load Google Map"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return PlacePicker(
apiKey: APIKeys.apiKey,
initialPosition: HomePage.kInitialPosition,
useCurrentLocation: true,
selectInitialPosition: true,
//usePlaceDetailSearch: true,
onPlacePicked: (result) {
selectedPlace = result;
Navigator.of(context).pop();
setState(() {});
},
//forceSearchOnZoomChanged: true,
//automaticallyImplyAppBarLeading: false,
//autocompleteLanguage: "ko",
//region: 'au',
//selectInitialPosition: true,
// selectedPlaceWidgetBuilder: (_, selectedPlace, state, isSearchBarFocused) {
// print("state: $state, isSearchBarFocused: $isSearchBarFocused");
// return isSearchBarFocused
// ? Container()
// : FloatingCard(
// bottomPosition: 0.0, // MediaQuery.of(context) will cause rebuild. See MediaQuery document for the information.
// leftPosition: 0.0,
// rightPosition: 0.0,
// width: 500,
// borderRadius: BorderRadius.circular(12.0),
// child: state == SearchingState.Searching
// ? Center(child: CircularProgressIndicator())
// : RaisedButton(
// child: Text("Pick Here"),
// onPressed: () {
// // IMPORTANT: You MUST manage selectedPlace data yourself as using this build will not invoke onPlacePicker as
// // this will override default 'Select here' Button.
// print("do something with [selectedPlace] data");
// Navigator.of(context).pop();
// },
// ),
// );
// },
// pinBuilder: (context, state) {
// if (state == PinState.Idle) {
// return Icon(Icons.favorite_border);
// } else {
// return Icon(Icons.favorite);
// }
// },
);
},
),
);
},
),
selectedPlace == null ? Container() : Text(selectedPlace.formattedAddress ?? ""),
],
),
));
}
}

Related

How to change theme in Flutter?

So I'm trying here to get the current theme, if it's light or dark.
So I can change widget color accordingly..
However, it doesn't work, I used if statment to know when it's dark mode..
but it's always False ..
This is the code.. btw it switch between dark & light theme..
but when i try to get current theme.. even if the theme changed to dark..
the if statments always show false...
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
bool darkModeOn = MediaQuery.of(context).platformBrightness == Brightness.dark;
Color containerColor;
if (darkModeOn == true) {
containerColor = Colors.blueGrey;
print("----------------");
print("dark mode ON");
print("----------------");
} else {
containerColor = Colors.deepPurple;
print("LIGHT mode ON");
}
return Scaffold(
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
//----switch theme---
currentTheme.switchTheme();
},
label: Text(
"Switch theme",
style: TextStyle(
),
),
icon: Icon(Icons.color_lens_outlined),
),
appBar: AppBar(
title: Text("DarkXLight"),
),
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(child: Container(
color: containerColor,
),
),
Expanded(child: Container(
color: Colors.amber,
),
),
],
),
),
);
}
}
You can't switch themes like that. You will need to handle the logic in the MaterialApp otherwise
MediaQuery.of(context).platformBrightness == Brightness.dark;
will always return true/false based on what was provided to the MaterialApp.themeMode.
Here's a sample code to get started. I used ValueListenableBuilder but you can also use provider.
Full code:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
final ValueNotifier<ThemeMode> _notifier = ValueNotifier(ThemeMode.light);
#override
Widget build(BuildContext context) {
return ValueListenableBuilder<ThemeMode>(
valueListenable: _notifier,
builder: (_, mode, __) {
return MaterialApp(
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
themeMode: mode, // Decides which theme to show, light or dark.
home: Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () => _notifier.value = mode == ThemeMode.light ? ThemeMode.dark : ThemeMode.light,
child: Text('Toggle Theme'),
),
),
),
);
},
);
}
}
So, I was able to solve my problem..
I will put the code so if someone faced the same issue..
I simply, changed the way I used to switch themes. It was wrong..
However, here I'm posting the Correct way & this way solved the problem..
MAIN PAGE
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:practice_darkmode/theme_provider.dart';
import 'package:provider/provider.dart';
import 'MyHomePage.dart';
Future<void> main() async {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => ThemeProvider(),
builder: (context, _) {
final themeProvider = Provider.of<ThemeProvider>(context);
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: MyThemes.lightTheme,
darkTheme: MyThemes.darkTheme,
themeMode: themeProvider.themeMode,
home: MyHomePage(),
);
},
);
}
}
Theme Provider class
import 'package:flutter/material.dart';
//---This to switch theme from Switch button----
class ThemeProvider extends ChangeNotifier {
//-----Store the theme of our app--
ThemeMode themeMode = ThemeMode.dark;
//----If theme mode is equal to dark then we return True----
//-----isDarkMode--is the field we will use in our switch---
bool get isDarkMode => themeMode == ThemeMode.dark;
//---implement ToggleTheme function----
void toggleTheme(bool isOn) {
themeMode = isOn ? ThemeMode.dark : ThemeMode.light;
//---notify material app to update UI----
notifyListeners();
}
}
//---------------Themes settings here-----------
class MyThemes {
//-------------DARK THEME SETTINGS----
static final darkTheme = ThemeData(
scaffoldBackgroundColor: Colors.black45,
// colorScheme: ColorScheme.dark(),
);
//-------------light THEME SETTINGS----
static final lightTheme = ThemeData(
scaffoldBackgroundColor: Colors.white,
//colorScheme: ColorScheme.light(),
);
}
Change Theme button widget class ( this is to create a switch button)
import 'package:flutter/material.dart';
import 'package:practice_darkmode/theme_provider.dart';
import 'package:provider/provider.dart';
class ChangeThemeButtonWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
//----First we want to get the theme provider----
final themeProvider = Provider.of<ThemeProvider>(context);
return Switch.adaptive(
//---isDarkMode to return if its dark or not--true or false--
value: themeProvider.isDarkMode,
onChanged: (value) {
final provider = Provider.of<ThemeProvider>(context, listen: false);
provider.toggleTheme(value);
},
activeColor: themeProvider.isDarkMode ? Colors.purple : Colors.green,
);
}
}
Home Page
import 'package:flutter/material.dart';
import 'package:practice_darkmode/theme_provider.dart';
import 'package:provider/provider.dart';
import 'ChangeThemeButtonWidget.dart';
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
dynamic text;
dynamic textColor;
dynamic appBarColor;
dynamic btnColor;
dynamic appBarTextColor;
if (Provider.of<ThemeProvider>(context).themeMode == ThemeMode.dark) {
text = "IT'S DARK ";
textColor = Colors.cyanAccent;
appBarColor = Colors.black;
btnColor = Colors.deepPurple;
appBarTextColor = Colors.cyanAccent;
} else if (Provider.of<ThemeProvider>(context).themeMode == ThemeMode.light) {
text = "IT'S LIGHT ";
textColor = Colors.red;
appBarColor = Colors.red;
btnColor = Colors.red;
appBarTextColor = Colors.white;
}
return Scaffold(
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
},
label: Text(
"Switch theme",
style: TextStyle(
),
),
icon: Icon(Icons.color_lens_outlined),
backgroundColor: btnColor,
),
appBar: AppBar(
title: Text("DarkXLight", style: TextStyle(color: appBarTextColor),),
backgroundColor: appBarColor,
actions: [
ChangeThemeButtonWidget(),
],
),
body: Container(
child: Center(
child: Text(
"$text!",
style: (
TextStyle(
fontSize: 27,
color: textColor,
)
),
),
),
),
);
}
}
Below code will to change theme via Icon Button in appBar. Steps:
Create a stateful widget.
Add the following variables:
bool _iconBool = false;
IconData _iconLight = Icons.wb_sunny;
IconData _iconDark = Icons.nights_stay;
Create actions -> IconButton in the appBar as below:
appBar: AppBar(
title: Text("Simple Colregs"),
backgroundColor: Color(0xFF5B4B49).withOpacity(0.8),
actions: [
IconButton(icon: Icon(_iconBool ? _iconDark : _iconLight),
},)
],
), //AppBar
Add Below methods with Light and Dark themes and any custom preference is required:
// light Theme
ThemeData lightThemeData(BuildContext context) {
return ThemeData.light().copyWith(
primaryColor: Color(0xFF5B4B49),
colorScheme: ColorScheme.fromSwatch().copyWith(secondary: Color(0xFF24A751)));
}
// dark Theme
ThemeData darkThemeData(BuildContext context) {
return ThemeData.dark().copyWith(
primaryColor: Color(0xFFFF1D00),
colorScheme: ColorScheme.fromSwatch().copyWith(secondary: Color(0xFF24A751)));
}
Read more about ThemeData Class here.
Under IconButton, create a functionality for the button as below which will toggle the theme:
onPressed: () {
setState(() {
_iconBool = !_iconBool;
});
Finally add under Material App:
theme: _iconBool ? lightThemeData(context) : darkThemeData(context),
That's all, good to go. Hope it helps.
you can use it in initState
bool darkModeOn = brightness == Brightness.dark;
or
var brightness = MediaQuery.of(context).platformBrightness;
bool darkModeOn = brightness == Brightness.dark;

Flutter how to load new screen by tap on navigation bar

I have created a custom bottom navigation bar for my app but I messed up my code. Right now its just shifting screen by true false value. I want to load screen but what I done is simple showing screen in body by bool.
My code
bottomNavigationBar: CustomBottomNavigationBar(
iconList: [
'images/ichome.png',
'images/icservice.png',
'images/icstore.png',
'images/Component 7 – 1#2x.png',
],
iconList2: [
'images/ichomeactive.png',
'images/icserviceactive.png',
'images/icstoreactive.png',
'images/icaccount.png',
],
onChange: (val) {
setState(() {
_selectedItem = val;
print(val);
if (val == 0) {
setState(() {
home = true;
service = false;
shop = false;
account = false;
});
}
if (val == 1) {
home = false;
service = true;
shop = false;
account = false;
}
if (val == 2) {
home = false;
service = false;
shop = true;
account = false;
}
if (val == 3) {
home = false;
service = false;
shop = false;
account = true;
}
});
},
defaultSelectedIndex: 0,
),
You can see on click I am changing bool value and in body show my widget. I know its wrong I do very stupid thing. That's why I need to know how I can load the page instead of just show and hide ? Also I need to show the navigation bar also on each page.
Please refer below code of Navigation bar
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: SettingView(),
);
}
}
class SettingView extends StatefulWidget {
#override
_SettingViewState createState() => _SettingViewState();
}
class _SettingViewState extends State<SettingView> {
final tabs = [DashboardView(), NotificationView(), ProfileView()];
int _currentIndex = 0;
#override
void initState() {
setState(() {});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
toolbarHeight: 40.0,
elevation: 0,
centerTitle: true,
backgroundColor: Colors.blue,
title: Text("Navigation Bar"),
),
bottomNavigationBar: BottomNavigationBar(
backgroundColor: Colors.blue,
currentIndex: _currentIndex,
type: BottomNavigationBarType.fixed,
selectedItemColor: Colors.white,
unselectedItemColor: Colors.white.withOpacity(0.5),
items: [
BottomNavigationBarItem(
icon: InkResponse(
focusColor: Colors.transparent,
hoverColor: Colors.transparent,
highlightColor: Colors.transparent,
child: Container(
padding: EdgeInsets.only(
left: 10,
),
child: Icon(
Icons.dashboard,
),
),
),
title: Padding(padding: EdgeInsets.zero),
backgroundColor: Colors.blue,
),
BottomNavigationBarItem(
icon: Container(
padding: EdgeInsets.only(
right: 10,
),
child: Icon(Icons.notifications),
),
title: Padding(padding: EdgeInsets.zero),
backgroundColor: Colors.blue,
),
BottomNavigationBarItem(
icon: Container(
padding: EdgeInsets.only(
right: 10,
),
child: Icon(Icons.account_box),
),
title: Padding(padding: EdgeInsets.zero),
backgroundColor: Colors.blue,
)
],
onTap: (index) {
setState(() {
_currentIndex = index;
});
},
),
body: tabs[_currentIndex],
);
}
}
/*Dashboard*/
class DashboardView extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text("Dashboard"),
),
);
}
}
/*Notification*/
class NotificationView extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text("Notification"),
),
);
}
}
/*Profile*/
class ProfileView extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text("Profile"),
),
);
}
}
You can do something like that:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'app name',
home: HomeScreen(),
routes: <String, WidgetBuilder>{
'/route1': (BuildContext context) => FirstScreen(),
'/route2': (BuildContext context) => SecondScreen(),
},
);
}
Create reusable navigation bar Widget and for selected content just tell navigator where it needs to bring you:
Navigator.pushNamed(context, '/route1');

How to force show text selection controls?

I need to show text selection controls on:
setState( () {
textController.selection = TextSelection(baseOffset: 0, extentOffset: textController.text.length);
});
But it did not appear on the screen. So, how to force flutter show the cut/copy/paste menu?
I hope it helps you.
You can use Selectable Widget.
https://www.youtube.com/watch?v=ZSU3ZXOs6hc&list=PLjxrf2q8roU23XGwz3Km7sQZFTdB996iG&index=56
Second suggestion
When I test with below code, it works well.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: "App",
theme: new ThemeData(primarySwatch: Colors.amber),
home: Test(),
);
}
}
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
TextEditingController controller = new TextEditingController(text: 'Kevin A');
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: "Title",
theme: new ThemeData(primarySwatch: Colors.amber),
home: Scaffold(
body: SafeArea(
child: TextField(
controller: controller,
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
controller.selection = new TextSelection(
baseOffset: 0,
extentOffset: controller.text.length,
);
showMenu(
context: context,
// TODO: Position dynamically based on cursor or textfield
position: RelativeRect.fromLTRB(0.0, 300.0, 300.0, 0.0),
items: [
PopupMenuItem(
child: Row(
children: <Widget>[
// TODO: Dynamic items / handle click
PopupMenuItem(
child: Text(
"Paste",
style: Theme.of(context)
.textTheme
.body2
.copyWith(color: Colors.red),
),
),
PopupMenuItem(
child: Text("Select All"),
),
],
),
),
],
);
},
child: Icon(Icons.navigation),
backgroundColor: Colors.green,
),
),
);
}
}

SharedPreferences value needs to be reset every other time

So,in this included flutter code,I am using a if loop in checkFirstSeen() to set my seen boolean to a value. This will then set my SharedPreferences value for the app. However,on every other restart of the application,I have to press the GotoHomepage button as opposed to it working automatically based off of the SharedPreferences value that was set. How can I fix this?
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:audiotest/UI/homepage.dart';
void main() => runApp(new MaterialApp(
title: "TestAudio",
initialRoute: '/intro_route',
routes: {
'/intro_route': (context) => IntroScreen(),
'/homescreen_route': (context) => MainPersistentTabBar2(),
}));
class IntroScreen extends StatefulWidget {
#override
IntroScreenstate2 createState() => IntroScreenstate2();
}
class IntroScreenstate2 extends State<IntroScreen> {
bool buttonstatus = true;
Future checkFirstSeen() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool seen = (prefs.getBool('seen') ?? false);
prefs.setBool('seen', false);
if (buttonstatus == false) {
prefs.setBool('seen', true);
}
if (seen == true) {
Navigator.pushNamed(context, '/homescreen_route');
} else {
}
}
#override
void initState() {
super.initState();
new Timer(new Duration(milliseconds: 1), () {
checkFirstSeen();
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Text('This is the placeholder for the TOS'),
new MaterialButton(
child: new Text('Go to Home Page'),
onPressed: () {
buttonstatus = false;
checkFirstSeen();
//Navigator.pushNamed(context, '/homescreen_route');
},
)
],
),
),
);
}
}
You can copy paste run full code below
You can get seen in main() and check seen directly in initialRoute
code snippet
bool seen;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences prefs = await SharedPreferences.getInstance();
seen = await prefs.getBool("seen");
await prefs.setBool("seen", true);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
...
initialRoute:
seen == false || seen == null ? "/intro_route" : "/homescreen_route",
routes: {
'/homescreen_route': (context) => MainPersistentTabBar2(
title: "demo",
),
"/intro_route": (context) => IntroScreen(),
},
);
}
}
working demo
full code
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter/services.dart';
bool seen;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences prefs = await SharedPreferences.getInstance();
seen = await prefs.getBool("seen");
await prefs.setBool("seen", true);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute:
seen == false || seen == null ? "/intro_route" : "/homescreen_route",
routes: {
'/homescreen_route': (context) => MainPersistentTabBar2(),
"/intro_route": (context) => IntroScreen(),
},
);
}
}
class MainPersistentTabBar2 extends StatefulWidget {
#override
MainPersistentTabBarState2 createState() => MainPersistentTabBarState2();
}
class MainPersistentTabBarState2 extends State<MainPersistentTabBar2> {
Brightness brightness;
#override
Widget build(BuildContext context) {
return new MaterialApp(
theme: new ThemeData(
primarySwatch: Colors.blue,
brightness: Brightness.dark,
),
home: DefaultTabController(
length: 4,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
isScrollable: true,
tabs: <Widget>[
Container(
width: 90,
height: 40,
alignment: Alignment.center,
child: Text("Session 1"),
),
Container(
width: 90,
height: 40,
alignment: Alignment.center,
child: Text("Session 2"),
),
Container(
width: 90,
height: 40,
alignment: Alignment.center,
child: Text("Session 3"),
),
Container(
width: 90,
height: 40,
alignment: Alignment.center,
child: Text("Session 4"),
),
],
),
title: Text('Own The Tone '),
/*actions: <Widget>[
PopupMenuButton<String>(
onSelected: _choiceAction,
itemBuilder: (BuildContext context) {
return Constants.choices.map((String choice) {
return PopupMenuItem<String>(
value: choice,
child: Text(choice),
);
}).toList();
},
)
],*/
),
body: TabBarView(
children: <Widget>[
FirstScreen(),
Center(child: Text("Sample two")),
Center(child: Text("Sample three")),
Center(child: Text("Sample four")),
],
),
),
),
);
}
// This area controls the settings menus
/* void _choiceAction(String choice) {
if (choice == Constants.about) {
Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('About the app'),
),
body: new PageView(),
);
}));
} else if (choice == Constants.settings) {
Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Settings'),
),
body: new Container(
child: Center(
child: Text('placeholder'),
)),
);
}));
}
}*/
}
class FirstScreen extends StatefulWidget {
#override
_FirstScreenState createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("First Screen"),
),
body: Text("First"));
}
}
class IntroScreen extends StatefulWidget {
#override
_IntroScreenState createState() => _IntroScreenState();
}
class _IntroScreenState extends State<IntroScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Introduction"),
),
body: Text("Intro"));
}
}

Flutter: How to user a DropDownButton with provider?

I have a dropDownButton where i select the theme for the entire app. I have tried two ways of actually trying to fix this. First one was using the commented line "Provider.of(context).toggleTheme();" in the "setState". Had to make the "listen" option "false" as advised in another thread but it was not working. And the second one was to just call the "toggleTheme()" inside the "Themes.dart" in order to notify listeners that way. What would be a correct implementation for a Dropdownbutton like this.
MainScreen.dart
import 'package:flutter/material.dart';
import 'package:thisismylastattempt/Misc/Themes.dart';
import 'package:provider/provider.dart';
class MainScreen extends StatefulWidget {
static const id = "main_screen";
#override
_MainScreenState createState() => _MainScreenState();
}
class ThemeOptions{
final Color themeColor;
final ThemeType enumTheme;
ThemeOptions({this.themeColor, this.enumTheme});
void callParentTheme(){
ThemeModel().changeEnumValue(enumTheme);
}
}
class _MainScreenState extends State<MainScreen> {
List<ThemeOptions> themes = [
ThemeOptions(themeColor: Colors.teal, enumTheme: ThemeType.Teal),
ThemeOptions(themeColor: Colors.green, enumTheme: ThemeType.Green),
ThemeOptions(themeColor: Colors.lightGreen, enumTheme: ThemeType.LightGreen),
];
ThemeOptions dropdownValue;
#override
void initState() {
dropdownValue = themes[0];
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('MainScreen'),
),
body: Column(
children: <Widget>[
Container(
child: DropdownButton<ThemeOptions>(
value: dropdownValue,
icon: Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: TextStyle(
color: Colors.deepPurple
),
underline: Container(
height: 0.0,
color: Colors.deepPurpleAccent,
),
onChanged: (ThemeOptions newValue) {
setState(() {
dropdownValue = newValue;
dropdownValue.callParentTheme();
print(newValue.themeColor);
//Provider.of<ThemeModel>(context).toggleTheme();
});
},
items: themes.map((ThemeOptions colorThemeInstance) {
return DropdownMenuItem<ThemeOptions>(
value: colorThemeInstance,
child: CircleAvatar(
backgroundColor: colorThemeInstance.themeColor,
),
);
})
.toList(),
),
),
SizedBox(height: 20.0,),
],
),
);
}
}
Themes.dart
import 'package:flutter/material.dart';
enum ThemeType {Teal, Green, LightGreen}
ThemeData tealTheme = ThemeData.light().copyWith(
primaryColor: Colors.teal.shade700,
appBarTheme: AppBarTheme(
color: Colors.teal.shade700,
),
);
ThemeData greenTheme = ThemeData.light().copyWith(
primaryColor: Colors.green.shade700,
appBarTheme: AppBarTheme(
color: Colors.green.shade700,
),
);
ThemeData lightGreenTheme = ThemeData.light().copyWith(
primaryColor: Colors.lightGreen.shade700,
appBarTheme: AppBarTheme(
color: Colors.lightGreen.shade700,
),
);
class ThemeModel extends ChangeNotifier {
ThemeData currentTheme = tealTheme;
ThemeType _themeType = ThemeType.Teal;
toggleTheme() {
if (_themeType == ThemeType.Teal) {
currentTheme = tealTheme;
_themeType = ThemeType.Teal;
print('teal');
notifyListeners();
}
if (_themeType == ThemeType.Green) {
currentTheme = greenTheme;
_themeType = ThemeType.Green;
print('green');
notifyListeners();
}
if (_themeType == ThemeType.LightGreen) {
currentTheme = lightGreenTheme;
_themeType = ThemeType.LightGreen;
print('lightGreen');
notifyListeners();
}
}
ThemeType getEnumValue(){
return _themeType;
}
void changeEnumValue(ThemeType newThemeType){
_themeType = newThemeType;
toggleTheme();
}
}
main.dart
void main() => runApp(ChangeNotifierProvider<ThemeModel>(
create: (BuildContext context) => ThemeModel(), child: MyApp()));
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamProvider<User>.value(
value: AuthService().user,
child: MaterialApp(
theme: Provider.of<ThemeModel>(context).currentTheme,
title: 'Flutter Demo',
initialRoute: MainScreen.id,
routes: {
Wrapper.id: (context) => Wrapper(),
LoginPage.id: (context) => LoginPage(),
Registration.id: (context) => Registration(),
MainScreen.id: (context) => MainScreen(),
SwitchAuthenticationState.id: (context) =>
SwitchAuthenticationState(),
},
),
);
}
}
I managed to make it work by calling the changeEnumValue from the Provider in the callParentTheme of your ThemeOptionsclass :
class ThemeOptions {
final Color themeColor;
final ThemeType enumTheme;
ThemeOptions({this.themeColor, this.enumTheme});
// void callParentTheme() {
// ThemeModel().changeEnumValue(enumTheme);
void callParentTheme(context) {
Provider.of<ThemeModel>(context, listen: false).changeEnumValue(enumTheme);
}
call the method with the context in your DropDown onChanged method :
onChanged: (ThemeOptions newValue) {
setState(() {
dropdownValue = newValue;
dropdownValue.callParentTheme(context);
print(newValue.themeColor);
});
},
Hope It's help