Consumer doesn't update the UI when using notifyListeners() - flutter

I'm using animated containers and I want them to change color when I use NotifyListeners();
Thing is, the color only updates when you click on the container, otherwise it remains the same.
I tried switching to normal containers, I tried changing the home screen to stateful, nothing seems to work, any help is appreciated.
Github link: https://github.com/amrogad/beat_maker
void main() {
runApp(MultiProvider(providers: [
ChangeNotifierProvider<SoundProvider>(create: (_) => SoundProvider(),
),
ChangeNotifierProvider<IconProvider>(create: (_) => IconProvider(),
),
], child: MyApp()));
}
class IconProvider extends ChangeNotifier {
Color primary1 = Colors.deepPurpleAccent;
Color secondary1 = Colors.deepPurple;
Color primary2 = Colors.yellowAccent;
Color secondary2 = Colors.orangeAccent;
Color primary3 = Colors.cyanAccent;
Color secondary3 = Colors.blue;
Color primary4 = Colors.lime;
Color secondary4 = Colors.lightGreen;
void changeIcons(
Color primaryPath1,
Color secondaryPath1,
Color primaryPath2,
Color secondaryPath2,
Color primaryPath3,
Color secondaryPath3,
Color primaryPath4,
Color secondaryPath4,
) {
primary1 = primaryPath1;
secondary1 = secondaryPath1;
primary2 = primaryPath2;
secondary2 = secondaryPath2;
primary3 = primaryPath3;
secondary3 = secondaryPath3;
primary4 = primaryPath4;
secondary4 = secondaryPath4;
notifyListeners();
}
}
class HomeScreen extends StatelessWidget {
static const String routeName = 'Home Screen';
#override
Widget build(BuildContext context) {
var soundProvider = Provider.of<SoundProvider>(context);
return SafeArea(
child: Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
automaticallyImplyLeading: false,
backgroundColor: Colors.black,
title: Text(
'Beat Maker',
style: GoogleFonts.anton(color: Colors.lime, fontSize: 24),
),
centerTitle: true,
actions: [
GestureDetector(
onTap: () {
Navigator.of(context).pushNamed(SettingsScreen.routeName);
},
child: Icon(
Icons.settings,
color: Colors.lime,
size: 24,
)),
SizedBox(
width: 10,
),
],
),
body: Consumer<IconProvider>(
builder: (context, icon, child) {
return GridView(
physics: NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4
),
children: [
SoundButton(
icon.primary1, icon.secondary1, soundProvider.note1),
SoundButton(
icon.primary2, icon.secondary2, soundProvider.note2),
SoundButton(
icon.primary3, icon.secondary3, soundProvider.note3),
SoundButton(
icon.primary4, icon.secondary4, soundProvider.note4)
],
);
}
),
),
);
}
class SoundButton extends StatefulWidget {
final Color mainColor;
final Color sideColor;
final note;
const SoundButton(this.mainColor, this.sideColor, this.note, {Key? key})
: super(key: key);
#override
State<SoundButton> createState() => _SoundButtonState();
}
class _SoundButtonState extends State<SoundButton> {
late Color _mainColor;
late Color _sideColor;
final player = AudioPlayer();
#override
void initState() {
_mainColor = widget.mainColor;
_sideColor = widget.sideColor;
super.initState();
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
_mainColor = Colors.redAccent;
_sideColor = Colors.red;
player.play(AssetSource(widget.note));
});
},
child: AnimatedContainer(
decoration: BoxDecoration(
border: Border.all(width: 1),
gradient: RadialGradient(colors: [_mainColor, _sideColor]),
boxShadow: const [
BoxShadow(
blurRadius: 1.0,
spreadRadius: 1.0,
offset: Offset(
1.0,
1.0,
),
),
]),
curve: Curves.easeOutCubic,
onEnd: () => Reset(),
duration: const Duration(milliseconds: 100),
),
);
}
void Reset() {
setState(() {
_mainColor = widget.mainColor;
_sideColor = widget.sideColor;
});
}
}
class OpenIconBottomSheet extends StatelessWidget {
const OpenIconBottomSheet({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
var iconProvider = Provider.of<IconProvider>(context);
return Container(
height: 106,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(12), topRight: Radius.circular(12)),
color: Colors.black,
border: Border.all(width: 3, color: Colors.lime)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
InkWell(
onTap: () {
iconProvider.changeIcons(
Colors.deepPurpleAccent,
Colors.deepPurple,
Colors.yellowAccent,
Colors.orangeAccent,
Colors.cyanAccent,
Colors.blue,
Colors.lime,
Colors.lightGreen,
);
Navigator.pop(context);
},
child: isSelected(
'Main Theme',
iconProvider.primary1 == Colors.deepPurpleAccent
? true
: false)),
Container(
width: double.infinity,
height: 3,
color: Colors.lime,
),
SizedBox(
height: 7,
),
InkWell(
onTap: () {
iconProvider.changeIcons(
Colors.white70,
Colors.white,
Colors.pinkAccent,
Colors.pink,
Colors.tealAccent,
Colors.teal,
Colors.amberAccent,
Colors.redAccent,
);
Navigator.pop(context);
},
child: isSelected('Secondary Theme',
iconProvider.primary1 == Colors.white70 ? true : false)),
],
),
);
}
Widget isSelected(String text, bool selected) {
if (selected) {
return Padding(
padding: EdgeInsets.all(6),
child: Text(text,
style: GoogleFonts.anton(color: Colors.lime, fontSize: 24)),
);
} else {
return Padding(
padding: EdgeInsets.all(6),
child: Text(text,
style: GoogleFonts.anton(color: Colors.white, fontSize: 24)),
);
}
}
}

