Implementation in InWell on multiple widgets - flutter

The flutter code below represents a list of MealsListView objects, which represents a series of buttons that are displayed to the user, what I want to do is add an onPressed method which, when the user clicks on the specific button, passes the button title to the _marcaturautente(titlename) function. How can I go about doing this?
Flutter dart code:
//Funzione che viene eseguita quando l'utente clicca su un pulsante per effettuare la marcatura
Future<void> _marcaturautente(String tipologiaMarcatura) async {
print("Sono dentro la funzione che esegue la marcatura");
//Instanzio l'oggetto che si occupa di recuperare i dati per la marcatura
var location = new Location();
//Recupero i valori per istanziare l'oggetto dell'utente
var email = await Storage.leggi("Email");
var password = await Storage.leggi("Password");
var idutente = int.parse(await Storage.leggi("IdUtente"));
location.onLocationChanged().listen((LocationData currentLocation) {
double longitudine = currentLocation.longitude;
double latitudine = currentLocation.latitude;
//Genero l'istanza dell'utente
var user = new Utente.init(idutente, email, password);
//Genero l'istanza che si occuperà di effettuare la marcatura
var marcatura = new Marcatura(user, longitudine, latitudine);
//Verifico la tipologia della marcatura
if (tipologiaMarcatura == "Ingresso") {
marcatura.ingresso();
} else if (tipologiaMarcatura == "Uscita") {
marcatura.uscita();
} else if (tipologiaMarcatura == "Arrivo") {
marcatura.arrivo();
} else if (tipologiaMarcatura == "Partenza") {
marcatura.partenza();
}
});
}
class MealsListView extends StatefulWidget {
const MealsListView(
{Key key, this.mainScreenAnimationController, this.mainScreenAnimation})
: super(key: key);
final AnimationController mainScreenAnimationController;
final Animation<dynamic> mainScreenAnimation;
#override
_MealsListViewState createState() => _MealsListViewState();
}
class _MealsListViewState extends State<MealsListView>
with TickerProviderStateMixin {
AnimationController animationController;
List<MealsListData> mealsListData = MealsListData.tabIconsList;
#override
void initState() {
animationController = AnimationController(
duration: const Duration(milliseconds: 2000), vsync: this);
super.initState();
}
Future<bool> getData() async {
await Future<dynamic>.delayed(const Duration(milliseconds: 50));
return true;
}
#override
void dispose() {
animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: widget.mainScreenAnimationController,
builder: (BuildContext context, Widget child) {
return FadeTransition(
opacity: widget.mainScreenAnimation,
child: Transform(
transform: Matrix4.translationValues(
0.0, 30 * (1.0 - widget.mainScreenAnimation.value), 0.0),
child: Container(
height: 216,
width: double.infinity,
child: ListView.builder(
padding: const EdgeInsets.only(
top: 0, bottom: 0, right: 16, left: 16),
itemCount: mealsListData.length,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
final int count =
mealsListData.length > 10 ? 10 : mealsListData.length;
final Animation<double> animation =
Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
parent: animationController,
curve: Interval((1 / count) * index, 1.0,
curve: Curves.fastOutSlowIn)));
animationController.forward();
return MealsView(
onTap: (index) {},
mealsListData: mealsListData[index],
animation: animation,
animationController: animationController,
tipologiaMarcatura: mealsListData[index].titleTxt);
},
),
),
),
);
},
);
}
}
typedef CustomCallback = void Function(int);
class MealsView extends StatelessWidget {
const MealsView(
{Key key,
this.mealsListData,
this.animationController,
this.animation,
this.index,
this.onTap,
this.tipologiaMarcatura})
: super(key: key);
//Stringa che viene inizializzata con la tipologia della marcatura
final String tipologiaMarcatura;
final MealsListData mealsListData;
final AnimationController animationController;
final Animation<dynamic> animation;
final int index;
final CustomCallback onTap;
//Recupero dei dati che vanno inseriti all'interno dell widget
Widget getData() {
return FadeTransition(
opacity: animation,
//wrap your Stack widget inside InkWell
child: Transform(
transform:
Matrix4.translationValues(100 * (1.0 - animation.value), 0.0, 0.0),
child: SizedBox(
width: 130,
child: Stack(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(
top: 32, left: 8, right: 8, bottom: 16),
child: Container(
decoration: BoxDecoration(
boxShadow: <BoxShadow>[
BoxShadow(
color:
HexColor(mealsListData.endColor).withOpacity(0.6),
offset: const Offset(1.1, 4.0),
blurRadius: 8.0),
],
gradient: LinearGradient(
colors: <HexColor>[
HexColor(mealsListData.startColor),
HexColor(mealsListData.endColor),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: const BorderRadius.only(
bottomRight: Radius.circular(8.0),
bottomLeft: Radius.circular(8.0),
topLeft: Radius.circular(8.0),
topRight: Radius.circular(54.0),
),
),
child: Padding(
padding: const EdgeInsets.only(
top: 54, left: 16, right: 16, bottom: 8),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
mealsListData.titleTxt,
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: TemaApp.fontName,
fontWeight: FontWeight.bold,
fontSize: 16,
letterSpacing: 0.2,
color: TemaApp.white,
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.only(top: 8, bottom: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
mealsListData.meals.join('\n'),
style: TextStyle(
fontFamily: TemaApp.fontName,
fontWeight: FontWeight.w500,
fontSize: 10,
letterSpacing: 0.2,
color: TemaApp.white,
),
),
],
),
),
),
mealsListData.kacl != 0
? Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Text(
mealsListData.kacl.toString(),
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: TemaApp.fontName,
fontWeight: FontWeight.w500,
fontSize: 24,
letterSpacing: 0.2,
color: TemaApp.white,
),
),
Padding(
padding: const EdgeInsets.only(
left: 4, bottom: 3),
child: Text(
'',
style: TextStyle(
fontFamily: TemaApp.fontName,
fontWeight: FontWeight.w500,
fontSize: 10,
letterSpacing: 0.2,
color: TemaApp.white,
),
),
),
],
)
: Container(
decoration: BoxDecoration(
color: TemaApp.nearlyWhite,
shape: BoxShape.circle,
boxShadow: <BoxShadow>[
BoxShadow(
color: TemaApp.nearlyBlack
.withOpacity(0.4),
offset: Offset(8.0, 8.0),
blurRadius: 8.0),
],
),
child: Padding(
padding: const EdgeInsets.all(6.0),
child: Icon(
Icons.add,
color: HexColor(mealsListData.endColor),
size: 24,
),
),
),
],
),
),
),
),
Positioned(
top: 0,
left: 0,
child: Container(
width: 84,
height: 84,
decoration: BoxDecoration(
color: TemaApp.nearlyWhite.withOpacity(0.2),
shape: BoxShape.circle,
),
),
),
Positioned(
top: 0,
left: 8,
child: SizedBox(
width: 80,
height: 80,
child: Image.asset(mealsListData.imagePath),
),
)
],
),
),
),
);
}
#override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: animationController,
builder: (BuildContext context, Widget child) {
//InWell è un rettangolo che permett edi rispondere al touch
return InkWell(
onTap: () {
onTap(index);
print("Eseguito tap su index: " + index.toString() + "");
},
//Viene generato il child con il container dei dati
child: Container(
child: getData(),
),
);
});
}
}

