点击手势检测器后,Flutter UI 不会刷新
Flutter UI is not refreshing once tap the gesture detector
我实现了一个介绍屏幕,用户可以在开始时设置应用程序的主题。
一切正常,但我面临的唯一问题是选择时 BoxDecoration 切换颜色。仅当我从浅色模式切换到系统默认值时(当系统默认值处于浅色模式时,它在暗色模式下工作正常)才会出现此问题,反之亦然。而且我在调试时没有遇到任何错误。我还附上了一段视频 link.
IntroScreen.dart
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:mint/helpers/config.dart';
import 'package:mint/ui/animations/showUp.dart';
import 'package:eva_icons_flutter/eva_icons_flutter.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
enum ThemeSelected { System, Light, Dark }
class IntroTheme extends StatefulWidget {
const IntroTheme({Key? key}) : super(key: key);
@override
_IntroThemeState createState() => _IntroThemeState();
}
class _IntroThemeState extends State<IntroTheme> {
// Currently Selected Theme
ThemeSelected? theme;
final MyTheme currentTheme = GetIt.I<MyTheme>();
@override
void initState() {
super.initState();
theme = ThemeSelected.System;
}
@override
Widget build(BuildContext context) {
void checkTheme() {
if (currentTheme.currentTheme() == ThemeMode.system) {
theme = ThemeSelected.System;
} else if (currentTheme.currentTheme() == ThemeMode.light) {
theme = ThemeSelected.Light;
} else if (currentTheme.currentTheme() == ThemeMode.dark) {
theme = ThemeSelected.Dark;
}
}
checkTheme();
return SafeArea(
child: Stack(
alignment: Alignment.center,
children: [
ShowUpTransition(
duration: const Duration(milliseconds: 600),
forward: true,
slideSide: SlideFromSlide.LEFT,
child: Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
const Padding(
padding: EdgeInsets.only(right: 8),
child: AnimatedSwitcher(
duration: Duration(milliseconds: 300),
child: Icon(EvaIcons.colorPaletteOutline,
size: 40, color: Colors.red),
),
),
RichText(
textAlign: TextAlign.center,
text: TextSpan(
style: TextStyle(
fontSize: 22,
fontFamily: 'Product Sans',
fontWeight: FontWeight.w600,
color:
Theme.of(context).textTheme.bodyText1?.color),
children: [
const TextSpan(text: "App "),
TextSpan(
text: AppLocalizations.of(context)!
.intro_labelAppCustomization,
style: TextStyle(
color:
Theme.of(context).colorScheme.secondary,
fontWeight: FontWeight.w600))
]),
),
],
),
),
),
),
ShowUpTransition(
slideSide: SlideFromSlide.BOTTOM,
duration: const Duration(milliseconds: 600),
forward: true,
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.6,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'assets/images/appTheme.png',
fit: BoxFit.contain,
height: 300.0,
width: 300.0,
),
Container(
margin: const EdgeInsets.only(top: 32),
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(
style: TextStyle(
fontSize: 18,
fontFamily: 'Product Sans',
fontWeight: FontWeight.w500,
color:
Theme.of(context).textTheme.bodyText1?.color),
children: [
TextSpan(
text: AppLocalizations.of(
context,
)!
.intro_labelSelectPreferred +
"\n"),
TextSpan(
text: AppLocalizations.of(
context,
)!
.intro_labelTheme +
"!",
style: TextStyle(
color:
Theme.of(context).colorScheme.secondary,
fontWeight: FontWeight.w600))
]),
),
),
],
),
),
),
Container(
alignment: Alignment.bottomCenter,
margin: const EdgeInsets.only(bottom: 32),
child: Flex(
direction: Axis.horizontal,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Flexible(
flex: 1,
child: Padding(
padding: const EdgeInsets.only(left: 30, right: 15),
child: ShowUpTransition(
duration: const Duration(milliseconds: 600),
delay: const Duration(milliseconds: 600),
forward: true,
slideSide: SlideFromSlide.BOTTOM,
child: GestureDetector(
onTap: () {
currentTheme.switchTheme(
isDark: false,
useSystemTheme: true,
);
},
child: AnimatedContainer(
padding: const EdgeInsets.all(8),
duration: const Duration(milliseconds: 150),
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: theme == ThemeSelected.System
? Theme.of(context).colorScheme.secondary
: Theme.of(context).cardColor.withOpacity(0.4),
boxShadow: [
BoxShadow(
color: Colors.black12.withOpacity(0.08),
offset: const Offset(0, 0),
spreadRadius: 0.01,
blurRadius: 20.0)
]),
child: Center(
child: Text(
AppLocalizations.of(
context,
)!
.intro_labelSystem,
style: TextStyle(
fontSize: 14,
color: theme == ThemeSelected.System
? Colors.white
: Theme.of(context)
.textTheme
.bodyText1
?.color,
fontWeight: FontWeight.w700,
fontFamily: 'Product Sans')),
),
),
),
),
),
),
Flexible(
flex: 1,
child: Padding(
padding: const EdgeInsets.only(left: 15, right: 15),
child: ShowUpTransition(
duration: const Duration(milliseconds: 600),
delay: const Duration(milliseconds: 700),
forward: true,
slideSide: SlideFromSlide.BOTTOM,
child: GestureDetector(
onTap: () {
currentTheme.switchTheme(
isDark: false,
useSystemTheme: false,
);
},
child: AnimatedContainer(
padding: const EdgeInsets.all(8),
duration: const Duration(milliseconds: 150),
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: theme == ThemeSelected.Light
? Theme.of(context).colorScheme.secondary
: Theme.of(context).cardColor.withOpacity(0.4),
boxShadow: [
BoxShadow(
color: Colors.black12.withOpacity(0.08),
offset: const Offset(0, 0),
spreadRadius: 0.01,
blurRadius: 20.0)
]),
child: Center(
child: Text("Light",
style: TextStyle(
fontSize: 14,
color: theme == ThemeSelected.Light
? Colors.white
: Theme.of(context)
.textTheme
.bodyText1
?.color,
fontWeight: FontWeight.w700,
fontFamily: 'Product Sans')),
),
),
),
),
),
),
Flexible(
flex: 1,
child: Padding(
padding: const EdgeInsets.only(left: 15, right: 30),
child: ShowUpTransition(
duration: const Duration(milliseconds: 600),
delay: const Duration(milliseconds: 800),
forward: true,
slideSide: SlideFromSlide.BOTTOM,
child: GestureDetector(
onTap: () {
currentTheme.switchTheme(
isDark: true,
useSystemTheme: false,
);
},
child: AnimatedContainer(
padding: const EdgeInsets.all(8),
duration: const Duration(milliseconds: 150),
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: theme == ThemeSelected.Dark
? Theme.of(context).colorScheme.secondary
: Theme.of(context).cardColor.withOpacity(0.4),
boxShadow: [
BoxShadow(
color: Colors.black12.withOpacity(0.08),
offset: const Offset(0, 0),
spreadRadius: 0.01,
blurRadius: 20.0)
]),
child: Center(
child: Text("Dark",
style: TextStyle(
fontSize: 14,
color: theme == ThemeSelected.Dark
? Colors.white
: Theme.of(context)
.textTheme
.bodyText1
?.color,
fontWeight: FontWeight.w700,
fontFamily: 'Product Sans')),
),
),
),
),
),
)
],
),
)
],
));
}
}
config.dart
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
class MyTheme with ChangeNotifier {
bool _isDark =
Hive.box('settings').get('darkMode', defaultValue: false) as bool;
bool _useSystemTheme =
Hive.box('settings').get('useSystemTheme', defaultValue: false) as bool;
void refresh() {
final Box settingsBox = Hive.box('settings');
_isDark = settingsBox.get('darkMode', defaultValue: true) as bool;
_useSystemTheme =
settingsBox.get('useSystemTheme', defaultValue: false) as bool;
accentColor = settingsBox.get('themeColor', defaultValue: 'Teal') as String;
canvasColor =
settingsBox.get('canvasColor', defaultValue: 'Grey') as String;
cardColor = settingsBox.get('cardColor', defaultValue: 'Grey900') as String;
backGrad = settingsBox.get('backGrad', defaultValue: 2) as int;
cardGrad = settingsBox.get('cardGrad', defaultValue: 4) as int;
bottomGrad = settingsBox.get('bottomGrad', defaultValue: 3) as int;
colorHue = settingsBox.get('colorHue', defaultValue: 400) as int;
notifyListeners();
}
void switchTheme({bool? useSystemTheme, bool? isDark, bool notify = true}) {
if (isDark != null) {
_isDark = isDark;
}
if (useSystemTheme != null) {
_useSystemTheme = useSystemTheme;
}
Hive.box('settings').put('darkMode', _isDark);
Hive.box('settings').put('useSystemTheme', _useSystemTheme);
if (notify) notifyListeners();
}
ThemeMode currentTheme() {
if (_useSystemTheme == true) {
return ThemeMode.system;
} else {
return _isDark ? ThemeMode.dark : ThemeMode.light;
}
}
Color currentColor() {
switch (accentColor) {
case 'Red':
return Colors.redAccent[currentHue()]!;
case 'Teal':
return Colors.tealAccent[currentHue()]!;
case 'Light Blue':
return Colors.lightBlueAccent[currentHue()]!;
case 'Yellow':
return Colors.yellowAccent[currentHue()]!;
case 'Orange':
return Colors.orangeAccent[currentHue()]!;
case 'Blue':
return Colors.blueAccent[currentHue()]!;
case 'Cyan':
return Colors.cyanAccent[currentHue()]!;
case 'Lime':
return Colors.limeAccent[currentHue()]!;
case 'Pink':
return Colors.pinkAccent[currentHue()]!;
case 'Green':
return Colors.greenAccent[currentHue()]!;
case 'Amber':
return Colors.amberAccent[currentHue()]!;
case 'Indigo':
return Colors.indigoAccent[currentHue()]!;
case 'Purple':
return Colors.purpleAccent[currentHue()]!;
case 'Deep Orange':
return Colors.deepOrangeAccent[currentHue()]!;
case 'Deep Purple':
return Colors.deepPurpleAccent[currentHue()]!;
case 'Light Green':
return Colors.lightGreenAccent[currentHue()]!;
case 'White':
return Colors.white;
default:
return _isDark ? Colors.tealAccent[400]! : Colors.lightBlueAccent[400]!;
}
}
void setInitialTheme(String themeName) {
Hive.box('settings').put('theme', themeName);
}
String getInitialTheme() {
return Hive.box('settings').get('theme') as String;
}
}
提前致谢。
使用 setState 在 GestureDetector
中更新您的 UI
onTap() {
setState(() {
currentTheme.switchTheme(
isDark: false,
useSystemTheme: true,
);
});
}
希望有用
我实现了一个介绍屏幕,用户可以在开始时设置应用程序的主题。 一切正常,但我面临的唯一问题是选择时 BoxDecoration 切换颜色。仅当我从浅色模式切换到系统默认值时(当系统默认值处于浅色模式时,它在暗色模式下工作正常)才会出现此问题,反之亦然。而且我在调试时没有遇到任何错误。我还附上了一段视频 link.
IntroScreen.dart
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:mint/helpers/config.dart';
import 'package:mint/ui/animations/showUp.dart';
import 'package:eva_icons_flutter/eva_icons_flutter.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
enum ThemeSelected { System, Light, Dark }
class IntroTheme extends StatefulWidget {
const IntroTheme({Key? key}) : super(key: key);
@override
_IntroThemeState createState() => _IntroThemeState();
}
class _IntroThemeState extends State<IntroTheme> {
// Currently Selected Theme
ThemeSelected? theme;
final MyTheme currentTheme = GetIt.I<MyTheme>();
@override
void initState() {
super.initState();
theme = ThemeSelected.System;
}
@override
Widget build(BuildContext context) {
void checkTheme() {
if (currentTheme.currentTheme() == ThemeMode.system) {
theme = ThemeSelected.System;
} else if (currentTheme.currentTheme() == ThemeMode.light) {
theme = ThemeSelected.Light;
} else if (currentTheme.currentTheme() == ThemeMode.dark) {
theme = ThemeSelected.Dark;
}
}
checkTheme();
return SafeArea(
child: Stack(
alignment: Alignment.center,
children: [
ShowUpTransition(
duration: const Duration(milliseconds: 600),
forward: true,
slideSide: SlideFromSlide.LEFT,
child: Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
const Padding(
padding: EdgeInsets.only(right: 8),
child: AnimatedSwitcher(
duration: Duration(milliseconds: 300),
child: Icon(EvaIcons.colorPaletteOutline,
size: 40, color: Colors.red),
),
),
RichText(
textAlign: TextAlign.center,
text: TextSpan(
style: TextStyle(
fontSize: 22,
fontFamily: 'Product Sans',
fontWeight: FontWeight.w600,
color:
Theme.of(context).textTheme.bodyText1?.color),
children: [
const TextSpan(text: "App "),
TextSpan(
text: AppLocalizations.of(context)!
.intro_labelAppCustomization,
style: TextStyle(
color:
Theme.of(context).colorScheme.secondary,
fontWeight: FontWeight.w600))
]),
),
],
),
),
),
),
ShowUpTransition(
slideSide: SlideFromSlide.BOTTOM,
duration: const Duration(milliseconds: 600),
forward: true,
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.6,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'assets/images/appTheme.png',
fit: BoxFit.contain,
height: 300.0,
width: 300.0,
),
Container(
margin: const EdgeInsets.only(top: 32),
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(
style: TextStyle(
fontSize: 18,
fontFamily: 'Product Sans',
fontWeight: FontWeight.w500,
color:
Theme.of(context).textTheme.bodyText1?.color),
children: [
TextSpan(
text: AppLocalizations.of(
context,
)!
.intro_labelSelectPreferred +
"\n"),
TextSpan(
text: AppLocalizations.of(
context,
)!
.intro_labelTheme +
"!",
style: TextStyle(
color:
Theme.of(context).colorScheme.secondary,
fontWeight: FontWeight.w600))
]),
),
),
],
),
),
),
Container(
alignment: Alignment.bottomCenter,
margin: const EdgeInsets.only(bottom: 32),
child: Flex(
direction: Axis.horizontal,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Flexible(
flex: 1,
child: Padding(
padding: const EdgeInsets.only(left: 30, right: 15),
child: ShowUpTransition(
duration: const Duration(milliseconds: 600),
delay: const Duration(milliseconds: 600),
forward: true,
slideSide: SlideFromSlide.BOTTOM,
child: GestureDetector(
onTap: () {
currentTheme.switchTheme(
isDark: false,
useSystemTheme: true,
);
},
child: AnimatedContainer(
padding: const EdgeInsets.all(8),
duration: const Duration(milliseconds: 150),
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: theme == ThemeSelected.System
? Theme.of(context).colorScheme.secondary
: Theme.of(context).cardColor.withOpacity(0.4),
boxShadow: [
BoxShadow(
color: Colors.black12.withOpacity(0.08),
offset: const Offset(0, 0),
spreadRadius: 0.01,
blurRadius: 20.0)
]),
child: Center(
child: Text(
AppLocalizations.of(
context,
)!
.intro_labelSystem,
style: TextStyle(
fontSize: 14,
color: theme == ThemeSelected.System
? Colors.white
: Theme.of(context)
.textTheme
.bodyText1
?.color,
fontWeight: FontWeight.w700,
fontFamily: 'Product Sans')),
),
),
),
),
),
),
Flexible(
flex: 1,
child: Padding(
padding: const EdgeInsets.only(left: 15, right: 15),
child: ShowUpTransition(
duration: const Duration(milliseconds: 600),
delay: const Duration(milliseconds: 700),
forward: true,
slideSide: SlideFromSlide.BOTTOM,
child: GestureDetector(
onTap: () {
currentTheme.switchTheme(
isDark: false,
useSystemTheme: false,
);
},
child: AnimatedContainer(
padding: const EdgeInsets.all(8),
duration: const Duration(milliseconds: 150),
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: theme == ThemeSelected.Light
? Theme.of(context).colorScheme.secondary
: Theme.of(context).cardColor.withOpacity(0.4),
boxShadow: [
BoxShadow(
color: Colors.black12.withOpacity(0.08),
offset: const Offset(0, 0),
spreadRadius: 0.01,
blurRadius: 20.0)
]),
child: Center(
child: Text("Light",
style: TextStyle(
fontSize: 14,
color: theme == ThemeSelected.Light
? Colors.white
: Theme.of(context)
.textTheme
.bodyText1
?.color,
fontWeight: FontWeight.w700,
fontFamily: 'Product Sans')),
),
),
),
),
),
),
Flexible(
flex: 1,
child: Padding(
padding: const EdgeInsets.only(left: 15, right: 30),
child: ShowUpTransition(
duration: const Duration(milliseconds: 600),
delay: const Duration(milliseconds: 800),
forward: true,
slideSide: SlideFromSlide.BOTTOM,
child: GestureDetector(
onTap: () {
currentTheme.switchTheme(
isDark: true,
useSystemTheme: false,
);
},
child: AnimatedContainer(
padding: const EdgeInsets.all(8),
duration: const Duration(milliseconds: 150),
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: theme == ThemeSelected.Dark
? Theme.of(context).colorScheme.secondary
: Theme.of(context).cardColor.withOpacity(0.4),
boxShadow: [
BoxShadow(
color: Colors.black12.withOpacity(0.08),
offset: const Offset(0, 0),
spreadRadius: 0.01,
blurRadius: 20.0)
]),
child: Center(
child: Text("Dark",
style: TextStyle(
fontSize: 14,
color: theme == ThemeSelected.Dark
? Colors.white
: Theme.of(context)
.textTheme
.bodyText1
?.color,
fontWeight: FontWeight.w700,
fontFamily: 'Product Sans')),
),
),
),
),
),
)
],
),
)
],
));
}
}
config.dart
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
class MyTheme with ChangeNotifier {
bool _isDark =
Hive.box('settings').get('darkMode', defaultValue: false) as bool;
bool _useSystemTheme =
Hive.box('settings').get('useSystemTheme', defaultValue: false) as bool;
void refresh() {
final Box settingsBox = Hive.box('settings');
_isDark = settingsBox.get('darkMode', defaultValue: true) as bool;
_useSystemTheme =
settingsBox.get('useSystemTheme', defaultValue: false) as bool;
accentColor = settingsBox.get('themeColor', defaultValue: 'Teal') as String;
canvasColor =
settingsBox.get('canvasColor', defaultValue: 'Grey') as String;
cardColor = settingsBox.get('cardColor', defaultValue: 'Grey900') as String;
backGrad = settingsBox.get('backGrad', defaultValue: 2) as int;
cardGrad = settingsBox.get('cardGrad', defaultValue: 4) as int;
bottomGrad = settingsBox.get('bottomGrad', defaultValue: 3) as int;
colorHue = settingsBox.get('colorHue', defaultValue: 400) as int;
notifyListeners();
}
void switchTheme({bool? useSystemTheme, bool? isDark, bool notify = true}) {
if (isDark != null) {
_isDark = isDark;
}
if (useSystemTheme != null) {
_useSystemTheme = useSystemTheme;
}
Hive.box('settings').put('darkMode', _isDark);
Hive.box('settings').put('useSystemTheme', _useSystemTheme);
if (notify) notifyListeners();
}
ThemeMode currentTheme() {
if (_useSystemTheme == true) {
return ThemeMode.system;
} else {
return _isDark ? ThemeMode.dark : ThemeMode.light;
}
}
Color currentColor() {
switch (accentColor) {
case 'Red':
return Colors.redAccent[currentHue()]!;
case 'Teal':
return Colors.tealAccent[currentHue()]!;
case 'Light Blue':
return Colors.lightBlueAccent[currentHue()]!;
case 'Yellow':
return Colors.yellowAccent[currentHue()]!;
case 'Orange':
return Colors.orangeAccent[currentHue()]!;
case 'Blue':
return Colors.blueAccent[currentHue()]!;
case 'Cyan':
return Colors.cyanAccent[currentHue()]!;
case 'Lime':
return Colors.limeAccent[currentHue()]!;
case 'Pink':
return Colors.pinkAccent[currentHue()]!;
case 'Green':
return Colors.greenAccent[currentHue()]!;
case 'Amber':
return Colors.amberAccent[currentHue()]!;
case 'Indigo':
return Colors.indigoAccent[currentHue()]!;
case 'Purple':
return Colors.purpleAccent[currentHue()]!;
case 'Deep Orange':
return Colors.deepOrangeAccent[currentHue()]!;
case 'Deep Purple':
return Colors.deepPurpleAccent[currentHue()]!;
case 'Light Green':
return Colors.lightGreenAccent[currentHue()]!;
case 'White':
return Colors.white;
default:
return _isDark ? Colors.tealAccent[400]! : Colors.lightBlueAccent[400]!;
}
}
void setInitialTheme(String themeName) {
Hive.box('settings').put('theme', themeName);
}
String getInitialTheme() {
return Hive.box('settings').get('theme') as String;
}
}
提前致谢。
使用 setState 在 GestureDetector
中更新您的 UIonTap() {
setState(() {
currentTheme.switchTheme(
isDark: false,
useSystemTheme: true,
);
});
}
希望有用