Related

How to reset my quiz app questions choices

I am new to flutter, I have built a quizz app that takes 5 questions randomly from a pool of questions and presents them to the user one after the other, then displays the total score at the end (on a different) screen with the option of retaking the quiz (with another set of randomly picked questions).
My issue I am facing is that when I choose to retake the quiz, if in the pool of questions presented there is a question from the past quiz, it still has its options highlighted (marked either wrong or correct as per the previous selection).
Can someone help me on how to totally dismiss previous choices after taking a quiz ?
This is an example of question answered in the previous quiz, and it came back with the option already highlighted (my previous answer).
[enter image description here][1]
[1]: https://i.stack.imgur.com/U1YFf.png[enter image description here][1]
Here is my code:
import 'package:flutter/material.dart';
import 'package:percent_indicator/percent_indicator.dart';
import 'package:schoolest_app/widgets/quizz/quizz_image_container.dart';
import '../../models/quizz.dart';
import '../../widgets/quizz/options_widget.dart';
import '../../widgets/quizz/quizz_border_container.dart';
import '../../widgets/quizz/result_page.dart';
class QuizzDisplayScreen extends StatefulWidget {
const QuizzDisplayScreen({
Key? key,
}) : super(key: key);
static const routeName = '/quizz-display';
#override
State<QuizzDisplayScreen> createState() => _QuizzDisplayScreenState();
}
class _QuizzDisplayScreenState extends State<QuizzDisplayScreen> {
enter code here
late String quizzCategoryTitle;
late List<Question> categoryQuestions;
late List<Question> quizCategoryQuestions;
var _loadedInitData = false;
#override
void didChangeDependencies() {
if (!_loadedInitData) {
final routeArgs =
ModalRoute.of(context)!.settings.arguments as Map<String, String>;
quizzCategoryTitle = (routeArgs['title']).toString();
// final categoryId = routeArgs['id'];
categoryQuestions = questions.where((question) {
return question.categories.contains(quizzCategoryTitle);
}).toList();
quizCategoryQuestions =
(categoryQuestions.toSet().toList()..shuffle()).take(5).toList();
_loadedInitData = true;
}
super.didChangeDependencies();
}
late PageController _controller;
int _questionNumber = 1;
int _score = 0;
int _totalQuestions = 0;
bool _isLocked = false;
void _resetQuiz() {
for (var element in quizCategoryQuestions) {
setState(()=> element.isLocked == false);
}
}
#override
void initState() {
super.initState();
_controller = PageController(initialPage: 0);
}
#override
void dispose() {
_controller.dispose();
_resetQuiz();
super.dispose();
}
#override
Widget build(BuildContext context) {
final myPrimaryColor = Theme.of(context).colorScheme.primary;
final mySecondaryColor = Theme.of(context).colorScheme.secondary;
double answeredPercentage =
(_questionNumber / quizCategoryQuestions.length);
return quizCategoryQuestions.isEmpty
? Scaffold(
appBar: AppBar(
title: Text(
'Quizz - $quizzCategoryTitle',
style: TextStyle(color: myPrimaryColor),
),
iconTheme: IconThemeData(
color: myPrimaryColor,
),
centerTitle: true,
backgroundColor: Colors.transparent,
elevation: 0,
flexibleSpace: Container(
decoration: BoxDecoration(`enter code here`
borderRadius: const BorderRadius.only(`enter code here`
bottomLeft: Radius.circular(15),
bottomRight: Radius.circular(15),
),
color: mySecondaryColor,
border: Border.all(color: myPrimaryColor, width: 1.0),
),
),
),
body: const Center(
child: Text('Cette catégorie est vide pour l\'instant'),
))
: Scaffold(
appBar: AppBar(
title: Text(
'Quizz - $quizzCategoryTitle',
style: TextStyle(color: myPrimaryColor),
),
iconTheme: IconThemeData(
color: myPrimaryColor,
),
centerTitle: true,
backgroundColor: Colors.transparent,
elevation: 0,
flexibleSpace: Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(15),
bottomRight: Radius.circular(15),
),
color: mySecondaryColor,
border: Border.all(color: myPrimaryColor, width: 1.0),
),
),
),
body: Container(
// height: 600,
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
children: [
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(
'Question $_questionNumber/${quizCategoryQuestions.length}',
style: const TextStyle(
fontSize: 20, fontWeight: FontWeight.bold),
),
CircularPercentIndicator(
radius: 40,
// animation: true,
// animationDuration: 2000,
percent: answeredPercentage,
progressColor: myPrimaryColor,
backgroundColor: Colors.cyan.shade100,
circularStrokeCap: CircularStrokeCap.round,
center: Text(
// ignore: unnecessary_brace_in_string_interps
'${(answeredPercentage * 100).round()} %',
style: const TextStyle(
fontSize: 10, fontWeight: FontWeight.bold),
),
// lineWidth: 10,
)
],
),
const SizedBox(height: 10),
Divider(
thickness: 1,
color: myPrimaryColor,
),
Expanded(
child: PageView.builder(
itemCount: quizCategoryQuestions.length,
controller: _controller,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
final _question = quizCategoryQuestions[index];
return buildQuestion(_question);
},
),
),
_isLocked
? buildElevatedButton(context)
: const SizedBox.shrink(),
const SizedBox(height: 10),
],
),
),
);
}
Column buildQuestion(Question question) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 10),
question.text!.isNotEmpty
? QuizzBorderContainer(
childWidget: Text(
question.text!,
style: const TextStyle(
fontSize: 20, fontWeight: FontWeight.bold),
),
)
: const SizedBox.shrink(),
question.imagePath!.isNotEmpty
? QuizzImageContainer(imagePath: question.imagePath!)
: const SizedBox.shrink(),
Expanded(
child: OptionsWidget(
question: question,
onClickedOption: (option) {
if (question.isLocked) {
return;
} else {
setState(() {
question.isLocked = true;
question.selectedOption = option;
});
_isLocked = question.isLocked;
if (question.selectedOption!.isCorrect) {
_score++;
}
}
},
),
),
],
);
}
ElevatedButton buildElevatedButton(BuildContext context) {
final mySecondaryColor = Theme.of(context).colorScheme.secondary;
return ElevatedButton(
onPressed: () {
if (_questionNumber < quizCategoryQuestions.length) {
_controller.nextPage(
duration: const Duration(milliseconds: 1000),
curve: Curves.easeInExpo,
);
setState(() {
_questionNumber++;
_isLocked = false;
});
} else {
setState(() {
// _isLocked = false;
_totalQuestions = quizCategoryQuestions.length;
});
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) =>
ResultPage(score: _score, totalQuestions: _totalQuestions),
),
);
}
},
child: Text(
_questionNumber < quizCategoryQuestions.length
? 'Suivant'
: 'Voir le résultat',
style: TextStyle(
color: mySecondaryColor,
fontWeight: FontWeight.bold,
),
),
);
}
}
I don't seem to the solution to this.
And this is the code on the result page:
import 'package:flutter/material.dart';
import '../../screens/quizz/quizz_screen.dart';
class ResultPage extends StatefulWidget {
final int score;
final int totalQuestions;
const ResultPage({
Key? key,
required this.score,
required this.totalQuestions,
}) : super(key: key);
#override
State<ResultPage> createState() => _ResultPageState();
}
class _ResultPageState extends State<ResultPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: SizedBox(
height: 150,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
'You got ${widget.score}/${widget.totalQuestions}',
style: const TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
),
),
ElevatedButton(
onPressed: () {
Navigator.pop(context);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const QuizzScreen(),
),
);
},
child: const Text('OK'),
),
],
),
),
),
);
}
}
I don't know what is missing to get the reset right.
When you want to take retest try to dispose all the answers which are saved in the memory. Or you can use these navigators to which might help you in solving the issue. Try using pushReplacement or pushAndRemoveUntil when navigating to retest, this will clear the memory of last pages and you will achive the goal which you want.