Update*
typedef CustomCallback = void Function(int);
//Custom Callback function
class MealsView extends StatelessWidget {
const MealsView(
{Key key,
this.mealsListData,
this.animationController,
this.animation,
this.index,
this.onTap;
this.tipologiaMarcatura})
: super(key: key);
//Stringa che viene inizializzata con la tipologia della marcatura
final String tipologiaMarcatura;
final MealsListData mealsListData;
final AnimationController animationController;
final Animation<dynamic> animation;
final int index;
final CustomCallback onTap;
//wrap your Stack widget inside InkWell
InkWell(
onTap:(){
onTap(index);
//Todo
},
//Your Stack and other code goes here...
)
}
and use it in
return MealsView(onTap:(ii){
},
mealsListData: mealsListData[index],
animation: animation,
animationController: animationController,
tipologiaMarcatura: mealsListData[index].titleTxt
);

Related

How can I maintain the height of an animation widget even if it's contained in another widget?

This is what I mean:
As you can see the animation starts from the top to bottom, the problem begins when I integrate another file into it
Example:
Here, I wrapped with another widget and don't respect the height of the app bar
This is my code:
home_page_timer.dart
import 'dart:core';
import 'package:flutter/material.dart';
import 'package:google_nav_bar/google_nav_bar.dart';
import 'package:pomodoro/5.hourglass_animation/countdown_timer/pomodoro_animation.dart';
import 'dart:async';
class HomePageTimerUI extends StatefulWidget {
const HomePageTimerUI({Key? key}) : super(key: key);
#override
State<HomePageTimerUI> createState() => _HomePageTimerUIState();
}
class _HomePageTimerUIState extends State<HomePageTimerUI>
with TickerProviderStateMixin {
late TabController _tabController;
late Timer timer;
late AnimationController controller;
String get countText {
Duration count = controller.duration! * controller.value;
return controller.isDismissed
? '${controller.duration!.inHours.toString().padLeft(2, '0')}:${(controller.duration!.inMinutes % 60).toString().padLeft(2, '0')}:${(controller.duration!.inSeconds % 60).toString().padLeft(2, '0')}'
: '${count.inHours.toString().padLeft(2, '0')}:${(count.inMinutes % 60).toString().padLeft(2, '0')}:${(count.inSeconds % 60).toString().padLeft(2, '0')}';
}
#override
void initState() {
super.initState();
_tabController = TabController(length: 3, vsync: this);
}
#override
void dispose() {
_tabController.dispose();
super.dispose();
}
void notify() {
if (countText == '00:00:00') {
_tabController.animateTo(1, duration: const Duration(milliseconds: 300));
}
}
#override
Widget build(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height,
child: DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
bottom: PreferredSize(
preferredSize: const Size.fromHeight(35),
child: Container(
color: Colors.transparent,
child: SafeArea(
child: Column(
children: <Widget>[
TabBar(
controller: _tabController,
indicator: const UnderlineTabIndicator(
borderSide: BorderSide(
color: Color(0xff3B3B3B), width: 4.0),
insets:
EdgeInsets.fromLTRB(12.0, 12.0, 12.0, 11.0)),
indicatorWeight: 15,
indicatorSize: TabBarIndicatorSize.label,
labelColor: const Color(0xff3B3B3B),
labelStyle: const TextStyle(
fontSize: 12,
letterSpacing: 1.3,
fontWeight: FontWeight.w500),
unselectedLabelColor: const Color(0xffD7D7D7),
tabs: const [
Tab(
text: "POMODORO",
icon: Icon(Icons.work_history, size: 35),
),
Tab(
text: "SHORT BREAK",
icon: Icon(Icons.ramen_dining, size: 35),
),
Tab(
text: "LONG BREAK",
icon: Icon(Icons.battery_charging_full_rounded,
size: 35),
),
])
],
),
),
),
),
),
body: TabBarView(
controller: _tabController,
children: <Widget>[
Center(
child: Container(
height: MediaQuery.of(context).size.height,
child: StartPomodoro(end: DateTime.now())),
),
const Center(
child: Text('short break'),
),
const Center(
child: Text('long break '),
),
],
),
),
),
);
}
}
start_pomodoro.dart
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:pomodoro/5.hourglass_animation/countdown_timer/responsive.dart';
class StartPomodoro extends StatefulWidget {
const StartPomodoro({super.key, required this.end});
final DateTime end;
#override
State<StartPomodoro> createState() => _StartPomodoroState();
}
class _StartPomodoroState extends State<StartPomodoro>
with TickerProviderStateMixin {
final now = DateTime.now();
List<bool> isSelected = [true, false];
late Timer timer;
late AnimationController controller;
String get countText {
Duration count = controller.duration! * controller.value;
return controller.isDismissed
? '${controller.duration!.inHours.toString().padLeft(2, '0')}:${(controller.duration!.inMinutes % 60).toString().padLeft(2, '0')}:${(controller.duration!.inSeconds % 60).toString().padLeft(2, '0')}'
: '${count.inHours.toString().padLeft(2, '0')}:${(count.inMinutes % 60).toString().padLeft(2, '0')}:${(count.inSeconds % 60).toString().padLeft(2, '0')}';
}
double progress = 1.0;
bool LongBreak = true;
void notify() {
if (countText == '00:00:00') {}
}
#override
void initState() {
super.initState();
controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 0),
);
controller.addListener(() {
notify();
if (controller.isAnimating) {
setState(() {
progress = controller.value;
});
} else {
setState(() {
progress = 1.0;
LongBreak = true;
});
}
});
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor:
LongBreak ? const Color(0xffD94530) : const Color(0xff6351c5),
body: Stack(
children: [
GestureDetector(
onTap: () {
if (controller.isDismissed) {
showModalBottomSheet(
context: context,
builder: (context) => SizedBox(
height: 300,
child: CupertinoTimerPicker(
initialTimerDuration: controller.duration!,
onTimerDurationChanged: (time) {
setState(() {
controller.duration = time;
});
},
),
),
);
}
},
child: AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Stack(
children: <Widget>[
Align(
alignment: Alignment.bottomCenter,
child: Container(
color: const Color(0xffD94530),
height: controller.value *
MediaQuery.of(context).size.height,
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Responsive(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Align(
alignment: Alignment.bottomCenter,
child: Align(
alignment: FractionalOffset.bottomCenter,
child: Container(
width:
MediaQuery.of(context).size.width,
height: 210,
decoration: const BoxDecoration(
color: Color.fromARGB(
255, 245, 245, 245),
),
child: Container(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
const Text(
"Hyper-focused on... (+add task)",
style: TextStyle(
fontSize: 22.0,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 16),
Center(
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment
.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Center(
child: Text(
countText,
style:
const TextStyle(
fontWeight:
FontWeight.w600,
letterSpacing: 4,
fontSize: 65.0,
color: Color(
0xff3B3B3B),
),
),
),
],
),
Row(
mainAxisAlignment:
MainAxisAlignment
.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
Center(
child: Text(
' Hours Minutes Seconds ',
style: TextStyle(
fontWeight:
FontWeight.w500,
letterSpacing: 2,
fontSize: 20.0,
color: Color(
0xff3B3B3B),
),
),
),
],
),
],
),
),
],
),
),
),
),
),
//Spacer(),
Responsive(
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.stretch,
children: [
AnimatedBuilder(
animation: controller,
builder: (context, child) {
return const Padding(
padding: EdgeInsets.symmetric(
vertical: 2.0,
horizontal: 15.0),
);
}),
AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Padding(
padding:
const EdgeInsets.symmetric(
vertical: 2.0,
horizontal: 15.0),
child: FloatingActionButton
.extended(
backgroundColor:
const Color(
0xffFAFAFA),
onPressed: () {
if (controller
.isAnimating) {
controller.stop();
setState(() {
LongBreak = false;
});
} else {
controller.reverse(
from: controller
.value ==
0
? 1.0
: controller
.value);
setState(() {
LongBreak = false;
});
}
},
icon: Icon(
controller.isAnimating
? Icons.pause
: Icons
.play_arrow,
color: const Color(
0xff3B3B3B),
),
label: Text(
controller.isAnimating
? "Pause"
: "Start",
style: const TextStyle(
color: Color(
0xff3B3B3B)),
)),
);
}),
],
),
),
],
),
),
),
],
);
}),
),
],
),
),
);
}
AnimationController _buildClockAnimation(TickerProvider tickerProvider) {
return AnimationController(
vsync: tickerProvider,
duration: const Duration(milliseconds: 750),
);
}
void _animateLeftDigit(
int prev,
int current,
AnimationController controller,
) {
final prevFirstDigit = (prev / 10).floor();
final currentFirstDigit = (current / 10).floor();
if (prevFirstDigit != currentFirstDigit) {
controller.forward();
}
}
}
How can I provide a height from the animation widget which respects the app bar widget and there is no lag when I started the timer?
What I mean is that I want to start the animation here:
Thank you for any help you can offer
As #Henrique Zanferrari suggested you are using height of the screen in
height: MediaQuery.of(context).size.height
Which is limiting the widgets to follow along with the appBar.
Try replacing this height with more general Widget like Expanded or Flexible like so.

