So I loaded up my flutter project after a few hours of not working on it, and when I try to click on a button that is supposed to root me to a specific page, the whole app freezes. The last time I ran it, it was working fine, and I haven't changed anything. I have restarted the program, and my pc and it still freezes. All other button that root to pages work so I assume it is a problem with the code of that page. This is the entire code for that page:
import 'package:flutter/material.dart';
import 'package:workwise2/classes/taskClass.dart';
import 'package:workwise2/config.dart';
class TodoTasks extends StatefulWidget {
#override
_TodoTasksState createState() => _TodoTasksState();
}
class _TodoTasksState extends State<TodoTasks> {
Settings settings = Settings();
BottomNavBarConfig bottomNavBarConfig = BottomNavBarConfig();
List <Task> tasks = [
Task(title: "Maths HW", description: "Complete Q2, Q6 and Q7 with GPCs on Q8", subject: "maths", day: 12, month: 4, year: 2021),
Task(title: "English test", description: "Revise quotes for anger", subject: "english", day: 13, month: 4, year: 2021),
];
#override
Widget build(BuildContext context) {
int _currentIndex = 0;
String _requestedPage;
return Scaffold(
appBar: AppBar(
title: Text(
"Tasks",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 30.0
),
),
backgroundColor: Colors.indigoAccent[700],
leading: Icon(Icons.check_box_rounded, size: 40.0,),
),
body: AnimatedContainer(
duration: Duration(milliseconds: 1700),
child: ListView.builder(
itemBuilder: (context, index) {
Color _checkButtonColour;
double _checkButtonElevation;
IconData _bookmark = Icons.bookmark_border;
if (tasks[index].state == "todo") {
_checkButtonColour = Colors.red[600];
_checkButtonElevation = 0.0;
}
else if (tasks[index].state == "doing") {
_checkButtonColour = Colors.amber;
_checkButtonElevation = 5.0;
}
else if (tasks[index].state == "done") {
_checkButtonColour = Colors.green;
_checkButtonElevation = 10.0;
}
while (tasks[index].favourited == true) {
_bookmark = Icons.bookmark;
}
while (tasks[index].favourited == false) {
_bookmark = Icons.bookmark_border;
}
return Padding(
padding: EdgeInsets.symmetric(horizontal: 8.0, vertical: 3.0),
child: Card(
elevation: 10.0,
child: ListTile(
contentPadding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 5.0),
onTap: () {},
leading: IconButton(
onPressed: () {
tasks[index].favourited = !tasks[index].favourited;
print(tasks[index].favourited);
},
icon: Icon(_bookmark),
iconSize: 35.0,
color: settings.subjectColours[tasks[index].subject]
),
title: Text(tasks[index].title, maxLines: 1, overflow: TextOverflow.fade,),
subtitle: Text(tasks[index].description, maxLines: 1, overflow: TextOverflow.ellipsis,),
trailing: AnimatedContainer(
height: 80.0,
width: 100.0,
duration: Duration(milliseconds: 1700),
child: Row(
children: <Widget> [
SizedBox(
width: 40.0,
height: 40.0,
child: MaterialButton(
elevation: _checkButtonElevation,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(6.0)),
onPressed: () {
if (tasks[index].state == "todo") {
setState(() {
tasks[index].state = "doing";
});
} else if (tasks[index].state == "doing") {
setState(() {
tasks[index].state = "done";
});
} else if (tasks[index].state == "done") {
setState(() {
tasks[index].state = "todo";
});
}
},
padding: EdgeInsets.all(2.0),
color: _checkButtonColour,
),
),
IconButton(
onPressed: () {},
icon: Icon(Icons.more_vert),
)
],
),
),
),
),
);
},
itemCount: tasks.length,
)
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
backgroundColor: Colors.indigoAccent[700],
fixedColor: Colors.white,
unselectedFontSize: bottomNavBarConfig.unactiveTextSize,
unselectedIconTheme: IconThemeData(
size: bottomNavBarConfig.unactiveIconSize
),
selectedFontSize: bottomNavBarConfig.activeTextSize,
selectedIconTheme: IconThemeData(
size: bottomNavBarConfig.activeIconSize
),
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.check_box_rounded),
label: "Tasks"
),
BottomNavigationBarItem(
icon: Icon(Icons.lightbulb),
label: "Learn"
),
BottomNavigationBarItem(
icon: Icon(Icons.home_rounded),
label: "Home"
),
BottomNavigationBarItem(
icon: Icon(Icons.library_books_rounded),
label: "Notes"
),
],
onTap: (index) {
if (index == 0) {
_requestedPage = "/todotasks";
}
else if (index == 2) {
_requestedPage = "/home";
}
else if (index == 3) {
_requestedPage = "/notes";
}
else if (index == 1) {
_requestedPage = "/sets";
}
setState(() {
_currentIndex = index;
});
Navigator.popAndPushNamed(context, _requestedPage);
},
)
);
}
}
I don't know what is wrong. Please help me I have no clue what to do. Comment for more details.
This was caused due to the two while statements in my code. They basically called each other and froze the app.
Use
Navigator.of(context).pushNamedUntil(_requestedPage);
Related
I am developing an audio player application using Flutter, I am using on_audio_query package to get audio files from device storage, and just_audio package for the audio player.
when I created the project, in the audio player I used setState to handle state management, and now, I want to convert to bloc pattern but when I tried to do that I faced a lot of issues and couldn't fix them.
I will attach the code of the audio player and also basic cubit code and if someone guided me or showed me how to convert I would appreciate it.
I'm sorry if the code is confusing but I don't know how to add it correctly.
audio player code
import 'package:just_audio/just_audio.dart';
import 'package:dorosi/shared/ui/my_icon.dart';
import 'package:dorosi/shared/ui/my_text.dart';
import 'package:flutter/material.dart';
import 'package:on_audio_query/on_audio_query.dart';
class AudioPlayerWithUrl extends StatefulWidget {
final SongModel songModel;
const AudioPlayerWithUrl({required this.songModel, Key? key})
: super(key: key);
#override
State<AudioPlayerWithUrl> createState() => _AudioPlayerWithUrlState();
}
class _AudioPlayerWithUrlState extends State<AudioPlayerWithUrl> {
final audioPlayer = AudioPlayer();
bool isPlaying = false;
Duration duration = const Duration();
Duration position = const Duration();
bool isPressed = false;
#override
void initState() {
super.initState();
setAudio();
playAudio();
}
Future setAudio() async {
audioPlayer.setLoopMode(LoopMode.off);
audioPlayer.setAudioSource(
AudioSource.uri(
Uri.parse(widget.songModel.uri!),
),
);
isPlaying = true;
audioPlayer.durationStream.listen((audioDuration) {
setState(() {
duration = audioDuration!;
});
});
audioPlayer.positionStream.listen((audioPosition) {
setState(() {
position = audioPosition;
});
});
}
#override
void dispose() {
audioPlayer.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const MyText(
writtenText: 'Now Playing',
textSize: 23,
textColor: Colors.black,
),
leading: IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: const MyIcon(
icon: Icons.arrow_back,
iconColor: Colors.black,
)),
centerTitle: true,
backgroundColor: Colors.transparent,
elevation: 0,
actions: [
IconButton(
onPressed: () {},
icon: const MyIcon(
icon: Icons.more_vert,
iconColor: Colors.black,
),
),
const SizedBox(width: 10)
],
),
body: SafeArea(
child: SingleChildScrollView(
child: Column(
children: [
const SizedBox(height: 15),
const CircleAvatar(
backgroundColor: Color(0xFFc61104),
radius: 100,
child: MyIcon(
icon: Icons.music_note,
iconSize: 100,
iconColor: Colors.white,
),
),
const SizedBox(
height: 15,
),
const SizedBox(height: 15),
MyText(
writtenText: widget.songModel.title,
textSize: 24,
textWeight: FontWeight.bold,
),
const SizedBox(height: 4),
MyText(
writtenText: widget.songModel.album!,
textSize: 20,
),
const SizedBox(height: 10),
Slider(
activeColor: Colors.orange,
inactiveColor: Colors.black87,
min: 0,
max: duration.inSeconds.toDouble(),
value: position.inSeconds.toDouble(),
onChanged: (value) async {
isPlaying = true;
final position = Duration(seconds: value.toInt());
await audioPlayer.seek(position);
await audioPlayer.play();
}),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MyText(
writtenText: formatTime(position),
textWeight: FontWeight.bold),
TextButton(
style: TextButton.styleFrom(primary: Colors.black),
onPressed: () {
setState(() {
showRemainingTime();
isPressed = !isPressed;
});
},
child: isPressed
? showRemainingTime()
: MyText(
writtenText: ' ${formatTime(duration)}',
textWeight: FontWeight.bold,
),
),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircleAvatar(
backgroundColor: const Color(0xFFc61104),
radius: 23,
child: IconButton(
onPressed: () async {
if (position >= const Duration(seconds: 10)) {
seekTo(position.inSeconds - 10);
} else {
setState(() {
seekTo(const Duration(seconds: 0).inSeconds);
isPlaying = false;
});
pauseAudio();
}
},
icon: const MyIcon(
icon: Icons.settings_backup_restore,
iconSize: 30,
iconColor: Colors.white,
)),
),
const SizedBox(width: 40),
CircleAvatar(
backgroundColor: const Color(0xFFc61104),
radius: 35,
child: IconButton(
icon: Icon(
isPlaying ? Icons.pause : Icons.play_arrow,
color: Colors.white,
),
iconSize: 50,
onPressed: () {
setState(() {
if (isPlaying) {
pauseAudio();
} else {
playAudio();
}
isPlaying = !isPlaying;
});
},
),
),
const SizedBox(width: 40),
CircleAvatar(
radius: 23,
backgroundColor: const Color(0xFFc61104),
child: IconButton(
onPressed: () async {
if (position < duration - const Duration(seconds: 10)) {
seekTo(position.inSeconds + 10);
} else {
setState(() {
seekTo(duration.inSeconds);
isPlaying = false;
});
pauseAudio();
}
},
icon: const MyIcon(
icon: Icons.forward_10,
iconSize: 30,
iconColor: Colors.white,
)),
),
],
),
const SizedBox(height: 15),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(width: 40),
ElevatedButton(
style: ElevatedButton.styleFrom(primary: Colors.orange),
onPressed: () {
setState(() {
if (audioPlayer.speed == 1) {
adjustAudioSpeed();
debugPrint('${audioPlayer.speed}');
} else if (audioPlayer.speed == 1.25) {
adjustAudioSpeed2();
} else if (audioPlayer.speed == 1.5) {
adjustAudioSpeed3();
} else if (audioPlayer.speed == 1.75) {
adjustAudioSpeed4();
} else if (audioPlayer.speed == 2) {
setAudioNormalSpeed();
}
});
},
child: MyText(
writtenText: '${audioPlayer.speed}',
textSize: 18,
textColor: Colors.black,
)),
const SizedBox(width: 40),
],
)
],
),
)),
);
}
Widget showRemainingTime() {
return MyText(
writtenText: '- ${formatTime(duration - position)}',
textWeight: FontWeight.bold,
);
}
seekTo(int seconds) {
audioPlayer.seek(Duration(seconds: seconds));
}
playAudio() {
audioPlayer.play();
}
pauseAudio() {
audioPlayer.pause();
}
setAudioNormalSpeed() {
audioPlayer.setSpeed(1);
}
adjustAudioSpeed() {
audioPlayer.setSpeed(1.25);
}
adjustAudioSpeed2() {
audioPlayer.setSpeed(1.5);
}
adjustAudioSpeed3() {
audioPlayer.setSpeed(1.75);
}
adjustAudioSpeed4() {
audioPlayer.setSpeed(2);
}
playNextAudio() {
audioPlayer.seekToNext();
}
playPreviousAudio() {
audioPlayer.seekToPrevious();
}
String formatTime(Duration duration) {
String twoDigits(int n) => n.toString().padLeft(2, '0');
final hours = twoDigits(duration.inHours);
final minutes = twoDigits(duration.inMinutes.remainder(60));
final seconds = twoDigits(duration.inSeconds.remainder(60));
return [
if (duration.inHours > 0) hours,
minutes,
seconds,
].join(':');
}
}
player cubit code
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:meta/meta.dart';
part 'player_state.dart';
class PlayerCubit extends Cubit<PlayerState> {
static PlayerCubit get(context) => BlocProvider.of(context);
PlayerCubit() : super(PlayerInitialState());
}
player state code
part of 'player_cubit.dart';
#immutable
abstract class PlayerState {}
class PlayerInitialState extends PlayerState {}
class PlayerPlayingState extends PlayerState {}
class PlayerPauseState extends PlayerState {}
I'm implementing some custom buttons using this package:
bottom_bar_with_sheet 2.1.0
I added the following code snippet below, but I am not able to remove the default selection of the button when clicking on the child buttons I have been trying in many ways but not being able to progress.
bottomNavigationBar: BottomBarWithSheet(
// selectedIndex: selectedPosition > 3 ? 4 : _selectedIndex,
selectedIndex: _selectedIndex,
controller: _bottomBarController,
onSelectItem: (index) {
setState(() {
_selectedIndex = selectedPosition > 3 ? -1 : index;
});
},
and in the action button of the child I did like this:
setState(() {
selectedPosition = posicao;
_selectedIndex = posicao;
});
Thanks in advance for all the help.
One of my problems was solved how can I add navigation where each button would lead to a parent route of a view, and this view will have other screen possibilities, where it will have routes too, what better way to do that in this plugin
using good practice like mobx?
this is the code in a single file, but I would like to separate the components.
import 'package:bottom_bar_with_sheet/bottom_bar_with_sheet.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
iconTheme: IconThemeData(
color: Colors.blue,
),
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final _bottomBarController = BottomBarWithSheetController(initialIndex: -1);
int selectedPosition = 4;
int _selectedIndex = -1;
#override
void initState() {
_bottomBarController.itemsStream.listen((i) {
if( i < 4 )
{
setState(() {
selectedPosition = -1;
_selectedIndex = i;
});
}
switch(i)
{
// case "HOME" : FutureBuilder: Navigator.pushReplacement(context, MaterialPageRoute(builder: (context)=> Home())); break;
case 0: print("Acesso rápido 0");break;
case 1: print("Acesso rápido 1");break;
case 2: print("Acesso rápido 2");break;
case 3: print("Acesso rápido 3");break;
}
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blue,
body: Center(
child: Text(
"Criar navegacao aqui",
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.w900,
),
),
),
bottomNavigationBar: BottomBarWithSheet(
selectedIndex:_selectedIndex,
controller: _bottomBarController,
bottomBarTheme: BottomBarTheme(
mainButtonPosition: MainButtonPosition.middle, // posicao do botao de 'mais -> (+)'
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(25)),
),
itemIconColor: Colors.grey,
itemTextStyle: TextStyle(
color: Colors.grey,
fontSize: 10.0,
),
selectedItemTextStyle: TextStyle(
color: Colors.blue,
fontSize: 10.0,
),
),
onSelectItem: (index) {
setState(() {
_selectedIndex = index;
});
},
sheetChild: Padding(
padding: EdgeInsets.only(top:10,bottom:6),
child:Column(
children: <Widget>[
Divider(
height: 10,
thickness: 2,
color: Colors.blue,
indent: 0,
),
Expanded(
child: GridView.count(
physics: NeverScrollableScrollPhysics(), //kill scrollable
// shrinkWrap: true,
crossAxisCount: 4,
children: <Widget>[
_createBottomBarSheetChild(context, 'Home', Icons.api_sharp, _routeMenu, 4),
_createBottomBarSheetChild(context, 'Produto', Icons.apartment, _routeMenu, 5),
_createBottomBarSheetChild(context, 'Cliente', Icons.person, _routeMenu, 6),
_createBottomBarSheetChild(context, 'Proposta', Icons.account_balance_wallet_outlined, _routeMenu, 7),
],
),
),
Expanded(
child: GridView.count(
physics: NeverScrollableScrollPhysics(), //kill scrollable
// shrinkWrap: true,
crossAxisCount: 4,
children: <Widget>[
_createBottomBarSheetChild(context, 'Reservas', Icons.add_location_rounded, _routeMenu, 8),
_createBottomBarSheetChild(context, 'Unidade', Icons.workspaces_filled, _routeMenu, 9),
_createBottomBarSheetChild(context, 'Contratos', Icons.work, _routeMenu, 10),
_createBottomBarSheetChild(context, 'Tarefas', Icons.calendar_today, _routeMenu, 11),
],
),
),
],
),
),
items: [
BottomBarWithSheetItem(label: "Notas",icon: Icons.notes),
BottomBarWithSheetItem(label: "Perfil",icon: Icons.account_circle),
BottomBarWithSheetItem(label: "Configurações",icon: Icons.settings),
BottomBarWithSheetItem(label: "Alertas",icon: Icons.add_alert),
],
),
);
}
#override
Widget _createBottomBarSheetChild(BuildContext context, String name, IconData icon, Function action, posicao)
{
return GestureDetector(
child: Card(
elevation: 0,
margin: EdgeInsets.only(
left: 3.0,
top: 25,
right: 3.0
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Icon(
icon,
size: 26,
color: selectedPosition == posicao ? Colors.blue : Colors.grey,
),
Container(
margin: EdgeInsets.only(top: 4, bottom: 6, ),
child: Column(
children: [
Text(
name,
// textAlign: TextAlign.center,
style: TextStyle(
color: selectedPosition == posicao ?
Colors.blue :
Colors.grey,
),
),
Divider(
height: 16,
thickness: 2,
color: selectedPosition == posicao ? Colors.blue : Colors.grey,
indent: 30,
endIndent:30
),
],
)
),
],
),
),
onTap: () {
// Navigator.pop(context);
setState(() {
selectedPosition = posicao;
_bottomBarController.selectItem(posicao);
});
Navigator.of(context);
action(context, name, posicao);
},
);
}
_routeMenu(context, rota, posicao)
{
print("rota ${rota.toUpperCase()}");
switch(rota.toUpperCase())
{
case "HOME" :""; posicao = 5;break;
case "PRODUTO":"";posicao = 6;break;
case "CLIENTE": "";posicao = 7; break;
case "PROPOSTA": "";posicao = 8; break;
case "RESERVA": "";posicao = 9; break;
case "UNIDADE": "";posicao = 10; break;
case "NOVIDADE": "";posicao = 11; break;
case "TAREFAS": "";posicao = 12; break;
}
}
}
I'm trying to create a custom TabBar which navigates only forward with a button click.
im using an enum to manage the state and couple of class objects to manage items for Tabs.
What result I expected
VS
What result I've got
The code I worked out is as follows. I am still trying to figure out a way of managing the expected outcome with my code implementation. if anyone can help out will be amazing.
Object classes
class CategoryModel {
final String? title;
final eCategory category;
// final eCategoryState? catState;
CategoryModel({this.title, required this.category});
}
class CategoryStateModel {
final CategoryModel? tItem;
late eTabState? tState;
CategoryStateModel({this.tItem, this.tState});
}
The code portion
class _ContributeTabScreenState extends State<ContributeTabScreen>
with SingleTickerProviderStateMixin {
eButtonState _submitBtnState = eButtonState.bActive;
eButtonState _continueBtnState = eButtonState.bActive;
int pageNo = 0;
TabController? _tabController;
late List<eTabState>? _tabState = [];
late List<CategoryModel>? _categoryModelList = [];
late List<Tab>? _tabList = [];
late List<CategoryStateModel>? _catStateList = [];
#override
void initState() {
_categoryModelList = widget.catList;
_assignTabs();
_tabController = new TabController(
vsync: this,
length: _categoryModelList!.length, //3,
);
super.initState();
// print(_categoryModelList![0].title.toString());
}
List<Tab> _assignTabs() {
for (var item = 0; item < _categoryModelList!.length; item++) {
//
if (item != 0) {
for (var t in _categoryModelList!) {
_catStateList!.add(
new CategoryStateModel(tItem: t, tState: eTabState.tUnSelected));
}
} else {
for (var t in _categoryModelList!) {
_catStateList!.add(
new CategoryStateModel(tItem: t, tState: eTabState.tSelected));
}
}
//
_tabList!.add(
new Tab(
child: _tabItem(_catStateList![item]),
// child: _tabItem(_categoryModelList![item]),
),
);
}
return _tabList!;
}
void _goBack() {
Navigator.of(context).pop();
}
//the onPressed call back I manage the forward move of a tabbar item + tabview
void forwardTabPage() {
if (pageNo >= 0 && pageNo < _categoryModelList!.length) {
setState(() {
// });
// setState(() {
pageNo = pageNo + 1;
// _catStateList![pageNo - 1].tState = eTabState.tCompleted;
// _tabState![pageNo - 1] = _catStateList![pageNo - 1].tState!;
});
_tabController!.animateTo(pageNo);
}
}
...rest of the code
//the Tabbar item
_tabItem(CategoryStateModel item) => Container(
width: 140.0,
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
item.tItem!.title!,
style: tBody4.copyWith(color: CustomColors.mDarkBlue),
),
item.tState == _catStateList![pageNo].tState //eTabState.tCompleted
? SizedBox(
width: 8.0,
)
: SizedBox(
width: 0.0,
),
item.tState == _catStateList![pageNo].tState //eTabState.tCompleted
? CircleAvatar(
radius: 12.0,
backgroundColor: CustomColors.green600,
child: Icon(
Icons.check_outlined,
size: 20.0,
),
)
: SizedBox(
width: 0.0,
),
],
),
);
continueBtn() => ButtonWidget(
btnColor: CustomColors.green600,
borderColor: CustomColors.green600,
textColor: CustomColors.mWhite,
text: "Continue",
eButtonType: eButtonType.bText,
eButtonState: _continueBtnState,
onPressed: () {
forwardTabPage();
// _tabState = eTabState.tCompleted;
},
);
submitBtn() => ButtonWidget(
btnColor: CustomColors.green600,
borderColor: CustomColors.green600,
textColor: CustomColors.mWhite,
text: "Submit",
eButtonType: eButtonType.bText,
eButtonState: _submitBtnState,
onPressed: () {},
);
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: _categoryModelList!.length,
child: Scaffold(
appBar: AppBar(
toolbarHeight: 60.0,
leadingWidth: 100.0,
leading: GestureDetector(
onTap: _goBack,
child: Container(
child: Row(
children: [
SizedBox(
width: 16.0,
),
const Icon(
Icons.arrow_back_ios,
color: CustomColors.grey700,
size: 24.0,
),
Flexible(
child: Text(
"Back",
style: tButtonSmall,
),
),
],
),
),
),
backgroundColor: Colors.white,
elevation: 0.0,
bottom: PreferredSize(
preferredSize: Size.fromHeight(50.0),
child: IgnorePointer(
child: TabBar(
controller: _tabController,
isScrollable: false,
enableFeedback: false,
padding: EdgeInsets.only(bottom: 8.0),
indicatorSize: TabBarIndicatorSize.label,
indicator:
// _tabState == eTabState.tSelected
// ?
BoxDecoration(
borderRadius: BorderRadius.circular(40.0),
color: CustomColors.green300,
border: Border.all(color: CustomColors.mGreen, width: 2),
),
tabs: _tabList!
),
),
),
),
body: Container(
child: TabBarView(
controller: _tabController,
physics: NeverScrollableScrollPhysics(),
children: [
Container(
color: CustomColors.grey600.withOpacity(0.2),
child: Center(
child: Text("Home Tab View"),
),
),
Center(
child: Text("Map Tab View"),
),
],
),
),
persistentFooterButtons: [
Container(
width: MediaQuery.of(context).size.width,
// height: 40,
padding: EdgeInsets.symmetric(horizontal: 24.0),
margin: EdgeInsets.symmetric(vertical: 16.0),
child: (_categoryModelList!.length == 1 ||
pageNo == _categoryModelList!.length - 1)
? submitBtn()
: continueBtn(),
)
],
),
);
}
enum classes
enum eCategoryState {
cSelected,
cUnSelected,
cEnded,
}
enum eTabState {
tSelected,
tUnSelected,
tCompleted,
}
enum eCategory {
cAccess,
cAmenities,
}
I don't know if I understand what you mean or not. but try this. TabBar has a isScrollable property. set it to true
I am trying to align the bottom section on the page to center, this shows correctly on a Mobile device but in the web it looks off. How do I arrange all 4 music buttons and text able in the center of the page. I tried Align friand center but both didn't bring those to the center of the widget. My goal is to get a button in the center of page based on page size, if page size is small below code is good but when i maximize browser it doesn't show in center.
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: MediaQuery.of(context).size.width * 0.7,
// child: Expanded(child: slider()),
child: kIsWeb ? null : slider(),
),
Marquee(
child: Text(inuseAudioinfo.title ?? appname,
softWrap: true,
style: TextStyle(
// color: AppColors.black.withAlpha(90),
color: AppColors.black.withAlpha(150),
fontSize: 16,
)),
),
Container(
decoration: BoxDecoration(
border: Border(
top: BorderSide(color: Colors.red[300]),
// bottom: BorderSide(color: AppColors.white)
)),
child: Wrap(
spacing: kIsWeb
? MediaQuery.of(context).size.width * 0.1
: 25, // space between two icons
children: <Widget>[
IconButton(
icon: Icon(
inuseAudioinfo.isRepeat
? Icons.repeat_one
: Icons.repeat,
color: inuseAudioinfo.isRepeat
? AppColors.brown
: AppColors.black,
),
onPressed: () {
print("User clicked Repeat one.");
if (inuseAudioinfo.playId != null) {
Duration seekdur = new Duration(seconds: 10);
if (inuseAudioinfo.isRepeat) {
setState(() {
inuseAudioinfo.isRepeat = false;
});
} else {
setState(() {
inuseAudioinfo.isRepeat = true;
});
}
} else {
commonmethod.displayDialog(
context,
"",
"Please select song to play.",
Icon(
Icons.library_music,
size: 100,
color: AppColors.red200,
),
);
}
},
),
IconButton(
icon: Icon(
inuseAudioinfo.isPlaying
? Icons.pause
: Icons.play_arrow,
color: AppColors.black,
),
onPressed: () {
_player(_songId);
}),
IconButton(
icon: Icon(
Icons.stop,
color: AppColors.black,
),
onPressed: () {
if (inuseAudioinfo.isPlaying) {
// _inuseAudioinfo.audioPlayer.stop();
inuseAudioinfo.duration =
new Duration(seconds: 0);
inuseAudioinfo.audioPlayer.stop();
setState(() {
inuseAudioinfo.isPlaying = false;
// position = new Duration(seconds: 0);
// _duration = new Duration();
});
}
// isPlaying = false;
}),
IconButton(
icon: Icon(
Icons.shuffle,
color: inuseAudioinfo.isShuffle
? AppColors.brown
: AppColors.black,
),
onPressed: () {
if (inuseAudioinfo.isShuffle) {
setState(() {
inuseAudioinfo.isShuffle = false;
});
} else {
setState(() {
inuseAudioinfo.isShuffle = true;
});
}
}),
],
),
),
// ),
// ),
],
)
remove Wrap() and use Row(mainAxisAlignment: MainAxisAlignment.center,)
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)