Related
`I am trying to implement a toggle switch in which when I toggle the switch I display two different things but I'm getting an error while I use setstate with my logic or something like that if I remove the setstate from my code the animation starts working again but the logic does not work and I don't get two different outcomes when i toggle between the switch
the code is :
import 'package:flutter/material.dart';
import 'package:sadapay_clone/screens/homepage.dart';
import 'package:sadapay_clone/widgets/physical_card_item.dart';
import 'package:sadapay_clone/widgets/virtual_card_item.dart';
import 'package:toggle_switch/toggle_switch.dart';
class CardScreen extends StatefulWidget {
const CardScreen({super.key});
#override
State<CardScreen> createState() => _CardScreenState();
}
class _CardScreenState extends State<CardScreen>{
// AnimationController _controller;
bool toggle = false;
// #override
// void initState() {
// _controller = AnimationController(vsync: this);
// super.initState();
// }
// void toggleSwitch(int index) {
// if (index == 0) {
// setState(() {
// toggle = true;
// });
// } else if (index == 1) {
// setState(() {
// toggle = false;
// });
// }
// }
void toggleSwitch(int index) {
if (index == 0) {
setState(() {
toggle = true;
});
} else if (index == 1) {
setState(() {
toggle = false;
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
const SizedBox(height: 75),
SizedBox(
width: double.infinity,
child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
onPressed: () {
Navigator.pop(
context,
MaterialPageRoute(
builder: (context) => const MyHomePage(),
),
);
},
icon: const Icon(Icons.arrow_back_ios),
),
Container(
width: 295,
alignment: Alignment.center,
child: const Text(
'My Cards',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
textAlign: TextAlign.center,
),
),
],
),
),
const SizedBox(
height: 20,
),
Container(
alignment: Alignment.center,
height: 40,
width: 365,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.grey[300],
),
child: ToggleSwitch(
minHeight: 30,
minWidth: 180.0,
cornerRadius: 20.0,
activeBgColors: const [
[Colors.white],
[Colors.white]
],
activeFgColor: Colors.black,
inactiveBgColor: Colors.grey[300],
inactiveFgColor: Colors.black54,
initialLabelIndex: 0,
totalSwitches: 2,
labels: const ['Virtual', 'Physical'],
radiusStyle: true,
onToggle: (index) {
toggleSwitch(index!);
},
// onToggle: (index) {
// setState(() {
// toggle = index == 0;
// });
// },
),
),
toggle ? VirtualCard() : PhysicalCard(),
],
),
);
}
}
I tried using setstate logic inside the function rather than using it inside the onchanged property but still, the logic was working I was seeing two different outcomes when I pressed the switch but the animation was not working`
The issue is, while we are calling setState, the build method is trigger and setting initialLabelIndex to 0 again, you can do a check here,
class _CardScreenState extends State<CardScreen> {
bool toggle = false;
void toggleSwitch(int index) {
if (index == 0) {
setState(() {
toggle = true;
});
} else if (index == 1) {
setState(() {
toggle = false;
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Container(
alignment: Alignment.center,
height: 40,
width: 365,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.grey[300],
),
child: ToggleSwitch(
minHeight: 30,
minWidth: 180.0,
cornerRadius: 20.0,
activeBgColors: const [
[Colors.white],
[Colors.white]
],
activeFgColor: Colors.black,
inactiveBgColor: Colors.grey[300],
inactiveFgColor: Colors.black54,
initialLabelIndex: toggle ? 0 : 1,
totalSwitches: 2,
labels: ['Virtual', 'Physical'],
radiusStyle: true,
onToggle: (index) {
toggleSwitch(index!);
},
),
),
toggle ? Text("VirtualCard") : Text("PhysicalCard"),
],
),
);
}
}
I have Container with objects, and my objects are rendered from Firebase. I change a color of container on tap, and it works. But, when I have a several objects, it changes colors of all containers. But I need to change a color of current (tapping) container.
Container(
key: Key(snapshot.data!.docs[index].id),
child: GestureDetector(
onLongPress: () {
setState(() {
cpressed = !cpressed;
});
},
child: AnimatedContainer(
duration: const Duration(seconds: 0, milliseconds: 200),
color: cpressed ? Colors.red : Colors.blue,
child: Container(
child: Text(snapshot.data!.docs[index].get('item'), style:
TextStyle(color: CWhite, fontSize: 24)),
margin: EdgeInsets.fromLTRB(16, 15, 0, 15)
)
),
)
)
I have tried to put my key: Key(snapshot.data!.docs[index].id) as a property in AnimatedContainer, but it still doesn't work.
What can I do? I assume, It has to be something with keys, or, my setState()?
Instead of using a boolean to determine which is selected, how about using the id instead?
Change cpressed to:
String? selectedId;
And the widget:
Container(
child: GestureDetector(
onLongPress: () {
var currentId = snapshot.data!.docs[index].id;
setState(() {
if (selectedId != null) {
if (selectedId == currentId) {
selectedId = null;
} else {
selectedId = currentId;
}
} else {
selectedId = currentId;
}
});
},
child: AnimatedContainer(
duration: const Duration(seconds: 0, milliseconds: 200),
color: selectedId == snapshot.data!.docs[index].id ? Colors.red : Colors.blue,
child: Container(
child: Text(snapshot.data!.docs[index].get('item'), style:
TextStyle(color: CWhite, fontSize: 24)),
margin: EdgeInsets.fromLTRB(16, 15, 0, 15)
)
),
)
)
i an trying to design the add to cart button when user click on 'add to cart' the 'add to cart' button hides and ListTile appear that is on back of button and listtile have three things title , leading and trailing everything is works like i want but issue is i want the same size of list tile as button size so it won't grow when listtile appear on screen
here is the video to clear what i mean
https://youtu.be/Bq2mrc5ao94
here is my code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
int total=0;
bool cartbuttoncheck=true;
bool listbool=false;
IconData delete_icon=Icons.remove;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Button"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Visibility(
visible: listbool,
child: Container(
color: Colors.green,
child: SizedBox(
height: 50.0,
width: 160.0,
child: ListTile(
title: Center(child: Text(total.toString(),style: TextStyle(fontStyle: FontStyle.italic,color: Colors.white),)),
leading: IconButton(
icon: Icon(delete_icon,color: Colors.white,),
onPressed: (){
setState(() {
if(total==2)
{
print("i am 2");
delete_icon=Icons.delete;
total--;
}
else if(total==1 && delete_icon==Icons.delete)
{
total=0;
listbool=false;
cartbuttoncheck=true;
}
if(total>2)
{
// delete_icon=Icons.remove;
total--;
}
});
},
),
trailing: IconButton(
icon: Icon(Icons.add,color: Colors.white),
onPressed: (){
setState(() {
if(total==1 && delete_icon==Icons.delete)
{
delete_icon=Icons.remove;
}
total++;
});
},
),
),
),
),
),
Stack(
alignment: Alignment.center,
children: <Widget>[
Visibility(
visible: cartbuttoncheck,
child: RaisedButton(
onPressed: (){
setState(() {
cartbuttoncheck=false;
listbool=true;
if(total==0)
{
total++;
delete_icon=Icons.delete;
}
});
},
child: Text("Add to Cart",style: TextStyle(color: Colors.white),),
color: Colors.green,
),
),
],
),
],
),
),
),
);
}
}
Just like the ListTile uses a SizedBox with a defined size you can do the same to the RaisedButton
SizedBox(
height: 50.0,
width: 160.0,
child: RaisedButton(
onPressed: (){
setState(() {
cartbuttoncheck=false;
listbool=true;
if(total==0){
total++;
delete_icon=Icons.delete;
}
});
},
child: Text("Add to Cart",style: TextStyle(color: Colors.white),),
color: Colors.green,
),
)
Having said that I believe it would be better to not use all of the widgets you use(Column, Stack, Visibility) and just change between the ListTile and the RaisedButton based on a bool value (listbool for example)
class _MyAppState extends State<MyApp> {
int total = 0;
bool listbool = false;
IconData delete_icon = Icons.remove;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Button"),
),
body: Center(
child: Container(
color: Colors.green,
height: 50.0,
width: 160.0,
child: listbool
? ListTile(
title: Center(
child: Text(
total.toString(),
style: TextStyle(
fontStyle: FontStyle.italic, color: Colors.white),
)),
leading: IconButton(
icon: Icon(
delete_icon,
color: Colors.white,
),
onPressed: () {
setState(() {
if (total == 2) {
print("i am 2");
delete_icon = Icons.delete;
total--;
} else if (total == 1 &&
delete_icon == Icons.delete) {
total = 0;
listbool = false;
}
if (total > 2) {
// delete_icon=Icons.remove;
total--;
}
});
},
),
trailing: IconButton(
icon: Icon(Icons.add, color: Colors.white),
onPressed: () {
setState(() {
if (total == 1 && delete_icon == Icons.delete) {
delete_icon = Icons.remove;
}
total++;
});
},
),
)
: RaisedButton(
onPressed: () {
setState(() {
listbool = true;
if (total == 0) {
total++;
delete_icon = Icons.delete;
}
});
},
child: Text(
"Add to Cart",
style: TextStyle(color: Colors.white),
),
color: Colors.green,
),
),
),
),
);
}
}
Now you have a container of a specific size of color green in the center and based on the value of the listbool it changes its child to the ListTile and RaisedButton
UPDATE
class _MyAppState extends State<MyApp> {
double width; //the width of the RaisedButton based on the text
double height; //the heightof the RaisedButton based on the text
EdgeInsets myPadding = EdgeInsets.all(8); //a known padding to use in the RaisedButton
#override
void initState(){
super.initState();
TextSpan longestParagraphTest = TextSpan(
text: "Add to Cart",
style: TextStyle(color: Colors.white, fontSize: 14),
);
TextPainter _textPainter = TextPainter(text: longestParagraphTest, textDirection: TextDirection.ltr, maxLines: 1)..layout(minWidth: 0.0, maxWidth: double.infinity);
width = _textPainter.width + 16; //this is the padding
height = _textPainter.height + 16; //this is the padding
}
int total = 0;
bool listbool = false;
IconData delete_icon = Icons.remove;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Button"),
),
body: Center(
child: Container(
duration: const Duration(milliseconds: 300),
color: Colors.green,
height: height,
width: width, //now you know the size of the RaisedButton and use it in both the ListTile and RaisedButton
child: listbool
? ListTile(
title: Center(
child: Text(
total.toString(),
style: TextStyle(
fontStyle: FontStyle.italic, color: Colors.white),
)),
leading: IconButton(
icon: Icon(
delete_icon,
color: Colors.white,
),
onPressed: () {
setState(() {
if (total == 2) {
print("i am 2");
delete_icon = Icons.delete;
total--;
} else if (total == 1 &&
delete_icon == Icons.delete) {
total = 0;
listbool = false;
}
if (total > 2) {
// delete_icon=Icons.remove;
total--;
}
});
},
),
trailing: IconButton(
icon: Icon(Icons.add, color: Colors.white),
onPressed: () {
setState(() {
if (total == 1 && delete_icon == Icons.delete) {
delete_icon = Icons.remove;
}
total++;
});
},
),
)
: RaisedButton(
padding: myPadding,
onPressed: () {
setState(() {
listbool = true;
if (total == 0) {
total++;
delete_icon = Icons.delete;
}
});
},
child: Text(
"Add to Cart",
maxLines: 1,
style: TextStyle(color: Colors.white, fontSize: 14),
),
color: Colors.green,
),
),
),
),
);
}
}
And you will get something like this because the button size is too small for a ListTile to show 2 icons and a text
I have 2 recommendations if you want to keep it this way, in the initState change the minWidth in layout(minWidth: 0.0, maxWidth: double.infinity); to a greater value (let's say 100.0) just to be sure in case your minWidth is too small it changes to 100 to fit the ListTile. My second recommendation is to use an AnimatedContainer and change the size based on the widget displayed
AnimatedContainer(
duration: const Duration(milliseconds: 300),
color: Colors.green,
height: listbool ? 50.0 : height, //it animates to a a better size to fit the listTile
width: listbool ? 200.0 : width, //it animates to a a better size to fit the listTile
child: listbool ? ListTile(...) : RaisedButton(...),
),
where height and width are the values calculated in the initState. It will do a smooth animation between the 2 sizes (just like your video but smoother and cleaner)
I have 2 screens and I am trying to achieve understand how to achieve page state. For example, in the below screen, I have 4 options, and all of them take the user to the same screen the only difference is API getting called for each of them is different to build a list. I am trying to handle back arrow action, and that's where I am having issues.
Use Case -
When user is on screen 2 he is playing the song, now on back press song continues to play. Now when the user again chooses the same option from screen 1 I want to show the same list without reload and selection. If user selects any other option it should behave normal, which is working.
Solution -
I can hardcode loaded songs list and send back to screen 1 and then again get that back with the selection but this will take lot of resources.
AutomaticKeepAliveClientMixin i tried this tutorial but that didn't help or kept state active.
PageStorage is 3rd option i saw but i found majority of the time this is being used on app where we have a tab.
Screen 1 -
class Dashboard extends StatefulWidget {
int playingId;
Dashboard({this.playingId});
#override
_DashboardState createState() => _DashboardState(playingId);
}
class _DashboardState extends State<Dashboard> {
String appname;
int playingId = 0;
_DashboardState(this.playingId);
// print('${playingId}');
#override
void initState() {
appname="";
// playingId=0;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: AppColors.darkBlue,
centerTitle: true,
title: Text("Tirthankar",
style: TextStyle(color: Colors.white),),
),
backgroundColor: AppColors.styleColor,
body: Column(
children: <Widget>[
// SizedBox(height: 5),
Padding(
padding: const EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
CustomGridWidget(
child: Icon(
Icons.file_download,
size: 100,
color: AppColors.styleColor,
),
// image: 'assets/bhaktambar.png',
sizew: MediaQuery.of(context).size.width * .4,
sizeh: MediaQuery.of(context).size.width * .5,
borderWidth: 2,
label: "Bhakti",
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ListPage(appname: "Kids",playingId: playingId,),
),
);
},
),
CustomGridWidget(
child: Icon(
Icons.file_download,
size: 100,
color: AppColors.styleColor,
),
// image: 'assets/bhaktambar.png',
sizew: MediaQuery.of(context).size.width * .4,
sizeh: MediaQuery.of(context).size.width * .5,
borderWidth: 2,
label: "Kids",
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ListPage(appname: "Kids",playingId: playingId,),
),
);
},
),
],
),
),
Padding(
padding: const EdgeInsets.only(
left: 20,
right: 20,
bottom: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
CustomGridWidget(
child: Icon(
Icons.favorite,
size: 100,
color: AppColors.styleColor,
),
// image: 'assets/kids.jpg',
sizew: MediaQuery.of(context).size.width * .4,
sizeh: MediaQuery.of(context).size.width * .5,
borderWidth: 2,
label: "Favorite",
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ListPage(appname: "Songs"),
),
);
},
),
Align(
alignment: Alignment.center,
child: CustomGridWidget(
child: Icon(
Icons.book,
size: 100,
color: AppColors.styleColor,
),
// image: 'assets/vidyasagar.jpg',
sizew: MediaQuery.of(context).size.width * .4,
sizeh: MediaQuery.of(context).size.width * .5,
borderWidth: 2,
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ListPage(appname: "Bhajan"),
),
);
},
),
),
],
),
),
]
),
);
}
Material boxTiles(IconData icon, String name){
return Material(
color: AppColors.mainColor,
elevation: 14.0,
shadowColor: AppColors.styleColor,
borderRadius: BorderRadius.circular(24.0),
child: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child:Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
InkWell(
onTap: (){print("tapped"); /* or any action you want */ },
child: Container(
width: 130.0,
height: 10.0,
color : Colors.transparent,
), // container
), //
//Text
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(name,
style:TextStyle(
color: AppColors.styleColor,
fontSize: 20.0,
)
),
),
//Icon
Material(
color: AppColors.styleColor,
borderRadius: BorderRadius.circular(50.0),
child: Padding(padding: const EdgeInsets.all(10.0),
child: Icon(icon, color: AppColors.lightBlue,size: 30,),
),
),
],
)
],
)
),
)
);
}
}
Screen 2 -
// import 'dart:js';
class ListPage extends StatefulWidget {
String appname;
int playingId;
ListPage({this.appname,this.playingId});
#override
_ListPageState createState() => _ListPageState(appname,playingId);
}
class _ListPageState extends State<ListPage>
with SingleTickerProviderStateMixin,AutomaticKeepAliveClientMixin<ListPage> {
String appname;
int playingId;
bool isPlaying = false;
_ListPageState(this.appname,playingId);
// List<MusicModel> _list1;
List<MusicData> _list;
var _value;
int _playId;
int _songId;
String _playURL;
bool _isRepeat;
bool _isShuffle;
bool _isFavorite;
String _startTime;
String _endTime;
AnimationController _controller;
Duration _duration = new Duration();
Duration _position = new Duration();
final _random = new Random();
AudioPlayer _audioPlayer = AudioPlayer();
#override
void initState() {
_playId = 0;
// _list1 = MusicModel.list;
this._fileUpdate();
// _list = _list1;
_controller =
AnimationController(vsync: this, duration: Duration(microseconds: 250));
_value = 0.0;
_startTime = "0.0";
_endTime = "0.0";
_isRepeat = false;
_isShuffle = false;
_isFavorite = false;
_audioPlayer.onAudioPositionChanged.listen((Duration duration) {
setState(() {
// _startTime = duration.toString().split(".")[0];
_startTime = duration.toString().split(".")[0];
_duration = duration;
// _position = duration.toString().split(".")[0];
});
});
_audioPlayer.onDurationChanged.listen((Duration duration) {
setState(() {
_endTime = duration.toString().split(".")[0];
_position = duration;
});
});
_audioPlayer.onPlayerCompletion.listen((event) {
setState(() {
isPlaying = false;
_position = _duration;
if (_isRepeat) {
_songId = _songId;
} else {
if (_isShuffle) {
var element = _list[_random.nextInt(_list.length)];
_songId = element.id;
} else {
_songId = _songId + 1;
}
}
_player(_songId);
});
});
super.initState();
}
bool get wantKeepAlive => true;
#override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: AppColors.mainColor,
centerTitle: true,
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: (){
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => Dashboard(playingId: _songId),
),
);
},
),
title: Text(
appname,
style: TextStyle(color: AppColors.styleColor),
),
),
backgroundColor: AppColors.mainColor,
body: Stack(
children: <Widget>[
Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(24.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
CustomButtonWidget(
child: Icon(
Icons.favorite,
color: AppColors.styleColor,
),
size: 50,
onTap: () {},
),
CustomButtonWidget(
image: 'assets/logo.jpg',
size: 100,
borderWidth: 5,
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => DetailPage(),
),
);
},
),
CustomButtonWidget(
child: Icon(
Icons.menu,
color: AppColors.styleColor,
),
size: 50,
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => HomePage(),
),
);
},
)
],
),
),
slider(),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(
icon: Icon(
_isRepeat ? Icons.repeat_one : Icons.repeat,
color: _isRepeat ? Colors.brown : AppColors.styleColor,
),
onPressed: () {
if (_isRepeat) {
_isRepeat = false;
} else {
_isRepeat = true;
}
},
),
IconButton(
icon: Icon(
isPlaying ? Icons.pause : Icons.play_arrow,
color: AppColors.styleColor,
),
onPressed: () {
if (isPlaying) {
_audioPlayer.pause();
setState(() {
isPlaying = false;
});
} else {
if (!isPlaying){
_audioPlayer.resume();
setState(() {
isPlaying = true;
});
}
}
}),
IconButton(
icon: Icon(
Icons.stop,
color: AppColors.styleColor,
),
onPressed: () {
if (isPlaying){
_audioPlayer.stop();
setState(() {
isPlaying = false;
_duration = new Duration();
});
}
// isPlaying = false;
}),
IconButton(
icon: Icon(
Icons.shuffle,
color:
_isShuffle ? Colors.brown : AppColors.styleColor,
),
onPressed: () {
if (_isShuffle) {
_isShuffle = false;
} else {
_isShuffle = true;
}
}),
],
),
),
Expanded(
//This is added so we can see overlay else this will be over button
child: ListView.builder(
physics:
BouncingScrollPhysics(), //This line removes the dark flash when you are at the begining or end of list menu. Just uncomment for
// itemCount: _list.length,
itemCount: _list == null ? 0 : _list.length,
padding: EdgeInsets.all(12),
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
_songId = index;
_player(index);
},
child: AnimatedContainer(
duration: Duration(milliseconds: 500),
//This below code will change the color of sected area or song being played.
decoration: BoxDecoration(
color: _list[index].id == _playId
? AppColors.activeColor
: AppColors.mainColor,
borderRadius: BorderRadius.all(
Radius.circular(20),
),
),
//End of row color change
child: Padding(
padding: const EdgeInsets.all(
16), //This will all padding around all size
child: Row(
mainAxisAlignment: MainAxisAlignment
.spaceBetween, //This will allign button to left, else button will be infront of name
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
_list[index].title,
style: TextStyle(
color: AppColors.styleColor,
fontSize: 16,
),
),
Text(
_list[index].album,
style: TextStyle(
color: AppColors.styleColor.withAlpha(90),
fontSize: 16,
),
),
],
),
IconButton(
icon: Icon(_isFavorite
? Icons.favorite
: Icons.favorite_border),
onPressed: () {
if (_isFavorite) {
_isFavorite = false;
} else {
_isFavorite = true;
}
})
//Diabled Play button and added fav button.
// CustomButtonWidget(
// //This is Play button functionality on list page.
// child: Icon(
// _list[index].id == _playId
// ? Icons.pause
// : Icons.play_arrow,
// color: _list[index].id == _playId
// ? Colors.white
// : AppColors.styleColor,
// ),
// size: 50,
// isActive: _list[index].id == _playId,
// onTap: () async {
// _songId = index;
// _player(index);
// },
// )
],
),
),
),
);
},
),
)
],
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
height: 50,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
AppColors.mainColor.withAlpha(0),
AppColors.mainColor,
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
)),
),
)
],
),
// floatingActionButton: FloatingActionButton(
// child: Icon(Icons.music_note),
// onPressed: () async { // String filePath = await FilePicker.getFilePath();
// int status = await _audioPlayer.play("https://traffic.libsyn.com/voicebot/Jan_Konig_on_the_Jovo_Open_Source_Framework_for_Voice_App_Development_-_Voicebot_Podcast_Ep_56.mp3");
// if (status == 1){
// setState(() {
// isPlaying = true;
// });
// }
// },
// )
);
}
Widget slider() {
return Slider(
activeColor: AppColors.styleColor,
inactiveColor: Colors.lightBlue,
value: _duration.inSeconds.toDouble(),
min: 0.0,
max: _position.inSeconds.toDouble(),
divisions: 10,
onChangeStart: (double value) {
print('Start value is ' + value.toString());
},
onChangeEnd: (double value) {
print('Finish value is ' + value.toString());
},
onChanged: (double value) {
setState(() {
seekToSecond(value.toInt());
value = value;
});
});
}
Future<Void> _fileUpdate() async {
String url =
"azonaws.com/input.json";
String arrayObjsText = "";
try {
eos.Response response;
Dio dio = new Dio();
response = await dio.get(url,options: Options(
responseType: ResponseType.plain,
),);
arrayObjsText = response.data;
print(response.data.toString());
} catch (e) {
print(e);
}
var tagObjsJson = jsonDecode(arrayObjsText)['tags'] as List;
this.setState(() {
_list = tagObjsJson.map((tagJson) => MusicData.fromJson(tagJson)).toList();
});
// return _list;
// print(_list);
}
Future<void> _player(int index) async {
if (isPlaying) {
if (_playId == _list[index].id) {
int status = await _audioPlayer.pause();
if (status == 1) {
setState(() {
isPlaying = false;
});
}
} else {
_playId = _list[index].id;
_playURL = _list[index].songURL;
_audioPlayer.stop();
int status = await _audioPlayer.play(_playURL);
if (status == 1) {
setState(() {
isPlaying = true;
});
}
}
} else {
_playId = _list[index].id;
_playURL = _list[index].songURL;
int status = await _audioPlayer.play(_playURL);
if (status == 1) {
setState(() {
isPlaying = true;
});
}
}
}
String _printDuration(Duration duration) {
String twoDigits(int n) {
if (n >= 10) return "$n";
return "0$n";
}
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
return "${twoDigits(duration.inHours)}:$twoDigitMinutes:$twoDigitSeconds";
}
void seekToSecond(int second) {
Duration newDuration = Duration(seconds: second);
_audioPlayer.seek(newDuration);
}
}
PageStorage is 3rd option i saw but i found majority of the time this is being used on app where we have a tab.
You still can use this approach with what you want, with or without Tab/ bottom navigation bar.
PageViewClass
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> with SingleTickerProviderStateMixin{
PageController _pageController;
#override
void initState() {
super.initState();
_pageController = PageController();
}
#override
void dispose() {
super.dispose();
_pageController?.dispose();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: PageView(
controller: _pageController,
physics: NeverScrollableScrollPhysics(), // so the user cannot scroll, only animating when they select an option
children: <Widget>[
Dashboard(playingId: 1, key: PageStorageKey<String>('MyPlayList'), pageController: _pageController), //or the name you want, but you need to give them a key to all the child so it can save the Scroll Position
ListPage(appname: "FirstButton",playingId: 1, key: PageStorageKey<String>('FirstButton'), pageController: _pageController),
ListPage(appname: "SecondButton",playingId: 1, key: PageStorageKey<String>('SecondButton'), pageController: _pageController),
ListPage(appname: "ThirdButton",playingId: 1, key: PageStorageKey<String>('ThirdButton'), pageController: _pageController),
ListPage(appname: "FourthButton",playingId: 1, key: PageStorageKey<String>('FourthButton'), pageController: _pageController)
],
),
)
);
}
}
Now you pass the PageController to all children (add a key and PageController attribute to Screen 1 and 2) and in DashBoard (Screen 1) you can change the onTap of the buttons from the MaterialRoute to this
onTap: () => widget.pageController.jumpToPage(x), //where x is the index of the children of the PageView you want to see (between 0 and 4 in this case)
In Screen 2 you wrap all your Scaffold with a WillPopScope so when the user tap back instead of closing the route it goes back to the Dashboard Widget at index 0
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
widget.pageController.jumpToPage(0); // Move back to dashboard (index 0)
return false;
}
child: Scaffold(...)
);
}
You can use other methods of PageController if you want some effects like animations (animateTo, nextPage, previousPage, etc.)
I am new to flutter and trying to solve the below issue, in the first screenshot I have labelStart line 127 value as 1.21, when i pass that value using the variable i get renderflex error, if i am using hardcoded i don't get any error. Not sure what i am doing wrong. I tried adding Expanded after reading few posts online but that didn't help. Can someone please guide me on what mistake i am doing here?
class _ListPageState extends State<ListPage> with SingleTickerProviderStateMixin {
List<MusicModel> _list;
var _value;
int _playId;
String _playURL;
bool isPlaying = false;
String _startTime;
String _endTime;
AnimationController _controller;
AudioPlayer _audioPlayer = AudioPlayer();
#override
void initState() {
_playId = 0;
_list = MusicModel.list;
_controller = AnimationController(vsync: this,duration: Duration(microseconds: 250));
_value = 0.0;
_startTime="0.0";
_endTime="0.0";
super.initState();
_audioPlayer.onAudioPositionChanged.listen((Duration duration) {
setState(() {
_startTime = duration.toString().split(".")[0];
});
});
_audioPlayer.onDurationChanged.listen((Duration duration) {
setState(() {
_endTime = duration.toString().split(".")[0];
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: AppColors.mainColor,
centerTitle: true,
title: Text("Skin - Flume",
style: TextStyle(color: AppColors.styleColor),),
),
backgroundColor: AppColors.mainColor,
body: Stack(
children: <Widget>[
Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(24.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
CustomButtonWidget(
child: Icon(
Icons.favorite,
color: AppColors.styleColor,
),
size: 50,
onTap: (){
},
),
CustomButtonWidget(
image: 'assets/logo.jpg',
size: 100,
borderWidth: 5,
onTap: (){
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => DetailPage(),
),
);
},
),
CustomButtonWidget(
child: Icon(
Icons.menu,
color: AppColors.styleColor,
),
size: 50,
onTap: (){
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => HomePage(),
),
);
},
)
],
),
),
//Progress bar section
// Expanded(child: SizedBox()),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: CustomProgressWidget(
value: _value,
labelStart: "1.21",
labelend: "2.34",
),
),
// Expanded(child: SizedBox()),
Expanded( //This is added so we can see overlay else this will be over button
child: ListView.builder(
physics: BouncingScrollPhysics(),//This line removes the dark flash when you are at the begining or end of list menu. Just uncomment for
itemCount: _list.length,
padding: EdgeInsets.all(12),
itemBuilder: (context,index){
return GestureDetector(
onTap: (){
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => DetailPage(),
),
);
},
child: AnimatedContainer(
duration: Duration(milliseconds: 500),
//This below code will change the color of sected area or song being played.
decoration: BoxDecoration(
color: _list[index].id == _playId
? AppColors.activeColor
: AppColors.mainColor,
borderRadius: BorderRadius.all(
Radius.circular(20),
),
),
//End of row color change
child: Padding(
padding: const EdgeInsets.all(16), //This will all padding around all size
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, //This will allign button to left, else button will be infront of name
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
_list[index].title,
style: TextStyle(
color: AppColors.styleColor,
fontSize: 16,
),
),
Text(
_list[index].album,
style: TextStyle(
color: AppColors.styleColor.withAlpha(90),
fontSize: 16,
),
),
],
),
CustomButtonWidget( //This is Play button functionality on list page.
child: Icon(
_list[index].id == _playId
? Icons.pause
: Icons.play_arrow,
color: _list[index].id == _playId
? Colors.white
: AppColors.styleColor,
),
size: 50,
isActive: _list[index].id == _playId,
onTap: () async {
if (isPlaying){
if (_playId == _list[index].id){
int status = await _audioPlayer.pause();
if (status == 1){
setState(() {
isPlaying = false;
});
}
} else {
_playId = _list[index].id;
_playURL = _list[index].songURL;
_audioPlayer.stop();
int status = await _audioPlayer.play(_playURL);
if (status == 1){
setState(() {
isPlaying = true;
});
}
}
// int status = await _audioPlayer.pause();
// if (status == 1){
// setState(() {
// isPlaying = false;
// });
// }
} else {
_playId = _list[index].id;
_playURL = _list[index].songURL;
int status = await _audioPlayer.play(_playURL);
if (status == 1){
setState(() {
isPlaying = true;
});
}
} // String filePath = await FilePicker.getFilePath();
},
// onTap: (){
// setState(() {
// _playId = _list[index].id;
// });
// },
)
],
),
),
),
);
},
),
)
],
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
height: 50,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
AppColors.mainColor.withAlpha(0),
AppColors.mainColor,
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
)
),
),
)
],
),
);
}
}
After changing line 1.27 with a dynamic value variable.
You have to wrap you Column in a scrollview like SingleChildScrollView or ListView. This error occurs when the items in column take more space than available.
I had the same problem, and my problem was my variable extracted of my state it took too long in show and showed first the widget after the variable.
In my case use Getx, and fixed for this way:
My old code:
GetX<UserController>(
builder: (_){
return Text(_.user.name);
}
},
),
My new code
GetX<UserController>(
builder: (_){
if(_.user.email != null){
return Text(_.user.name);
}else{
return Text('Loading....');
}
},
),