How to animate row when children changes

How do you achieve the smooth transition when the checkmark is added?
Clicking the element will setState update the pressAttention variable, and therefore add the checkmark widget to the list of children of the row.
For now it just instantly rebuilds the row, and adds the checkmark, but I would really like it to smoothly do as in the GIF.
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
widget.amount,
style: const TextStyle(
color: Colors.white, fontWeight: FontWeight.w700),
),
if (pressAttention)
Padding(
padding: const EdgeInsets.only(left: 10),
child: Container(
width: 23,
height: 23,
decoration: BoxDecoration(
color: Theme.of(context).highlightColor,
shape: BoxShape.circle,
),
child: Padding(
padding: const EdgeInsets.all(4),
child: SvgPicture.asset(
MyIcons.checkmarkThick,
),
),
),
)
],
),
try this:
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
late Animation<double> _animation;
late Animation<double> _opacityAnimation;
late Animation _colorAnimation;
late AnimationController _controller;
var pressAttention = false;
#override
void initState() {
super.initState();
_controller =
AnimationController(duration: Duration(milliseconds: 500), vsync: this)
..addListener(() => setState(() {}));
_animation = Tween(begin: 15.0, end: 0.0).animate(_controller);
_opacityAnimation = Tween(begin: 0.0, end: 1.0).animate(_controller);
_colorAnimation =
ColorTween(begin: Colors.grey, end: Colors.purple).animate(_controller);
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: Center(
child: Center(
child: Container(
child: InkWell(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
onTap: () {
if (pressAttention) {
_controller.forward();
} else {
_controller.reverse();
}
setState(() {
pressAttention = !pressAttention;
});
},
child: AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Container(
width: 100,
decoration: BoxDecoration(
border: Border.all(color: _colorAnimation.value),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Transform.translate(
offset: Offset(_animation.value, 0),
child: Text(
'1000',
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.w700),
),
),
Opacity(
opacity: _opacityAnimation.value,
child: Padding(
padding: EdgeInsets.only(left: 10),
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).highlightColor,
shape: BoxShape.circle,
),
child: const Padding(
padding: EdgeInsets.all(4),
child: Icon(
Icons.check,
size: 13,
),
),
),
),
)
],
),
);
}),
),
),
),
),
);
}
}
You can achieve this with a combination of Animated Widgets. Set their behaviours and durations and you should be good to go.

