Changing the TabBar shape in flutter - flutter

I made a bottom app bar with the shape property set to "CircularNotchedRectangle" and it worked like a charm! The problem is that I'm looking for a "swipe to change page" functionality as TabBar provides but I don't see any way I can change its shape to the CircularNotchedRectangle. Can I change its shape? Or should I try and make my own "swipe to change page" functionality?
Thanks!
My current BottomNavigationBar:
BottomAppBar(
shape: CircularNotchedRectangle(),
notchMargin: 2.0,
child: Stack(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
icon: Icon(Icons.search),
iconSize: 35,
color: widget.currentTab == 0 ? Colors.purple[500] : Colors.black,
onPressed: (){
setState(() {
widget.currentTab = 0;
});
}
),
IconButton(
icon: Icon(Icons.account_circle),
iconSize: 35,
color: widget.currentTab == 1 ? Colors.purple[500] : Colors.black,
onPressed: (){
setState(() {
widget.currentTab = 1;
});
}
),
SizedBox(width: 40),
IconButton(
icon: Icon(Icons.group),
iconSize: 35,
color: widget.currentTab == 2 ? Colors.purple[500] : Colors.black,
onPressed: (){
setState(() {
widget.currentTab = 2;
});
}
),
IconButton(
icon: Icon(Icons.chat_bubble),
iconSize: 35,
color: widget.currentTab == 3 ? Colors.purple[500] : Colors.black,
onPressed: (){
setState(() {
widget.currentTab = 3;
});
}
),
]
)
]
)
);
This is the shape I'm trying to get with the TabBar

You can copy paste run full code below
To implement swipe to change page functionality with your current code
You can directly use PageView
code snippet
PageController pageController = PageController(
initialPage: 0,
keepPage: true,
);
Widget buildPageView() {
return PageView(
controller: pageController,
onPageChanged: (index) {
pageChanged(index);
},
children: <Widget>[
Red(),
Blue(),
Yellow(),
Green(),
],
);
}
...
void bottomTapped(int index) {
setState(() {
currentTab = index;
pageController.animateToPage(index,
duration: Duration(milliseconds: 500), curve: Curves.ease);
});
}
...
IconButton(
icon: Icon(Icons.search),
iconSize: 35,
color: currentTab == 0 ? Colors.purple[500] : Colors.black,
onPressed: () {
bottomTapped(0);
}),
working demo
full code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
double width;
Color primaryColor = Colors.blue;
int currentTab = 0;
PageController pageController = PageController(
initialPage: 0,
keepPage: true,
);
Widget buildPageView() {
return PageView(
controller: pageController,
onPageChanged: (index) {
pageChanged(index);
},
children: <Widget>[
Red(),
Blue(),
Yellow(),
Green(),
],
);
}
#override
void initState() {
super.initState();
}
void pageChanged(int index) {
setState(() {
currentTab = index;
});
}
void bottomTapped(int index) {
setState(() {
currentTab = index;
pageController.animateToPage(index,
duration: Duration(milliseconds: 500), curve: Curves.ease);
});
}
#override
Widget build(BuildContext context) {
width = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: buildPageView(),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.red,
child: const Icon(
Icons.add,
),
onPressed: () {},
),
bottomNavigationBar: BottomAppBar(
shape: CircularNotchedRectangle(),
notchMargin: 2.0,
child: Stack(children: [
Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
IconButton(
icon: Icon(Icons.search),
iconSize: 35,
color: currentTab == 0 ? Colors.purple[500] : Colors.black,
onPressed: () {
bottomTapped(0);
}),
IconButton(
icon: Icon(Icons.account_circle),
iconSize: 35,
color: currentTab == 1 ? Colors.purple[500] : Colors.black,
onPressed: () {
bottomTapped(1);
}),
SizedBox(width: 40),
IconButton(
icon: Icon(Icons.group),
iconSize: 35,
color: currentTab == 2 ? Colors.purple[500] : Colors.black,
onPressed: () {
bottomTapped(2);
}),
IconButton(
icon: Icon(Icons.chat_bubble),
iconSize: 35,
color: currentTab == 3 ? Colors.purple[500] : Colors.black,
onPressed: () {
bottomTapped(3);
}),
])
])),
);
}
}
class Red extends StatefulWidget {
#override
_RedState createState() => _RedState();
}
class _RedState extends State<Red> {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.purple,
);
}
}
class Blue extends StatefulWidget {
#override
_BlueState createState() => _BlueState();
}
class _BlueState extends State<Blue> {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.blueAccent,
);
}
}
class Yellow extends StatefulWidget {
#override
_YellowState createState() => _YellowState();
}
class _YellowState extends State<Yellow> {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.yellowAccent,
);
}
}
class Green extends StatefulWidget {
#override
_GreenState createState() => _GreenState();
}
class _GreenState extends State<Green> {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.greenAccent,
);
}
}