TabBar scroll/slide making inaccuracy of displaying

I uses Container 's color to make indicator-like rather than using TabBar's indicator as I've to implement some animation to the Container.
When TabController index is changing, setState is called in the listener. Tries scroll/slide on the TabBar, the TabBar isn't properly changing the index, as listener doesn't listen to animation for TabBar.
I've tried using tabcontroller.animation.addListener method, but there isn't any workaround for me to control the scroll movement.
Attached video below demonstrates tapping and scroll/slide applied on the TabBar.
TabBar-Scroll/Slide
Code:
class TabTest extends StatefulWidget {
#override
_TabTestState createState() => _TabTestState();
}
class _TabTestState extends State<TabTest> with TickerProviderStateMixin {
late TabController _tabController;
late List<AnimationController> _animationControllers;
#override
void initState() {
super.initState();
_tabController = TabController(length: 4, vsync: this)
..addListener(_listener);
_animationControllers = List.generate(
4,
(i) => AnimationController(
vsync: this,
duration: Duration(milliseconds: 750),
reverseDuration: Duration(milliseconds: 350),
));
}
#override
Widget build(BuildContext context) {
List<IconData> _tabIconData = [
Icons.card_giftcard,
Icons.confirmation_num_outlined,
Icons.emoji_events_outlined,
Icons.wine_bar_outlined,
];
List<String> _tabLabel = [
'Tab1',
'Tab2',
'Tab3',
'Tab4',
];
Widget _tab({
required IconData iconData,
required String label,
required bool isSelectedIndex,
// required double widthAnimation,
// required heightAnimation,
}) {
const _tabTextStyle = TextStyle(
fontWeight: FontWeight.w300, fontSize: 12, color: Colors.black);
return AnimatedContainer(
duration: Duration(milliseconds: 300),
padding: EdgeInsets.only(bottom: 2.0),
height: 55,
width: double.infinity, //_animContainerWidth - widthAnimation,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: isSelectedIndex ? Colors.black : Colors.transparent,
width: 2.0,
),
),
),
child: Tab(
iconMargin: EdgeInsets.only(bottom: 5.0),
icon: Icon(iconData, color: Colors.black),
child: Text(label, style: _tabTextStyle),
),
);
}
List<Widget> _animationGenerator() {
return List.generate(
4,
(index) => ClipRRect(
child: AnimatedBuilder(
animation: _animationControllers[index],
builder: (ctx, _) {
final value = _animationControllers[index].value;
final angle = math.sin(value * math.pi * 2) * math.pi * 0.04;
return Transform.rotate(
angle: angle,
child: _tab(
iconData: _tabIconData[index],
label: _tabLabel[index],
isSelectedIndex: _tabController.index == index,
));
}),
),
);
}
return Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(100),
child: AppBar(
iconTheme: Theme.of(context).iconTheme,
title: Text(
'Tab Bar',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w400,
),
),
centerTitle: true,
bottom: PreferredSize(
preferredSize: Size.fromHeight(20),
child: Container(
child: TabBar(
controller: _tabController,
labelPadding: EdgeInsets.only(top: 5.0, bottom: 2.0),
indicatorColor: Colors.transparent,
tabs: _animationGenerator(),
),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.white,
spreadRadius: 5.0,
offset: Offset(0, 3))
],
),
),
),
),
),
body: TabBarView(
controller: _tabController,
children: List.generate(
4,
(index) => FittedBox(
child: Text('Tab $index'),
)),
),
);
}
void _listener() {
if (_tabController.indexIsChanging) {
setState(() {}); // To refresh color for Container bottom Border
_animationControllers[_tabController.previousIndex].reverse();
} else {
_animationControllers[_tabController.index].forward();
}
}
#override
void dispose() {
super.dispose();
_tabController.removeListener(_listener);
}
}
this is a solution with a CustomPaint widget driven by TabController.animation:
class TabTest extends StatefulWidget {
#override
_TabTestState createState() => _TabTestState();
}
class _TabTestState extends State<TabTest> with TickerProviderStateMixin {
late TabController _tabController;
late List<AnimationController> _animationControllers;
#override
void initState() {
super.initState();
// timeDilation = 10;
_tabController = TabController(length: 4, vsync: this)
..addListener(_listener);
_animationControllers = List.generate(4, (i) => AnimationController(
vsync: this,
duration: Duration(milliseconds: 750),
));
}
#override
Widget build(BuildContext context) {
List<IconData> _tabIconData = [
Icons.card_giftcard,
Icons.confirmation_num_outlined,
Icons.emoji_events_outlined,
Icons.wine_bar_outlined,
];
List<String> _tabLabel = [
'Tab1',
'Tab2',
'Tab3',
'Tab4',
];
List<Color> _tabColor = [
Color(0xffaa0000),
Color(0xff00aa00),
Color(0xff0000aa),
Colors.black,
];
Widget _tab({
required IconData iconData,
required String label,
required Color color,
required int index,
required Animation<double>? animation,
}) {
const _tabTextStyle = TextStyle(fontWeight: FontWeight.w300, fontSize: 12, color: Colors.black);
return CustomPaint(
painter: TabPainter(
animation: animation!,
index: index,
color: color,
),
child: SizedBox(
width: double.infinity,
child: Tab(
iconMargin: EdgeInsets.only(bottom: 5.0),
icon: Icon(iconData, color: Colors.black),
child: Text(label, style: _tabTextStyle),
),
),
);
}
List<Widget> _animationGenerator() {
return List.generate(
4,
(index) => AnimatedBuilder(
animation: _animationControllers[index],
builder: (ctx, _) {
final value = _animationControllers[index].value;
final angle = sin(value * pi * 3) * pi * 0.04;
return Transform.rotate(
angle: angle,
child: _tab(
iconData: _tabIconData[index],
label: _tabLabel[index],
color: _tabColor[index],
index: index,
animation: _tabController.animation,
));
}),
);
}
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
title: Text('Tab Bar',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w400,
),
),
centerTitle: true,
bottom: TabBar(
controller: _tabController,
labelPadding: EdgeInsets.only(top: 5.0, bottom: 2.0),
indicatorColor: Colors.transparent,
tabs: _animationGenerator(),
),
),
body: TabBarView(
controller: _tabController,
children: List.generate(4, (index) => FittedBox(
child: Text('Tab $index'),
)),
),
);
}
void _listener() {
if (_tabController.indexIsChanging) {
_animationControllers[_tabController.previousIndex].value = 0;
} else {
_animationControllers[_tabController.index].forward();
}
}
#override
void dispose() {
super.dispose();
_tabController
..removeListener(_listener)
..dispose();
_animationControllers.forEach((ac) => ac.dispose());
}
}
class TabPainter extends CustomPainter {
final Animation<double> animation;
final int index;
final Color color;
final tabPaint = Paint();
TabPainter({
required this.animation,
required this.index,
required this.color,
});
#override
void paint(ui.Canvas canvas, ui.Size size) {
// timeDilation = 10;
if ((animation.value - index).abs() < 1) {
final rect = Offset.zero & size;
canvas.clipRect(rect);
canvas.translate(size.width * (animation.value - index), 0);
final tabRect = Alignment.bottomCenter.inscribe(Size(size.width, 3), rect);
canvas.drawRect(tabRect, tabPaint..color = color);
}
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}

ToggleButtons, Flutter: How to change border color and border radius

I have 3 ToggleButtons and I'm trying to figure out how to change the color of the selected button's border. As you can see in my picture, the green button on the left has a very hard to see light blue border around it since it is the selected button. I would like to know how I can change this color and also how I can round the border's corners.
If it helps, 'CryptoCard' is made with the Card class.
Here is my code:
Center(
child: ToggleButtons(
borderWidth: 0,
splashColor: Colors.yellow,
renderBorder: false,
children: <Widget>[
CryptoCard(
selectedCurrency,
snapshot.connectionState ==
ConnectionState.waiting
? '---'
: coinData[0],
'Bitcoin'),
CryptoCard(
selectedCurrency,
snapshot.connectionState ==
ConnectionState.waiting
? '---'
: coinData[1],
'Ethereum'),
CryptoCard(
selectedCurrency,
snapshot.connectionState ==
ConnectionState.waiting
? '---'
: coinData[2],
'Litecoin'),
],
onPressed: (int index) {
setState(() {
for (int buttonIndex = 0;
buttonIndex < isSelectedCrypto.length;
buttonIndex++) {
if (buttonIndex == index) {
isSelectedCrypto[buttonIndex] = true;
selectedCrypto =
cryptoAbbreviation[buttonIndex];
print("selectedCrypto");
print(selectedCrypto);
} else {
isSelectedCrypto[buttonIndex] = false;
}
}
});
futureData = getData();
},
isSelected: isSelectedCrypto))
ToggleButton has a property selectedBorderColor which you can use to set the border color of your selected button. You can use a custom widget to give rounded border to each individual button.
Please see the code below :
import 'package:flutter/material.dart';
final Color darkBlue = const Color.fromARGB(255, 18, 32, 47);
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<bool> isSelected = List.generate(6, (index) => false);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: ToggleButtons(
children: [
CustomIcon(
icon: const Icon(Icons.ac_unit),
isSelected: isSelected[0],
bgColor: const Color(0xfff44336),
),
CustomIcon(
icon: const Icon(Icons.call),
isSelected: isSelected[1],
bgColor: const Color(0xffE91E63),
),
CustomIcon(
icon: const Icon(Icons.cake),
isSelected: isSelected[2],
bgColor: const Color(0xff9C27B0),
),
CustomIcon(
icon: const Icon(Icons.add),
isSelected: isSelected[3],
bgColor: const Color(0xff673AB7),
),
CustomIcon(
icon: const Icon(Icons.accessibility),
isSelected: isSelected[4],
bgColor: const Color(0xff3F51B5),
),
CustomIcon(
icon: const Icon(Icons.analytics),
isSelected: isSelected[5],
bgColor: const Color(0xff2196F3),
),
],
onPressed: (int index) {
setState(() {
for (int buttonIndex = 0;
buttonIndex < isSelected.length;
buttonIndex++) {
if (buttonIndex == index) {
isSelected[buttonIndex] = !isSelected[buttonIndex];
} else {
isSelected[buttonIndex] = false;
}
}
});
},
isSelected: isSelected,
selectedColor: Colors.amber,
renderBorder: false,
fillColor: Colors.transparent,
),
),
);
}
}
class CustomIcon extends StatefulWidget {
final Icon icon;
final bool isSelected;
final Color bgColor;
const CustomIcon(
{Key key,
this.icon,
this.isSelected = false,
this.bgColor = Colors.green})
: super(key: key);
#override
_CustomIconState createState() => _CustomIconState();
}
class _CustomIconState extends State<CustomIcon> {
#override
Widget build(BuildContext context) {
return Container(
width: 47,
height: 47,
decoration: BoxDecoration(
border: widget.isSelected
? Border.all(
color: const Color(0xffC5CAE9),
)
: null,
borderRadius: const BorderRadius.all(
Radius.circular(10),
),
),
child: Center(
child: Container(
height: 32,
width: 32,
decoration: BoxDecoration(
color: widget.bgColor,
borderRadius: const BorderRadius.all(
Radius.circular(5),
),
),
child: widget.icon,
),
),
);
}
}
I'm sure it is not the best but here is my code for this maybe it will help someone out there.
if you need only need one selected button to be colorized in different colour like this
Color mColor = Color(0xFF6200EE),mColor0 = Color(0xFF6200EE),mColor1 = Color(0xFF6200EE);
final isSelected = <bool>[false, false, false];
then
ToggleButtons(
color: Colors.black.withOpacity(0.60),
selectedColor: mColor,
selectedBorderColor: mColor0,
fillColor: mColor1.withOpacity(0.08),
splashColor: Colors.grey.withOpacity(0.12),
hoverColor: Color(0xFF6200EE).withOpacity(0.04),
borderRadius: BorderRadius.circular(4.0),
constraints: BoxConstraints(minHeight: 36.0),
isSelected: isSelected,
onPressed: (index) {
// Respond to button selection
setState(() {
isSelected[0] = false;
isSelected[1] = false;
isSelected[2] = false;
if (index == 0) {
mColor = Colors.blue;
mColor0 = Colors.blue;
mColor1 = Colors.blue;
}
if (index == 1) {
mColor = Colors.green;
mColor0 = Colors.green;
mColor1 = Colors.green;
}
if (index == 2) {
mColor = Colors.red;
mColor0 = Colors.red;
mColor1 = Colors.red;
}
isSelected[index] = !isSelected[index];
});
},
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
'BUTTON 1',
style: TextStyle(fontSize: 20),
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
'BUTTON 2',
style: TextStyle(fontSize: 20),
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
'BUTTON 3',
style: TextStyle(fontSize: 20),
),
),
],
),