Flutter Linear progress indicator for each page of pageview builder

I want to build a progress indicator for each page of the pageview builder. Pageview changes after 10 seconds and the progress bar shifts to the next bar. I have successfully implemented this, but encounter an issue of 4 bars loading at the same time, while going back and forth to the page view screen or when I minimize and reopen the app.
This is what I already have achieved with the following code:
This is my code:
class WelcomeScreen extends StatefulWidget {
const WelcomeScreen({Key? key}) : super(key: key);
#override
State<WelcomeScreen> createState() => _WelcomeScreenState();
}
class _WelcomeScreenState extends State<WelcomeScreen>
with TickerProviderStateMixin {
final WelcomeController controller = Get.put(WelcomeController());
late AnimationController animationControllerOne;
late AnimationController animationControllerTwo;
late AnimationController animationControllerThree;
late AnimationController animationControllerFour;
late Animation<double> animation;
#override
void initState() {
super.initState();
animationControllerOne =
AnimationController(duration: const Duration(seconds: 10), vsync: this);
animation = Tween(begin: 0.0, end: 1.0).animate(animationControllerOne)
..addListener(() {
setState(() {
});
});
animationControllerOne.forward();
animationControllerTwo =
AnimationController(duration: const Duration(seconds: 10), vsync: this);
animation = Tween(begin: 1.0, end: 2.0).animate(animationControllerTwo)
..addListener(() {
setState(() {
});
});
Timer(const Duration(seconds: 10), () {
animationControllerTwo.forward();
});
animationControllerThree =
AnimationController(duration: const Duration(seconds: 10), vsync: this);
animation = Tween(begin: 2.0, end: 3.0).animate(animationControllerThree)
..addListener(() {
setState(() {});
});
Timer(const Duration(seconds: 20), () {
animationControllerThree.forward();
});
animationControllerFour =
AnimationController(duration: const Duration(seconds: 10), vsync: this);
animation = Tween(begin: 3.0, end: 4.0).animate(animationControllerFour)
..addListener(() {
setState(() {});
});
Timer(const Duration(seconds: 30), () {
animationControllerFour.forward();
});
animationControllerFour.addStatusListener((status) {
if (status == AnimationStatus.completed) {
animationControllerOne.reset();
animationControllerTwo.reset();
animationControllerThree.reset();
animationControllerFour.reset();
animationControllerOne.forward();
}
animationControllerOne.addStatusListener((status) {
if (status == AnimationStatus.completed) {
animationControllerTwo.reset();
animationControllerTwo.forward();
}
});
animationControllerTwo.addStatusListener((status) {
if (status == AnimationStatus.completed) {
animationControllerThree.reset();
animationControllerThree.forward();
}
});
animationControllerThree.addStatusListener((status) {
if (status == AnimationStatus.completed) {
animationControllerFour.reset();
animationControllerFour.forward();
}
});
});
}
#override
void dispose() {
animationControllerOne.dispose();
animationControllerTwo.dispose();
animationControllerThree.dispose();
animationControllerFour.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: context.theme.scaffoldBackgroundColor,
appBar: AppBar(
systemOverlayStyle: SystemUiOverlayStyle(
statusBarColor: Get.isDarkMode ? darkBackground : lightBackground,
statusBarIconBrightness:
Get.isDarkMode ? Brightness.light : Brightness.dark,
),
title: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
key: const Key('loading bar'),
children: [
Expanded(
child: LinearProgressIndicator(
color: primaryBlue,
backgroundColor: const Color(0xFFD9D9D9),
minHeight: 8,
value: animationControllerOne.value,
),
),
const SizedBox(
width: 10,
),
Expanded(
child: LinearProgressIndicator(
color: primaryBlue,
backgroundColor: const Color(0xFFD9D9D9),
minHeight: 8,
value: animationControllerTwo.value,
),
),
const SizedBox(
width: 10,
),
Expanded(
child: LinearProgressIndicator(
color: primaryBlue,
backgroundColor: const Color(0xFFD9D9D9),
minHeight: 8,
value: animationControllerThree.value,
),
),
const SizedBox(
width: 10,
),
Expanded(
child: LinearProgressIndicator(
backgroundColor: const Color(0xFFD9D9D9),
color: primaryBlue,
minHeight: 8,
value: animationControllerFour.value,
),
),
],
),
),
elevation: 0,
backgroundColor: Get.isDarkMode ? darkBackground : lightBackground,
centerTitle: true,
),
body: Padding(
padding: const EdgeInsets.symmetric(vertical: 15),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Welcome to Demonstration Bank!'.tr,
key: const Key('message'),
textAlign: TextAlign.center,
style: TextStyle(
color: Get.isDarkMode ? lightBackground : darkBackground,
fontSize: Get.height * 0.027,
fontWeight: FontWeight.w600,
),
),
SizedBox(
height: Get.height * 0.05,
),
SizedBox(
height: Get.height * 0.4,
width: Get.width * 0.8,
child: PageView.builder(
controller: controller.gifsController,
physics: const NeverScrollableScrollPhysics(),
itemCount: controller.images.length,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Image.asset(
controller.images[index],
fit: BoxFit.fitWidth,
);
},
),
),
SizedBox(
height: Get.height * 0.15,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CustomButton(
key: const Key('sign in button'),
height: Get.height * 0.069,
width: Get.width * 0.335,
fontSize: Get.height * 0.021,
color: Get.isDarkMode ? lightBackground : darkBackground,
textColor: Get.isDarkMode ? darkBackground : lightBackground,
text: 'Sign in'.tr,
onPressed: () => Get.to(() => const SigninScreen()),
),
const SizedBox(
width: 19,
),
CustomButton(
key: const Key('sign up button'),
height: Get.height * 0.069,
width: Get.width * 0.335,
fontSize: Get.height * 0.021,
color: primaryBlue,
textColor: Colors.white,
text: 'Sign Up'.tr,
onPressed: () => Get.to(() => CreateAccountScreen()),
),
],
),
const SizedBox(
height: 24,
),
],
),
),
);
}
}
Unexpected result: ( Note: this problem does not happen always )