All you need to do is to define the Fab location inside Scaffold like this :
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,

Related

Flutter: How to use a button that has the same effect as clicking on a BottomNavigationBar?

I have a Dart file named page0.dart and this only includes a BottomNavigationBar.
BottomNavigationBar has 2 items in it which redirects me to dashboard.dart and target.dart, the navigation via the BottomNavigationBar works as expected.
Now the problem: I need a button on dashboard.dart that should redirect me to target.dart, but keep the ButtomNavigationBar visible.
I am redirecting with Navigator.push, but that opens target.dart directly and skips page0.dart I think.
Screenshots are below. Please watch them for better understanding my problem.
Here are the code samples:
page0.dart:
import 'package:flutter/material.dart';
import 'package:navbartest/dashboard.dart';
import 'package:navbartest/target.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key, required String title}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return const Scaffold(
bottomNavigationBar: BottomNavBar(),
);
}
}
class BottomNavBar extends StatefulWidget {
const BottomNavBar({super.key});
#override
State<BottomNavBar> createState() => _BottomNavBarState();
}
class _BottomNavBarState extends State<BottomNavBar> {
int _pageIndex = 0;
final List<Widget> _tabList = const [
Dashboard(),
Target(),
];
Widget? onItemTap(int index) {
setState(() {
_pageIndex = index;
});
return null;
}
#override
Widget build(BuildContext context) {
return Stack(
children: [
_tabList.elementAt(_pageIndex),
Padding(
padding: EdgeInsets.only(right: 35, bottom: 25, left: 35),
child: Align(
alignment: const Alignment(0.0, 1.0),
child: ClipRRect(
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
child: BottomNavigationBar(
backgroundColor: const Color(0xff565656),
type: BottomNavigationBarType.fixed,
showSelectedLabels: false,
showUnselectedLabels: false,
unselectedItemColor: Colors.white,
selectedItemColor: Colors.white,
onTap: onItemTap,
items: [
BottomNavigationBarItem(
icon: const Icon(Icons.home),
label: "Dashboard",
),
BottomNavigationBarItem(
icon: const Icon(Icons.car_repair),
label: "Target",
),
],
),
),
),
),
],
);
}
}
dashboard.dart
import 'package:navbartest/target.dart';
class Dashboard extends StatelessWidget {
const Dashboard({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Center(
child: Container(
width: 120,
height: 20,
color: Colors.blue,
child: InkResponse(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const Target()),
);
},
child: Text('navigate to target'),
),
),
),
),
);
}
}
target.dart:
class Target extends StatelessWidget {
const Target({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Text('target'),
),
);
}
}
when the app is started, it looks like this
when I click the blue button to navigate, it looks like this (NavBar is gone!)
when I click the symbol in the navbar redirecting me to target.dart, it looks like this (thats how I want it with the blue button too!)
actually you need to use a state management for this type of actions , but I found a work around in your case ,
I will set the classes next Just replace them with your classes and it will work.
1 - page0.dart:
import 'target.dart';
import 'package:flutter/material.dart';
import 'dash.dart';
class BottomNavBar extends StatefulWidget {
const BottomNavBar({super.key});
#override
State<BottomNavBar> createState() => BottomNavBarState();
}
class BottomNavBarState extends State<BottomNavBar> {
late int _pageIndex;
late final List<Widget> _tabList;
Widget? onItemTap(int index) {
setState(() {
_pageIndex = index;
});
return null;
}
#override
void initState(){
super.initState();
_pageIndex = 0;
_tabList = [
Dashboard(ref:(int number){
setState(() {
_pageIndex = number;
});
}),
const Target(),
];
}
#override
Widget build(BuildContext context) {
return Stack(
children: [
_tabList.elementAt(_pageIndex),
Padding(
padding: EdgeInsets.only(right: 35, bottom: 25, left: 35),
child: Align(
alignment: const Alignment(0.0, 1.0),
child: ClipRRect(
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
child: BottomNavigationBar(
backgroundColor: const Color(0xff565656),
type: BottomNavigationBarType.fixed,
showSelectedLabels: false,
showUnselectedLabels: false,
unselectedItemColor: Colors.white,
selectedItemColor: Colors.white,
onTap: onItemTap,
items: [
BottomNavigationBarItem(
icon: const Icon(Icons.home),
label: "Dashboard",
),
BottomNavigationBarItem(
icon: const Icon(Icons.car_repair),
label: "Target",
),
],
),
),
),
),
],
);
}
}
2 - dashboard.dart :
import 'package:flutter/material.dart';
class Dashboard extends StatelessWidget {
const Dashboard({super.key, required this.ref});
final Function(int)? ref ;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Center(
child: Container(
width: 120,
height: 20,
color: Colors.blue,
child: InkResponse(
onTap: ()=>ref!(1),
child: Text('navigate to target'),
),
),
),
),
);
}
}
3 - target.dart:
import 'package:flutter/material.dart';
class Target extends StatelessWidget {
const Target({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Text('target'),
),
);
}
}
remove the import and re import for the right paths in your application file , but this is a work around and you should use the state management .

