i wanted to select color from a dialogColor and change my apps color (appBar & Buttons) then i use this package flutter_material_color_picker from pub dev
you can see my code here:
import 'dart:math';
import 'package:animated_theme_switcher/animated_theme_switcher.dart';
import 'package:appservice/flavors.dart';
import 'package:appservice/helper/dbhelper.dart';
import 'package:appservice/models/localappconfig.dart';
import 'package:appservice/pages/home_page.dart';
import 'package:appservice/services/createtable_services.dart';
import 'package:appservice/widgets/common_snackbar.dart';
import 'package:appservice/widgets/settings/settings_ui_data.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_material_color_picker/flutter_material_color_picker.dart';
import 'package:line_awesome_flutter/line_awesome_flutter.dart';
import 'package:progress_dialog/progress_dialog.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../helper/helper.dart';
import '../sqliteProvider/userappconfig_provider.dart';
import '../style/style.dart';
import '../utils/uidata.dart';
class SettingPage extends StatefulWidget {
final String accountName;
final bool reception;
const SettingPage({Key key, this.accountName, this.reception})
: super(key: key);
@override
_SettingPageState createState() => _SettingPageState();
}
class _SettingPageState extends State<SettingPage> {
ProgressDialog prDialog;
Color _shadeColor = Colors.orange[400];
Color _tempShadeColor;
ColorSwatch _tempMainColor;
ColorSwatch _mainColor = Colors.deepOrange;
@override
void initState() {
super.initState();
initData();
}
@override
Widget build(BuildContext context) {
// ScreenUtil.init(context, height: 896, width: 414, allowFontScaling: false);
return ThemeSwitchingArea(
child: Builder(
builder: (context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
centerTitle: true,
title: Text(
F.companyInfo.appCompanyName,
),
),
body: Column(
children: <Widget>[
SizedBox(height: 30.h),
header(),
Expanded(
child: ListView(
children: <Widget>[
widget.reception
? _widgetGetDataFromSazmani(context)
: SizedBox(),
_widgetThemeColor(context),
_widgetFontSize(),
_widgetLogout(context),
colorChange(),
],
),
)
],
),
);
},
),
);
}
Future<void> initData() async {
prDialog = new ProgressDialog(context,
type: ProgressDialogType.Normal, isDismissible: false);
prDialog.style(
message: 'چند لحظه صبر نمایید ',
borderRadius: 10.0,
backgroundColor: Colors.white,
elevation: 10.0,
insetAnimCurve: Curves.easeInOut,
progressTextStyle: Style.styleTextBlack(TEXT_SIZE_22, FontWeight.w400),
messageTextStyle: Style.styleTextBlack(TEXT_SIZE_30, FontWeight.w400),
);
}
Widget header() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(width: 40.w),
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Directionality(
textDirection: TextDirection.rtl, child: HomePage())),
);
},
child: Icon(
LineAwesomeIcons.arrow_right,
size: ScreenUtil().setSp(50),
),
),
profileInfo(),
themeSwitcher(),
SizedBox(width: 40.w),
],
);
}
Widget profileInfo() {
return Expanded(
child: Column(
children: <Widget>[
Container(
height: 150.h,
width: 165.w,
margin: EdgeInsets.only(top: 55.h),
child: Stack(
children: <Widget>[
CircleAvatar(
radius: 80,
backgroundImage: AssetImage('assets/images/admin.png'),
),
],
),
),
SizedBox(height: 40.h),
Text(widget.accountName,
style: Style.styleTextBlack(TEXT_SIZE_24, FontWeight.w700)),
SizedBox(height: 60.h),
Container(
height: 70.h,
width: 300.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Theme.of(context).accentColor,
),
child: widgetDownloadApk(),
),
SizedBox(height: 35.h),
],
),
);
}
Widget _widgetGetDataFromSazmani(BuildContext context) {
return InkWell(
onTap: () {
_getdata(context);
},
child: _widgetContent("دریافت اطلاعات پذیرش", LineAwesomeIcons.upload),
);
}
Future<void> _getdata(BuildContext context) async {
await Helper.isOnline().then((isOnline) async {
if (isOnline) {
prDialog.show();
bool result = false;
double _netserverversion = 0;
_netserverversion = await TableService.getVersion();
DbHelper dbHelper = new DbHelper();
var map = await dbHelper.getItem('LocalAppConfig');
LocalAppConfig appConfig = new LocalAppConfig.fromMap(map);
if (appConfig != null && appConfig.version == 0) {
result = await Helper.getDataSazmaniUntilEnd(_netserverversion);
} else if (appConfig != null &&
appConfig.version != _netserverversion) {
await TableService.getAlterTable().then((_) async {
result = await Helper.getDataSazmaniUntilEnd(_netserverversion);
});
} else {
result = await Helper.getDataSazmaniUntilEnd(_netserverversion);
}
if (!result) if (prDialog.isShowing()) prDialog.hide();
} else
FlushbarHelper.createInformation(
context: context,
message: "عدم ارتباط با سرور ،مجددا اقدام نمایید.",
title: "توجه");
});
}
Widget widgetDownloadApk() {
return InkWell(
onTap: _launchURL,
child: Row(
children: <Widget>[
SizedBox(width: 45.w),
Text(
"بروز رسانی ",
style: Style.styleTextBlack(TEXT_SIZE_24, FontWeight.w700),
),
SizedBox(width: 80.w),
Icon(
Icons.update_outlined,
size: 40.w,
),
],
),
);
}
_launchURL() async {
String url = F.companyInfo.urlDownload +
'WebApiB2BDotCore/UploadedFiles/Apk/b2bsorooshan.apk?${Random().nextInt(10000)}';
if (await canLaunch(url)) {
await launch(url);
}
}
Widget _widgetLogout(BuildContext context) {
return Container(
child: InkWell(
onTap: () {
Helper.onConfirmEasyDialog(
context,
'خروج',
'آیا از خروج از حساب کاربری اطمینان دارید؟',
_logout,
_cancel(context));
},
child: _widgetContent(
"خروج از حساب کاربری", LineAwesomeIcons.alternate_sign_out),
),
);
}
_logout() {
UserAppConfigProvider configProvider = UserAppConfigProvider();
configProvider.logOutUser(1, true).then((value) {
Helper.onExit();
});
}
_cancel(BuildContext context) => Navigator.of(context).pop(true);
Widget _widgetThemeColor(BuildContext context) {
return InkWell(
onTap: _openColorPicker,
child: _widgetContent(
" تغییر رنگ برنامه ", LineAwesomeIcons.paint_roller));
}
Widget _widgetFontSize() {
return InkWell(
onTap: () {},
child: _widgetContent(
" تغییر سایز فونت ", LineAwesomeIcons.alternate_pencil),
);
}
Widget _widgetContent(String title, IconData icon) {
return Container(
height: 90.h,
margin: EdgeInsets.symmetric(
horizontal: 60.w,
).copyWith(
bottom: 40.h,
),
padding: EdgeInsets.symmetric(
horizontal: 50.w,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Theme.of(context).backgroundColor,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(title,
style: Style.styleTextBlack(TEXT_SIZE_24, FontWeight.w700)),
Icon(
icon,
size: 30,
),
// Spacer(),
],
),
);
}
Widget themeSwitcher() {
return ThemeSwitcher(
builder: (context) {
return AnimatedCrossFade(
duration: Duration(milliseconds: 200),
crossFadeState:
ThemeProvider.of(context).brightness == Brightness.dark
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
firstChild: GestureDetector(
onTap: () =>
ThemeSwitcher.of(context).changeTheme(theme: kLightTheme),
child: Icon(
LineAwesomeIcons.sun,
size: ScreenUtil().setSp(50),
),
),
secondChild: GestureDetector(
onTap: () =>
ThemeSwitcher.of(context).changeTheme(theme: kDarkTheme),
child: Icon(
LineAwesomeIcons.moon,
size: ScreenUtil().setSp(50),
),
),
);
},
);
}
ThemeData selectedColorTheme(BuildContext context) => ThemeData(
accentColor: _shadeColor,
appBarTheme: ThemeData.dark().appBarTheme.copyWith(color: _shadeColor),
);
void _openColorPicker() async {
_openDialog(
"Color picker",
MaterialColorPicker(
selectedColor: _shadeColor,
onColorChange: (color) {
_tempShadeColor = Color(color.value);
},
onMainColorChange: (color) {
_tempMainColor = color;
},
),
);
}
void _openDialog(String title, Widget content) {
showDialog(
context: context,
builder: (_) {
return AlertDialog(
contentPadding: const EdgeInsets.all(6.0),
title: Text(title),
content: content,
actions: [
FlatButton(
child: Text('CANCEL'),
onPressed: Navigator.of(context).pop,
),
GestureDetector(
child: Text('SUBMIT'),
onTap: () {
Navigator.of(context).pop();
_mainColor = _tempMainColor;
_shadeColor = _tempShadeColor;
},
),
],
);
},
);
}
Widget colorChange() {
return ThemeSwitcher(
builder: (context) {
return Container(
child: RaisedButton(
child: Text(" change color "),
onPressed: () {
ThemeSwitcher.of(context).changeTheme(
theme: selectedColorTheme(context),
);
},
),
);
},
);
}
}
when i click the " change color " Button , this error " The getter 'dx' was called on null. Receiver: null Tried calling: dx " occur in my debug consol Can you help me ?????
if you need to see all of the debugconsul ,you can see here:
[38;5;248m════════ Exception caught by rendering library ═════════════════════════════════[39;49m
[38;5;244mThe following NoSuchMethodError was thrown during paint():[39;49m
The getter 'dx' was called on null.
Receiver: null
Tried calling: dx
[38;5;244mThe relevant error-causing widget was[39;49m
[38;5;248mThemeSwitchingArea[39;49m
lib\pages\setting_page.dart
[38;5;244mWhen the exception was thrown, this was the stack[39;49m
[38;5;244m#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)[39;49m
[38;5;244m#1 ThemeSwitcherCircleClipper._calcMaxRadius[39;49m
package:animated_theme_switcher/…/clippers/theme_switcher_circle_clipper.dart
[38;5;244m#2 ThemeSwitcherCircleClipper.getClip[39;49m
package:animated_theme_switcher/…/clippers/theme_switcher_circle_clipper.dart
[38;5;244m#3 ThemeSwitcherClipperBridge.getClip[39;49m
package:animated_theme_switcher/…/clippers/theme_switcher_clipper_bridge.dart
[38;5;244m#4 _RenderCustomClip._updateClip[39;49m
package:flutter/…/rendering/proxy_box.dart
[38;5;244m...[39;49m
[38;5;244mThe following RenderObject was being processed when the exception was fired: RenderClipPath#ac13c relayoutBoundary=up4[39;49m
[38;5;244mRenderObject: RenderClipPath#ac13c relayoutBoundary=up4[39;49m
[38;5;244mneeds compositing[39;49m
[38;5;244mparentData: not positioned; offset=Offset(0.0, 0.0) (can use size)[39;49m
[38;5;244mconstraints: BoxConstraints(0.0<=w<=411.4, 0.0<=h<=621.4)[39;49m
[38;5;244msize: Size(411.4, 621.4)[39;49m
[38;5;244mchild: RenderPhysicalModel#22ceb relayoutBoundary=up5 NEEDS-PAINT[39;49m
[38;5;244mneeds compositing[39;49m
[38;5;244mparentData: <none> (can use size)[39;49m
[38;5;244mconstraints: BoxConstraints(0.0<=w<=411.4, 0.0<=h<=621.4)[39;49m
[38;5;244mlayer: PhysicalModelLayer#b27dd DETACHED[39;49m
[38;5;244mengine layer: PhysicalShapeEngineLayer#bbffb[39;49m
[38;5;244melevation: 0.0[39;49m
[38;5;244mcolor: Color(0xffffffff)[39;49m
[38;5;244msize: Size(411.4, 621.4)[39;49m
[38;5;244melevation: 0.0[39;49m
[38;5;244mcolor: Color(0xfffafafa)[39;49m
[38;5;244mshadowColor: Color(0xfffafafa)[39;49m
[38;5;244mshape: BoxShape.rectangle[39;49m
[38;5;244mborderRadius: BorderRadius.zero[39;49m
[38;5;244mchild: _RenderInkFeatures#f8cf2 relayoutBoundary=up6 NEEDS-PAINT[39;49m
[38;5;244mneeds compositing[39;49m
[38;5;244mparentData: <none> (can use size)[39;49m
[38;5;244mconstraints: BoxConstraints(0.0<=w<=411.4, 0.0<=h<=621.4)[39;49m
[38;5;244msize: Size(411.4, 621.4)[39;49m
[38;5;244mchild: RenderCustomMultiChildLayoutBox#a6e7f relayoutBoundary=up7 NEEDS-PAINT[39;49m
[38;5;244mneeds compositing[39;49m
[38;5;244mparentData: <none> (can use size)[39;49m
[38;5;244mconstraints: BoxConstraints(0.0<=w<=411.4, 0.0<=h<=621.4)[39;49m
[38;5;244msize: Size(411.4, 621.4)[39;49m
[38;5;244mchild 1: RenderFlex#79c94 relayoutBoundary=up8 NEEDS-PAINT[39;49m
[38;5;244mneeds compositing[39;49m
[38;5;244mparentData: offset=Offset(0.0, 80.0); id=_ScaffoldSlot.body (can use size)[39;49m
[38;5;244mconstraints: BoxConstraints(0.0<=w<=411.4, 0.0<=h<=541.4)[39;49m
[38;5;244msize: Size(411.4, 541.4)[39;49m
[38;5;244mdirection: vertical[39;49m
[38;5;244mmainAxisAlignment: start[39;49m
[38;5;244mmainAxisSize: max[39;49m
[38;5;244mcrossAxisAlignment: center[39;49m
[38;5;244mverticalDirection: down[39;49m
[38;5;244mchild 2: RenderConstrainedBox#f6e13 relayoutBoundary=up8 NEEDS-PAINT[39;49m
[38;5;244mneeds compositing[39;49m
[38;5;244mparentData: offset=Offset(0.0, 0.0); id=_ScaffoldSlot.appBar (can use size)[39;49m
[38;5;244mconstraints: BoxConstraints(w=411.4, 0.0<=h<=621.4)[39;49m
[38;5;244msize: Size(411.4, 80.0)[39;49m
[38;5;244madditionalConstraints: BoxConstraints(0.0<=w<=Infinity, 0.0<=h<=80.0)[39;49m
[38;5;244mchild 3: RenderStack#38874 relayoutBoundary=up8 NEEDS-PAINT[39;49m
[38;5;244mparentData: offset=Offset(16.0, 605.4); id=_ScaffoldSlot.floatingActionButton (can use size)[39;49m
[38;5;244mconstraints: BoxConstraints(0.0<=w<=411.4, 0.0<=h<=621.4)[39;49m
[38;5;244msize: Size(0.0, 0.0)[39;49m
[38;5;244malignment: centerRight[39;49m
[38;5;244mtextDirection: rtl[39;49m
[38;5;244mfit: loose[39;49m
[38;5;248m════════════════════════════════════════════════════════════════════════════════[39;49m
D/TSBackgroundFetch( 2727): - Background Fetch event received
D/TSBackgroundFetch( 2727): - finish: flutter_background_fetch
D/TSBackgroundFetch( 2727): - jobFinished
ThemeSwitchingArea method is here:
import 'clippers/theme_switcher_clipper_bridge.dart';
import 'clippers/theme_switcher_circle_clipper.dart';
import 'theme_provider.dart';
import 'package:flutter/material.dart';
class ThemeSwitchingArea extends StatefulWidget {
ThemeSwitchingArea({
Key key,
@required this.child,
}) : assert(child != null),
super(key: key);
final Widget child;
@override
_ThemeSwitchingAreaState createState() => _ThemeSwitchingAreaState();
}
class _ThemeSwitchingAreaState extends State<ThemeSwitchingArea>
with SingleTickerProviderStateMixin {
AnimationController _controller;
bool _busy = false;
//one more key to save drawer state
final _globalKey = GlobalKey();
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
}
void _afterLayout(_) {
_oldTheme = ThemeProvider.of(context);
_controller = AnimationController(
vsync: this,
duration: ThemeProvider.instanceOf(context).duration,
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
ThemeData _oldTheme;
Offset _switcherOffset;
@override
Widget build(BuildContext context) {
var theme = ThemeProvider.of(context);
var child;
if (_oldTheme == null || _oldTheme == theme) {
child = _getPage(theme);
} else {
var firstWidget, animWidget;
if (ThemeProvider.instanceOf(context).reverseAnimation) {
firstWidget = _getPage(theme);
animWidget = RawImage(image: ThemeProvider.instanceOf(context).image);
} else {
firstWidget = RawImage(image: ThemeProvider.instanceOf(context).image);
animWidget = _getPage(theme);
}
child = Stack(
children: [
firstWidget,
AnimatedBuilder(
animation: _controller,
child: animWidget,
builder: (_, child) {
return ClipPath(
clipper: ThemeSwitcherClipperBridge(
clipper: ThemeProvider.instanceOf(context).clipper ??
const ThemeSwitcherCircleClipper(),
offset: _switcherOffset,
sizeRate: _controller.value,
),
child: child,
);
},
),
],
);
}
return Material(child: child);
}
Widget _getPage(ThemeData brandTheme) {
return Theme(
key: _globalKey,
data: brandTheme,
child: widget.child,
);
}
void _getSwitcherCoordinates(switcherGlobalKey) {
RenderBox renderObject =
switcherGlobalKey.currentContext.findRenderObject();
final size = renderObject.size;
_switcherOffset = renderObject
.localToGlobal(Offset.zero)
.translate(size.width / 2, size.height / 2);
}
@override
void didUpdateWidget(Widget oldWidget) {
super.didUpdateWidget(oldWidget);
var theme = ThemeProvider.of(context);
if (!_busy && theme != _oldTheme) {
_busy = true;
_getSwitcherCoordinates(
ThemeProvider.instanceOf(context).switcherGlobalKey);
_runAnimation(theme);
}
}
void _runAnimation(ThemeData theme) async {
if (ThemeProvider.instanceOf(context).reverseAnimation) {
await _controller.reverse(from: 1.0);
} else {
await _controller.forward(from: 0.0);
}
setState(() {
_busy = false;
_oldTheme = theme;
});
}
}