Widget not redrawing despite Setstate & UniqueKey

I have this code for selecting options in a product page.
The index is updating well, but the color of the selected option refuses to change (as well as the name of the selected option on the right -- see the image below), and i can't figure why..
I have tried to use Setstate(), and to use unique keys for the related parent widgets
Here the image:
import 'package:animate_do/animate_do.dart';
import 'package:flutter/material.dart';
import 'package:prem_market/models/product.dart';
import 'package:prem_market/models/product_variation.dart';
class DisplayAttributes extends StatefulWidget {
const DisplayAttributes({
Key key,
this.data,
Function onChanged,
}) : super(key: key);
final Product data;
#override
_DisplayAttributesState createState() => _DisplayAttributesState();
}
class _DisplayAttributesState extends State<DisplayAttributes> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
int activeOption = 0;
return Column(
children: [
...List.generate(
this.widget.data.attributes.length,
(index) => !this.widget.data.attributes[index].variation
? SizedBox()
: Column(
children: <Widget>[
SizedBox(
height: 25,
),
Padding(
padding: EdgeInsets.only(left: 25, right: 25),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
FadeInDown(
delay: Duration(milliseconds: 450),
child: Text(
this.widget.data.attributes[index].name,
style: TextStyle(
fontSize: 16, fontWeight: FontWeight.w600),
),
),
FadeInDown(
delay: Duration(milliseconds: 450),
child: Text(
activeOption == 100
? '-'
: this
.widget
.data
.attributes[index]
.options[activeOption],
style: TextStyle(
fontSize: 16,
//color: black.withOpacity(0.7)
),
),
)
],
)),
SizedBox(
height: 25,
),
FadeInDown(
delay: Duration(milliseconds: 500),
child: Padding(
padding: EdgeInsets.only(left: 20, right: 25),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: this
.widget
.data
.attributes[index]
.options
.asMap()
.map<int, GestureDetector>(
(i, String childData) {
return MapEntry(
i,
GestureDetector(
key: UniqueKey(),
onTap: () {
setState(() {
if (activeOption == i) {
//selected = false;
activeOption = 100;
} else {
activeOption = i;
//selected = true;
}
});
FocusScope.of(context)
.requestFocus(new FocusNode());
},
child: Padding(
padding: const EdgeInsets.only(
right: 15,
bottom: 5,
left: 5,
top: 5),
child: Container(
key: UniqueKey(),
//width: 50,
height: 50,
padding: EdgeInsets.symmetric(
horizontal: 10),
decoration: BoxDecoration(
color: activeOption == i
? Theme.of(context)
.textTheme
.headline6
.color
: Colors.grey[200],
borderRadius:
BorderRadius.circular(8),
boxShadow: [
BoxShadow(
spreadRadius: 0.5,
blurRadius: 1,
color: Theme.of(context)
.shadowColor
.withOpacity(0.1))
]),
child: Center(
child: Text(
childData,
key: UniqueKey(),
style: TextStyle(
fontSize: 16,
color: activeOption == i
? Theme.of(context)
.backgroundColor
: Theme.of(context)
.shadowColor),
),
),
),
),
));
})
.values
.toList(),
),
),
),
),
],
),
),
],
);
}
}
You are resetting activeOption to 0 in build function make it a global variable. Everytime you call setState() build method is called which again resets it to 0
#override
Widget build(BuildContext context) {
int activeOption = 0;
to
int activeOption = 0;
#override
Widget build(BuildContext context) {

How to add gradient to my standard switch in Flutter?

How can I change my standard Switch
to this gradient switch
Also how to increase the size of switch?
Please help.
Code:-
Switch(
activeColor: Colors.lightBlueAccent,
inactiveThumbColor: Colors.grey,
value: _switchValueRead,
onChanged: (value) {
setState(() {
_switchValueRead = value;
});
},
),
You can do it by this from this thread
library custom_switch;
import 'package:flutter/material.dart';
class CustomSwitch extends StatefulWidget {
final bool value;
final ValueChanged<bool> onChanged;
final Color activeColor;
final Color inactiveColor;
final String activeText;
final String inactiveText;
final Color activeTextColor;
final Color inactiveTextColor;
const CustomSwitch(
{Key key,
this.value,
this.onChanged,
this.activeColor,
this.inactiveColor = Colors.grey,
this.activeText = '',
this.inactiveText = '',
this.activeTextColor = Colors.white70,
this.inactiveTextColor = Colors.white70})
: super(key: key);
#override
_CustomSwitchState createState() => _CustomSwitchState();
}
class _CustomSwitchState extends State<CustomSwitch>
with SingleTickerProviderStateMixin {
Animation _circleAnimation;
AnimationController _animationController;
#override
void initState() {
super.initState();
_animationController =
AnimationController(vsync: this, duration: Duration(milliseconds: 60));
_circleAnimation = AlignmentTween(
begin: widget.value ? Alignment.centerRight : Alignment.centerLeft,
end: widget.value ? Alignment.centerLeft : Alignment.centerRight)
.animate(CurvedAnimation(
parent: _animationController, curve: Curves.linear));
}
#override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return GestureDetector(
onTap: () {
if (_animationController.isCompleted) {
_animationController.reverse();
} else {
_animationController.forward();
}
widget.value == false
? widget.onChanged(true)
: widget.onChanged(false);
},
child: Container(
width: 70.0,
height: 35.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
// I commented here.
// color: _circleAnimation.value == Alignment.centerLeft
// ? widget.inactiveColor
// : widget.activeColor,
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
// You can set your own colors in here!
colors: [
Colors.blue,
Colors.red,
],
),
),
child: Padding(
padding: const EdgeInsets.only(
top: 4.0, bottom: 4.0, right: 4.0, left: 4.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
_circleAnimation.value == Alignment.centerRight
? Padding(
padding: const EdgeInsets.only(left: 34.0, right: 0),
child: Text(
widget.activeText,
style: TextStyle(
color: widget.activeTextColor,
fontWeight: FontWeight.w900,
fontSize: 16.0),
),
)
: Container(),
Align(
alignment: _circleAnimation.value,
child: Container(
width: 25.0,
height: 25.0,
decoration: BoxDecoration(
shape: BoxShape.circle, color: Colors.white),
),
),
_circleAnimation.value == Alignment.centerLeft
? Padding(
padding: const EdgeInsets.only(left: 0, right: 34.0),
child: Text(
widget.inactiveText,
style: TextStyle(
color: widget.inactiveTextColor,
fontWeight: FontWeight.w900,
fontSize: 16.0),
),
)
: Container(),
],
),
),
),
);
},
);
}
}
Check this for gradient
For increasing the size - wrap your Switch into Container (or SizedBox) and set width and height to Container(SizedBox). It should help.