Flutter BottomNavigationBar with AnimatedContainer - what is causing a RenderFlex overflow error?

My Flutter app uses a BottomNavigationBar wrapped in an AnimatedContainer. When the animation takes place (activated by scrolling the list) a RenderFlex overflow error occurs. I can't work out what is causing this to happen.
I've stripped down the project to bare bones code in the hope that someone could try it out and identify the issue.
The main class:
class TestMain extends StatefulWidget {
const TestMain({Key? key}) : super(key: key);
#override
State<TestMain> createState() => _TestMain();
}
class BottomNavBarItemData {
String label;Icon icon;Widget screen;
BottomNavBarItemData({required this.label,required this.icon,required this.screen});
}
late ScrollController mainScrollController;
class _TestMain extends State<TestMain> {
int _selectedIndex = 0;
bool _isVisible = true;
#override
void initState() {
_isVisible = true;
mainScrollController = ScrollController();
mainScrollController.addListener(() {
if (mainScrollController.position.userScrollDirection == ScrollDirection.reverse) {
setState(() {
_isVisible = false;
});
}
if (mainScrollController.position.userScrollDirection == ScrollDirection.forward) {
setState(() {
_isVisible = true;
});
}
});
super.initState();
}
final List<BottomNavBarItemData> screens = [
BottomNavBarItemData(
icon: const Icon(Icons.home, size: 25.0, color: Colors.red),
label: 'Page1',
screen: const Screen1(),
),
BottomNavBarItemData(
icon: const Icon(Icons.home, size: 25.0, color: Colors.red),
label: 'Page2',
screen: const Screen2(),
),
];
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
extendBody: true,
body: SafeArea(
child: IndexedStack(
index: _selectedIndex,
children: [
...screens.map((e) => e.screen).toList(),
],
),
),
bottomNavigationBar: AnimatedContainer(
duration: const Duration(milliseconds: 400),
height: _isVisible ? 70 : 0.0,
child: SizedBox(
child: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
backgroundColor: Colors.orange,
currentIndex: _selectedIndex,
selectedIconTheme: IconThemeData(color: Colors.white),
selectedItemColor: Colors.white,
selectedFontSize: 14,
unselectedFontSize: 14,
unselectedIconTheme: const IconThemeData(
color: Colors.lightBlueAccent,
),
unselectedItemColor: Colors.lightBlueAccent,
onTap: _onItemTapped,
items: screens.map((e) => BottomNavigationBarItem(
label: e.label,
icon: e.icon,
),
).toList(),
),
),
),
);
}
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
}
And the two screens called by the main class:
class Screen1 extends StatefulWidget {
const Screen1({Key? key}) : super(key: key);
#override
State<Screen1> createState() => _Screen1();
}
class _Screen1 extends State<Screen1> {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: SingleChildScrollView(
controller: mainScrollController,
physics: const AlwaysScrollableScrollPhysics(),
child: Column(children: [
Container(height: 150, color: Colors.blue),
Container(height: 150, color: Colors.white),
Container(height: 150, color: Colors.blue),
Container(height: 150, color: Colors.white),
Container(height: 150, color: Colors.blue),
Container(height: 150, color: Colors.white),
],),
),
);
}
}
class Screen2 extends StatefulWidget {
const Screen2({Key? key}) : super(key: key);
#override
State<Screen2> createState() => _Screen2();
}
class _Screen2 extends State<Screen2> {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
);
}
}
Container gets overflow because the inner item space is greater to the animation size, like on 35 it will show the overflow. You can use different animation, but it will be little difference.
You can use SizeTransition for this case
class _TestMain extends State<TestMain> with SingleTickerProviderStateMixin {
int _selectedIndex = 0;
bool _isVisible = true;
late final AnimationController _controller = AnimationController(
duration: const Duration(milliseconds: 400),
vsync: this,
)..forward();
late final Animation<double> _animation = CurvedAnimation(
parent: _controller,
curve: Curves.fastOutSlowIn,
);
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
void initState() {
_isVisible = true;
mainScrollController = ScrollController();
mainScrollController.addListener(() {
if (mainScrollController.position.userScrollDirection ==
ScrollDirection.reverse) {
_controller.reverse();
setState(() {
_isVisible = false;
});
}
if (mainScrollController.position.userScrollDirection ==
ScrollDirection.forward) {
_controller.forward();
setState(() {
_isVisible = true;
});
}
});
super.initState();
}
final List<BottomNavBarItemData> screens = [
BottomNavBarItemData(
icon: const Icon(Icons.home, size: 25.0, color: Colors.red),
label: 'Page1',
screen: const Screen1(),
),
BottomNavBarItemData(
icon: const Icon(Icons.home, size: 25.0, color: Colors.red),
label: 'Page2',
screen: const Screen2(),
),
];
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
extendBody: true,
body: SafeArea(
child: IndexedStack(
index: _selectedIndex,
children: [
...screens.map((e) => e.screen).toList(),
],
),
),
bottomNavigationBar: SizeTransition(
sizeFactor: _animation,
child: SizedBox(
child: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
backgroundColor: Colors.orange,
currentIndex: _selectedIndex,
selectedIconTheme: IconThemeData(color: Colors.white),
selectedItemColor: Colors.white,
selectedFontSize: 14,
unselectedFontSize: 14,
unselectedIconTheme: const IconThemeData(
color: Colors.lightBlueAccent,
),
unselectedItemColor: Colors.lightBlueAccent,
onTap: _onItemTapped,
items: screens
.map(
(e) => BottomNavigationBarItem(
label: e.label,
icon: e.icon,
),
)
.toList(),
),
),
),
);
}
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
}
or
bottomNavigationBar: AnimatedScale(
duration: const Duration(milliseconds: 400),
scale: _isVisible ? 1 : 0.0,
alignment: Alignment.bottomCenter,

Flutter : how to actualize the state of a global variable in every widget?

so i have 2 pages and 1 file where i have my variable . when i run the app my variable total is update every time i enter income page or add a new income . but when i navigate back to the home page the total shows only the first value ive entered .
Home.dart
import 'package:flutter/material.dart';
import 'componets.dart';
import 'income.dart';
import 'variables.dart';
....
bottomNavigationBar: Container(
color: Colors.white,
child: Row(
children: <Widget>[
Expanded(
child: ListTile(
title: new Text("Balance:"),
subtitle: new Text("$Total"),
),
),
the variable total is shown in the bottom of home page
Income.dart
import 'package:flutter/material.dart';
import 'componets.dart';
import 'home.dart';
import 'variables.dart';
class Income extends StatefulWidget {
const Income({Key? key}) : super(key: key);
#override
State<Income> createState() => _IncomeState();
}
class _IncomeState extends State<Income> {
TextEditingController _textFieldController = TextEditingController();
List<double> transactions = [];
Future<void> _displayTextInputDialog(BuildContext context) async {
double Amount = 0;
String valueText = '';
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Add income'),
content: TextField(
keyboardType: TextInputType.number,
onChanged: (value) {
setState(() {
valueText = value;
});
},
controller: _textFieldController,
),
actions: <Widget>[
FlatButton(
color: Colors.red,
textColor: Colors.white,
child: Text('CANCEL'),
onPressed: () {
setState(() {
Navigator.pop(context);
});
},
),
FlatButton(
color: Colors.green,
textColor: Colors.white,
child: Text('OK'),
onPressed: () {
setState(() {
Amount = double.parse(valueText);
transactions.add(Amount);
Total = Total + Amount;
print(Amount);
Navigator.pop(context);
});
},
),
],
);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Income"),
backgroundColor: Colors.deepOrange,
centerTitle: false,
elevation: 1.0,
),
body: Center(
child: FlatButton(
color: Colors.teal,
textColor: Colors.white,
onPressed: () {
_displayTextInputDialog(context);
},
child: Text('Press For Alert'),
),
),
// NavigationBar
bottomNavigationBar: Container(
color: Colors.white,
child: Row(
children: <Widget>[
Expanded(
child: ListTile(
title: Text("Balance:"),
subtitle: Text('${Total}'),
),
),
the variable in the same place as the home page
variables.dart
double Total = 0;
I have created example of updating total value using provider by refering yours
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
//Provider for updating totalvalue
class TotalValue with ChangeNotifier {
double _total = 0;
double get value => _total;
void sum(double val) {
_total += val;
notifyListeners();
}
}
//Income Page
class Income extends StatefulWidget {
const Income({Key? key}) : super(key: key);
#override
State<Income> createState() => _IncomeState();
}
class _IncomeState extends State<Income> {
TextEditingController _textFieldController = TextEditingController();
List<double> transactions = [];
Future<void> _displayTextInputDialog(BuildContext context) async {
double Amount = 0;
String valueText = '';
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Add income'),
content: TextField(
keyboardType: TextInputType.number,
onChanged: (value) {
setState(() {
valueText = value;
});
},
controller: _textFieldController,
),
actions: <Widget>[
FlatButton(
color: Colors.red,
textColor: Colors.white,
child: Text('CANCEL'),
onPressed: () {
Navigator.pop(context);
},
),
FlatButton(
color: Colors.green,
textColor: Colors.white,
child: Text('OK'),
onPressed: () {
Amount = double.parse(valueText);
transactions.add(Amount);
context.read<TotalValue>().sum(Amount);
Navigator.pop(context);
},
),
],
);
});
}
#override
Widget build(BuildContext context) {
return Center(
child: FlatButton(
color: Colors.teal,
textColor: Colors.white,
onPressed: () {
_displayTextInputDialog(context);
},
child: Text('Press For Alert'),
),
);
}
}
//Home Page
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
int _selectedIndex = 0;
static TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static List<Widget> _widgetOptions(BuildContext context) {
return <Widget>[
Income(),
Text(
'${context.watch<TotalValue>().value}',
style: optionStyle,
),
];
}
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Income'),
),
body: Center(
child: _widgetOptions(context).elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.money),
label: 'Income',
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
);
}
}