how to disable tooltip dynamcically in flutter?

I can disable the tooltip statically.
But I want to disable tooltip dynamically when i click flatbutton.But Couldnt disable dynamically and i have no idea to do that.
This is my code:
import 'package:flutter/material.dart';
void main(){
runApp(MaterialApp(home: HelloWorld(),debugShowCheckedModeBanner: false,));
}
class HelloWorld extends StatefulWidget {
#override
_HelloWorldState createState() => _HelloWorldState();
}
class _HelloWorldState extends State<HelloWorld> {
bool check = false;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Column(children: <Widget>[
TopToolbar(),
FlatButton(
child: Text("Disable Tooltip"),
onPressed: () {
setState(() {
TopToolbar toolbar = new TopToolbar();
toolbar.showTooltip = false;
});
},
),
]),
),
));
}
}
class TopToolbar extends StatefulWidget {
bool showTooltip;
final Color backgroundColor;
final double height;
bool isVisible;
TopToolbar({
this.height = 55,
this.isVisible = true,
this.backgroundColor = const Color(0xFFEEEEEE),
Key key,this.showTooltip=true,
}) : super(key: key);
#override
_TopToolbarState createState() => _TopToolbarState();
}
class _TopToolbarState extends State<TopToolbar> {
#override
Widget build(BuildContext context) {
if (widget.isVisible) {
return Container(
foregroundDecoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Colors.grey,
),
),
),
margin: EdgeInsets.only(bottom: 1),
color: widget.backgroundColor,
height: widget.height,
child: Stack(
children: <Widget>[
Positioned(
top: 7,
right: 60,
height: 40,
width: 40,
child: RawMaterialButton(
elevation: 0.0,
fillColor: widget.backgroundColor,
splashColor: Colors.grey[300],
child: IconButton(
icon: Icon(
Icons.bookmark,
color: Colors.grey[500],
size: 25,
),
onPressed: (){},
tooltip: widget.showTooltip ? "Bookmark" : null,
),
onPressed: (){},
),
),
],
),
);
} else {
return Container();
}
}
}
If I give statically false. it works fine.
For example : If add child like TopToolbar(showTooltip : false),it works fine,
But If i give toolbar.showTooltip = false in Flatbutton onPressed method,it doesnt work.
I want to disble it in dynamically. please help me to do that.
we can hide or deactivate tooltip programmatically like below,
Future.delayed(
Duration(seconds: 2),
() {
tooltip?.deactivate();
}
);
Here, we can set time according to your requirement.(Currently, we are set 2 sec.)
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: HelloWorld(),
debugShowCheckedModeBanner: false,
));
}
class HelloWorld extends StatefulWidget {
#override
_HelloWorldState createState() => _HelloWorldState();
}
class _HelloWorldState extends State<HelloWorld> {
bool check = false;
bool showTooltip = true;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Column(children: <Widget>[
TopToolbar(showTooltip: showTooltip),
FlatButton(
child: Text("Disable Tooltip"),
onPressed: () {
setState(() {
showTooltip = false;
});
},
),
]),
),
));
}
}
class TopToolbar extends StatefulWidget {
final bool showTooltip;
final Color backgroundColor;
final double height;
final bool isVisible;
TopToolbar({
this.height = 55,
this.isVisible = true,
this.backgroundColor = const Color(0xFFEEEEEE),
Key key,
this.showTooltip = true,
}) : super(key: key);
#override
_TopToolbarState createState() => _TopToolbarState();
}
class _TopToolbarState extends State<TopToolbar> {
#override
Widget build(BuildContext context) {
if (widget.isVisible) {
return Container(
foregroundDecoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Colors.grey,
),
),
),
margin: EdgeInsets.only(bottom: 1),
color: widget.backgroundColor,
height: widget.height,
child: Stack(
children: <Widget>[
Positioned(
top: 7,
right: 60,
height: 40,
width: 40,
child: RawMaterialButton(
elevation: 0.0,
fillColor: widget.backgroundColor,
splashColor: Colors.grey[300],
child: IconButton(
icon: Icon(
Icons.bookmark,
color: Colors.grey[500],
size: 25,
),
onPressed: () {},
tooltip: widget.showTooltip ? 'Bookmark' : null,
),
onPressed: () {},
),
),
],
),
);
} else {
return Container();
}
}
}
I've used this method to hide tooltips:
Tooltip(
decoration: BoxDecoration(
color: Colors.white.withOpacity(0),
),
textStyle: TextStyle(color: Colors.white.withOpacity(0)),
message: 'Certificates',
child: Container()
);
Make the property message='' // empty string
setState((){messageText=''});
Tooltip(
message: messageText,
...
)

Flutter equvalent Android-Toggle-Switch

is any flutter widget like with this library in android java?
<belka.us.androidtoggleswitch.widgets.MultipleToggleSwitch
android:id="#+id/multiple_toggle_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
custom:textToggleCenter="Center"
custom:textToggleLeft="Left"
custom:textToggleRight="Right"
android:layout_gravity="center"
custom:toggleWidth="82dp"/>
i did try to search to find this implementation on flutter but i can't
as an option, how to use
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ToggleWidget(
initialLabel: 2,
activeBgColor: Colors.indigo,
activeTextColor: Colors.white,
inactiveBgColor: Colors.grey,
inactiveTextColor: Colors.grey[900],
labels: ['OR', 'XOR', 'AND', 'NOT'],
onToggle: (index) {
print('switched to: $index');
},
),
SizedBox(height: 16),
ToggleWidget(
cornerRadius: 20,
activeBgColor: Colors.redAccent,
activeTextColor: Colors.yellow,
inactiveBgColor: Colors.grey,
inactiveTextColor: Colors.white,
labels: ['YES', 'NO'],
),
],
),
),
),
);
}
}
and the widget itself
typedef OnToggle = void Function(int index);
class ToggleWidget extends StatefulWidget {
final Color activeBgColor;
final Color activeTextColor;
final Color inactiveBgColor;
final Color inactiveTextColor;
final List<String> labels;
final double cornerRadius;
final OnToggle onToggle;
final int initialLabel;
final double minWidth;
ToggleWidget({
Key key,
#required this.activeBgColor,
#required this.activeTextColor,
#required this.inactiveBgColor,
#required this.inactiveTextColor,
#required this.labels,
this.onToggle,
this.cornerRadius = 8.0,
this.initialLabel = 0,
this.minWidth = 72,
}) : super(key: key);
#override
_ToggleWidgetState createState() => _ToggleWidgetState();
}
class _ToggleWidgetState extends State<ToggleWidget> {
int current;
#override
void initState() {
current = widget.initialLabel;
super.initState();
}
#override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.circular(widget.cornerRadius),
child: Container(
height: 40,
color: widget.inactiveBgColor,
child: Row(
mainAxisSize: MainAxisSize.min,
children: List.generate(widget.labels.length * 2 - 1, (index) {
final active = index ~/ 2 == current;
final textColor = active ? widget.activeTextColor : widget.inactiveTextColor;
final bgColor = active ? widget.activeBgColor : Colors.transparent;
if (index % 2 == 1) {
final activeDivider = active || index ~/ 2 == current - 1;
return Container(
width: 1,
color: activeDivider ? widget.activeBgColor : Colors.white30,
margin: EdgeInsets.symmetric(vertical: activeDivider ? 0 : 8),
);
} else {
return GestureDetector(
onTap: () => _handleOnTap(index ~/ 2),
child: Container(
constraints: BoxConstraints(minWidth: widget.minWidth),
alignment: Alignment.center,
color: bgColor,
child: Text(widget.labels[index ~/ 2], style: TextStyle(color: textColor)),
),
);
}
}),
),
),
);
}
void _handleOnTap(int index) async {
setState(() => current = index);
if (widget.onToggle != null) {
widget.onToggle(index);
}
}
}
result:
You can opt to create your own switch, the code below is a quick demonstration and I know it needs signification improvements to match the original library style:
int selectedIndex = 0 ;
Center(
child: Container(
padding: EdgeInsets.all(2.0),
color: Colors.grey[300],
child: Row(
children: <Widget>[
RaisedButton(
child: Text('OR'),
textColor: Colors.white,
color: selectedIndex == 0 ? Colors.indigo : Colors.grey,
onPressed: (){
setState(() {
selectedIndex = 0 ;
});
},
),
RaisedButton(
child: Text('XOR'),
textColor: Colors.white,
color: selectedIndex == 1 ? Colors.indigo : Colors.grey,
onPressed: (){
setState(() {
selectedIndex = 1 ;
});
},
),
RaisedButton(
child: Text('AND'),
textColor: Colors.white,
color: selectedIndex == 2 ? Colors.indigo : Colors.grey,
onPressed: (){
setState(() {
selectedIndex = 2 ;
});
},
),
],
),
),
),
ToggleSwitch dart package (based on #Eugene's answer) is now available.
Usage
dependencies:
...
toggle_switch: "^0.1.4"