How to change the color of bottom navigation bar icon according to the user choice

I am new at flutter, and I am trying to change the color of a button when the button is active (been pressed), my code is not working as per expectation. Someone knows how to I fix that?
My code:
import 'package:flutter/material.dart';
class BottomNavBar extends StatefulWidget {
const BottomNavBar({Key? key}) : super(key: key);
#override
_BottomNavBarState createState() => _BottomNavBarState();
}
class _BottomNavBarState extends State<BottomNavBar> {
int _selectedIndex = 0;
#override
Widget build(BuildContext context) {
return Container(
child: Row(
children: <Widget>[
iconButtonBar(context, Icons.home, 0, _selectedIndex),
iconButtonBar(context, Icons.favorite, 1, _selectedIndex),
iconButtonBar(context, Icons.person, 2, _selectedIndex),
iconButtonBar(context, Icons.search, 3, _selectedIndex),
],
),
);
}
Container iconButtonBar(
BuildContext context, IconData icon, int index, int _selectedIndex) {
return Container(
height: 60,
width: MediaQuery.of(context).size.width / 4,
color: index == _selectedIndex ? Colors.blue : Colors.white, // changing the color
child: IconButton(
icon: Icon(icon),
onPressed: () {
_selectedIndex = index;
},
));
}
}
really happy if you find the time to answer.
You should try to refer below code:
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
PageController _pageController = PageController();
List<Widget> _screen = [
Home(),
MyProfile(),
Conversations(),
SearchPage()
];
void _onPageChanged(int index) {
setState(() {
_selectedIndex = index;
});
}
void _onItemTapped(int selectedIndex) {
_pageController.jumpToPage(selectedIndex);
}
int _selectedIndex = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: PageView(
controller: _pageController,
children: _screen,
onPageChanged: _onPageChanged,
physics: NeverScrollableScrollPhysics(),
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: this._selectedIndex,
selectedItemColor: Colors.blue,
unselectedItemColor: Colors.black45,
backgroundColor: Colors.black,
selectedLabelStyle: TextStyle(fontWeight: FontWeight.bold),
onTap: _onItemTapped,
items: [
BottomNavigationBarItem(
icon: Icon(
Icons.home,
),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(
Icons.person,
),
label: 'Profile'),
BottomNavigationBarItem(
icon: Icon(
Icons.sms,
),
label: 'Messages'),
BottomNavigationBarItem(
icon: Icon(
Icons.search,
),
label: 'Search'),
],
),
);
}
}
You need to call setState(); so that the changes will be reflected to the UI. so your code looks
Container iconButtonBar(
BuildContext context, IconData icon, int index, int _selectedIndex) {
return Container(
height: 60,
width: MediaQuery.of(context).size.width / 4,
color: index == _selectedIndex ? Colors.blue : Colors.white, // changing the color
child: IconButton(
icon: Icon(icon),
onPressed: () {
setState((){
_selectedIndex = index;
});
},
));
}

Flutter: How to use animated icon in the AppBar - I want to use this animated icon instead of Animatedless Icon, in the appbar of flutter app

I want to use the animated icon in this AppBar, but can not be done because the animated icon have a stateful widget with "with TickerProviderStateMixin". If I move the whole scaffold to a stateful widget then the "onMenuTap" is not working. The main purpose of the Question is to use the animated icon in the Flutter AppBar.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../FreelanceTheme/AppStyleModeNotifier.dart';
class HomePage extends StatelessWidget with NavigationStates {
final Function onMenuTap;
const HomePage({Key key, this.onMenuTap}) : super(key: key);
#override
Widget build(BuildContext context) {
final appStyleMode = Provider.of<AppStyleModeNotifier>(context);
return MaterialApp(
home: Scaffold(
backgroundColor: Color(0xffE5E5E5),
appBar: AppBar(
elevation: 0,
backgroundColor: appStyleMode.appBarBackgroundColor,
actions: <Widget>[
Switch(
activeColor: Colors.orange,
value: appStyleMode.mode,
onChanged: (value) => appStyleMode.switchMode(),
),
],
leading: IconButton(
tooltip: 'App Settings',
icon: Icon(
FontAwesomeIcons.bars,
color: Colors.white,
),
onPressed: onMenuTap,
),
centerTitle: true,
title: Text(
"Home",
style: TextStyle(
color: Colors.white,
),
),
),
body: FreelancingHomePage(),
),
);
}
}
I want to replace this IconButton with the animated icon in the appbar.
leading: IconButton(
tooltip: 'App Settings',
icon: Icon(
FontAwesomeIcons.bars,
color: Colors.white,
),
onPressed: onMenuTap,
),
Following is the code for the animated icon. I want to use this animated icon in the above appBar.
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
AnimationController _animationIconController1,
bool isarrowmenu = false;
#override
void initState() {
super.initState();
_animationIconController1 = AnimationController(
vsync: this,
duration: Duration(milliseconds: 750),
reverseDuration: Duration(milliseconds: 750),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
GestureDetector(
onTap: () {
setState(() {
isarrowmenu
? _animationIconController1.reverse()
: _animationIconController1.forward();
isarrowmenu = !isarrowmenu;
});
},
child: ClipOval(
child: Container(
decoration: BoxDecoration(
border: Border.all(
width: 2.5,
color: Colors.green,
),
borderRadius: BorderRadius.all(
Radius.circular(50.0),
),
),
width: 75,
height: 75,
child: Center(
child: AnimatedIcon(
icon: AnimatedIcons.arrow_menu,
progress: _animationIconController1,
color: Colors.red,
size: 60,
),
),
),
),
),
),
);
}
You can copy paste run full code below
Step 1: You can make this animated icon with StatefulWidget that have VoidCallback onMenuTap
class CustomIcon extends StatefulWidget {
VoidCallback onMenuTap;
CustomIcon({Key key, this.onMenuTap}) : super(key: key);
#override
_CustomIconState createState() => _CustomIconState();
}
class _CustomIconState extends State<CustomIcon> with TickerProviderStateMixin {
AnimationController _animationIconController1;
Step 2: In leading, you can use CustomIcon and pass onMenuTap
home: HomePage(
onMenuTap: () {
print("hi");
},
),
...
leading: CustomIcon(
onMenuTap: () {
onMenuTap();
},
),
working demo
output of working demo
I/flutter (25195): hi
I/flutter (25195): hi
full code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: HomePage(
onMenuTap: () {
print("hi");
},
),
);
}
}
class HomePage extends StatelessWidget {
final Function onMenuTap;
const HomePage({Key key, this.onMenuTap}) : super(key: key);
#override
Widget build(BuildContext context) {
//final appStyleMode = Provider.of<AppStyleModeNotifier>(context);
return MaterialApp(
home: Scaffold(
backgroundColor: Color(0xffE5E5E5),
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.blue,
actions: <Widget>[
/* Switch(
activeColor: Colors.orange,
value: appStyleMode.mode,
onChanged: (value) => appStyleMode.switchMode(),
),*/
],
leading: CustomIcon(
onMenuTap: () {
onMenuTap();
},
),
centerTitle: true,
title: Text(
"Home",
style: TextStyle(
color: Colors.white,
),
),
),
body: Text("FreelancingHomePage()"),
),
);
}
}
class CustomIcon extends StatefulWidget {
VoidCallback onMenuTap;
CustomIcon({Key key, this.onMenuTap}) : super(key: key);
#override
_CustomIconState createState() => _CustomIconState();
}
class _CustomIconState extends State<CustomIcon> with TickerProviderStateMixin {
AnimationController _animationIconController1;
bool isarrowmenu = false;
#override
void initState() {
super.initState();
_animationIconController1 = AnimationController(
vsync: this,
duration: Duration(milliseconds: 750),
reverseDuration: Duration(milliseconds: 750),
);
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
isarrowmenu
? _animationIconController1.reverse()
: _animationIconController1.forward();
isarrowmenu = !isarrowmenu;
if (widget.onMenuTap != null) {
widget.onMenuTap();
}
});
},
child: ClipOval(
child: Container(
decoration: BoxDecoration(
border: Border.all(
width: 2.5,
color: Colors.green,
),
borderRadius: BorderRadius.all(
Radius.circular(50.0),
),
),
width: 75,
height: 75,
child: Center(
child: AnimatedIcon(
icon: AnimatedIcons.arrow_menu,
progress: _animationIconController1,
color: Colors.red,
size: 60,
),
),
),
),
);
}
}