i can't able to use curved navigation bar in flutter, when i slide screen so buttons of curved navigation bar are also moving but when i tap on buttons of curved navigation bar nothing happens . i think onTap() didn't work properly. how to navigate pages when i tap buttons?
here is the code of my program=>
static final String id = 'profile_page';
#override
_PagesState createState() => _PagesState();
}
class _PagesState extends State<Pages> {
PageController _pageController;
int _Page=0;
#override
void initState() {
super.initState();
_pageController = PageController();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: PageView(
controller: _pageController,
children: <Widget>[
Search(),
Trending(),
Friends(),
Profile(),
],
onPageChanged: (int index) {
setState(() {
_pageController.jumpToPage(index);
});
}
),
bottomNavigationBar: CurvedNavigationBar(
animationCurve: Curves.easeInOutBack,
index:3,
items: <Widget>[
Icon(Icons.search, size: 30, color: Colors.white, ),
Icon(Icons.trending_up, size: 30, color: Colors.white),
Icon(Icons.group, size: 30, color: Colors.white),
Icon(Icons.person, size: 30, color: Colors.white)
],
color: Colors.blueAccent,
backgroundColor: Colors.white,
height: 60.0,
onTap: (int index) {
setState(() {
_pageController.jumpToPage(index);
});
},
),
);
}
}
I use it this way:
Create a list and a variable that holds current Page no. Here 3 classes can be stateless or statefull widgets.
final List<Widget> _tabItems = [Class1(), Class2(), Class3()];
int _activePage = 0;
Define your body like this:
body: _tabItems[_activePage], //Customise it as you want.
Then in your onTap:
onTap: (index) {
setState(() {
_activePage = index;
});
},
Hope it helps! Happy Coding:)
If you change the page of the PageView, you are telling the CurvedNavigationBar to change its page. But when you change the page of the CurvedNavigationBar you aren't telling the PageView to change its page.
You need to add a PageController to the PageView, like this:
final _pageController = PageController();
PageView(
controller: _pageController,
...
Then you should be able to do this:
_pageController.jumpToPage(index);
But make sure when you tell one to change the page of the other, the other doesn't tell again the first one to change its page, because it will be an infinite loop.
Simply replace
_pageController = PageController(); with
final _pageController = PageController();
and remove _pageController = PageController(); in the void initState() method.
No use of int _Page=0;
You will be fine.
Related
I am using android studio and flutter. I want to build the screen as shown below in the image:screen Image
let's say I have 4 screens. on the first screen, the bar will load up to 25%. the user will move to next screen by clicking on continue, the linearbar will load up to 50% and so on. the user will get back to previous screens by clicking on the back button in the appbar.
I tried stepper but it doesn't serve my purpose.
You can use the widget LinearProgressIndicator(value: 0.25,) for the first screen and with value: 0.5 for the second screen etc.
If you want to change the bar value within a screen, just use StatefullWidget's setState(), or any state management approaches will do.
import 'package:flutter/material.dart';
class ProgressPage extends StatefulWidget {
const ProgressPage({super.key});
#override
State<ProgressPage> createState() => _ProgressPageState();
}
class _ProgressPageState extends State<ProgressPage> {
final _pageController = PageController();
final _pageCount = 3;
int? _currentPage;
double? _screenWidth;
double? _unit;
double? _progress;
#override
void initState() {
super.initState();
_pageController.addListener(() {
_currentPage = _pageController.page?.round();
setState(() {
_progress = (_currentPage! + 1) * _unit!;
});
});
}
#override
void didChangeDependencies() {
super.didChangeDependencies();
_screenWidth = MediaQuery.of(context).size.width;
_unit = _screenWidth! / _pageCount;
_progress ??= _unit;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('HOZEROGOLD')),
body: Column(
children: [
Align(
alignment: Alignment.topLeft,
child: Container(
color: Colors.yellow,
height: 10,
width: _progress,
),
),
Expanded(
child: PageView(
controller: _pageController,
children: _createPage(),
),
),
],
),
);
}
List<Widget> _createPage() {
return List<Widget>.generate(
_pageCount,
(index) => Container(
color: Colors.white,
child: Center(
child: ElevatedButton(
onPressed: () => _moveNextPage(),
child: Text('NEXT $index'),
),
),
),
);
}
void _moveNextPage() {
if (_pageController.page!.round() == _pageCount-1) {
_pageController.jumpToPage(0);
} else {
_pageController.nextPage(
curve: Curves.bounceIn,
duration: const Duration(milliseconds: 100));
}
}
}
HAPPY CODING! I hope it will be of help.
I have implemented following BottomNavigation
class AppMenu extends StatefulWidget {
const AppMenu({Key? key}) : super(key: key);
#override
State<AppMenu> createState() => _AppMenuState();
}
class _AppMenuState extends State<AppMenu> {
int current = 0;
final List<String> titles = [
"Home 1",
"Home 2"
];
final List<Widget> views = [
const HomeView1(),
const HomeView2(),
];
final List<String> icons = [
"icon_1",
"icon_2",
];
final List<String> barTitles = ["Home1", "Home2"];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: HomeAppBar(
title: titles[current],
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
onTap: (index) {
setState(() {
current = index;
});
},
selectedItemColor: const Color(0xff6B6B6B),
showUnselectedLabels: true,
showSelectedLabels: true,
unselectedItemColor: const Color(0xff6B6B6B),
selectedLabelStyle: const TextStyle(fontSize: 12),
unselectedLabelStyle: const TextStyle(fontSize: 12),
items: views.map((e) {
final itemIndex = views.indexOf(e);
return BottomNavigationBarItem(
icon: Padding(
padding: const EdgeInsets.only(bottom: 4),
child: Image.asset(
"assets/images/${icons[itemIndex]}${itemIndex == current ? "" : "_disabled"}.png",
width: 25,
),
),
label: barTitles[itemIndex],
);
}).toList()),
body: Column(
children: [
Expanded(child: views[current]),
],
),
);
}
}
Now it works perfect when I click on home1 and home2 bottom menu and it shows respected widget and load all the content which I have wrote on initState of home1 and home2 but now assume that I am on home1 and if I click again home1 then it is not calling initState again.
I want to call initState or specific function if user click on that menu even if it is selected.
Is there any way to do it?
You can create a initialize or initXXX function to initialize something in initState or somewhere. If parent widget call setState(), then child widget will call didUpdateWidget().
void initialize() {
// do something
}
Call initialize() in initState().
void initState() {
super.initState();
initialize();
}
Call initialize() in didUpdateWidget() of page(child widget).
#override
void didUpdateWidget(covariant PageTest oldWidget) {
super.didUpdateWidget(oldWidget);
initialize();
}
To handle the case in a simple way. You can add your method in onTap of BottomNavigationBar and then pass your data down to the widget tree.
It's only a demonstration to handle your case, you can adjust it with your own liking
For example
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
onTap: (index) {
if(current == index){
foo = yourMethodHere();
}
setState(() {
current = index;
});
},
Pass the variable in the tree
List<Widget> get views => [
HomeView1(foo),
HomeView2(foo),
];
I have a bottom navigation bar with some tabs and I want to animate the icons of them when I switch page, without an external package.
And I have one more question, I added a view pager to switch pages swiping, and taping in the nav bar icons, but I got an error.
For example: I am in the page 1, and I want to switch to page 3, while it is going and passes page 2, it goes back and stay in page 2.
_onPageChanged method:
_onPageChanged(int index) {
setState(() {
_pageController.animateToPage(index,
duration: const Duration(milliseconds: 200), curve: Curves.easeInOut);
_activePage = index;
});
}
BottomNavBar(from scratch) and ViewPager:
bottomNavigationBar: BottomNavBar(
activeTab: _activePage,
onTabTap: _onPageChanged,
tabs: const [
BottomNavBarItem(
icon: Icon(Icons.icon_1, color: gray),
selectedIcon: Icon(Icons.icon_1_selected, color: white)
),
BottomNavBarItem(
icon: Icon(Icons.icon_2, color: gray),
selectedIcon: Icon(Icons.icon_2_selected, color: white)
),
BottomNavBarItem(
icon: Icon(Icons.icon_3, color: gray),
selectedIcon: Icon(Icons.icon_3_selected, color: white)
),
],
),
body: PageView(
controller: _pageController,
onPageChanged: _onPageChanged,
children: _pages,
),
The BottomNavigationBarItem's icon parameter is a Widget, so you can use any Widget you'd like for what you have in mind, this is not related to the NavigationBar, but rather to what you'd like to animate.
So it could be as simple as an icon rotating once it's been clicked.
class AnimatedButtonThingy extends StatefulWidget {
const AnimatedButtonThingy({Key? key}) : super(key: key);
#override
_AnimatedButtonThingyState createState() => _AnimatedButtonThingyState();
}
class _AnimatedButtonThingyState extends State<AnimatedButtonThingy>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
bool shouldAnimate = false;
#override
void initState() {
_controller =
AnimationController(vsync: this, duration: Duration(seconds: 2));
super.initState();
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
shouldAnimate = !shouldAnimate;
shouldAnimate ? _controller.repeat() : _controller.stop();
});
},
child: Icon(Icons.auto_awesome));
}
}
Read the code above as pseudo-code, since it has not been tested, but give you an idea what could be done.
The animation code has been copied from here how-to-rotate-an-image-using-flutter-animationcontroller-and-transform
I am using the flutter_pagewise library and have implemented a paginated grid as per the library's documentation (following their example at https://pub.dev/packages/flutter_pagewise/example), which grabs placeholder images and text via the network.
In my app, I have 2 pages (one is called PaginatedGrid and the other is called SearchPage) that I can tab to via a BottomNavigationBar. However, when I tab to the SearchPage, then tab back to PaginatedGrid, the paginated grid scroll state isn't preserved. The pagination starts from the very beginning and the screen is scrolled back to the top.
import 'package:myproject/my_events/my_events_page.dart';
import 'package:myproject/search/search_page.dart';
import 'package:myproject/widget/paginated_grid.dart';
import 'package:flutter/material.dart';
class PageWrapper extends StatefulWidget {
#override
_PageWrapperState createState() => _PageWrapperState();
}
class _PageWrapperState extends State<PageWrapper> {
ScrollController _scrollController = ScrollController();
int _curIndex = 0;
List<Widget> _pages;
final bucket = PageStorageBucket();
final Key searchPageKey = PageStorageKey('searchKey');
final Key paginatedGridKey = PageStorageKey('paginatedGrid');
#override
void initState() {
_pages = [
PaginatedGrid(key: paginatedGridKey),
SearchPage(key: searchPageKey)
];
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: PageStorage(
bucket: bucket,
child: CustomScrollView(
key: PageStorageKey(_pages[_curIndex].runtimeType.toString()),
controller: _scrollController,
slivers: <Widget>[SliverAppBar(), _pages[_curIndex]],
),
),
bottomNavigationBar: BottomNavigationBar(
onTap: (int i) {
setState(() {
_curIndex = i;
});
},
currentIndex: _curIndex,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Browse',
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
label: 'Search',
)
],
),
);
}
}
Any help would be appreciated.
Using an indexedStack is a solution that worked! The paginated state is preserved on navigation to another tab from the bottom navigation bar.
Instead of using a PageStorage widget, use an IndexedStack widget.
#override
Widget build(BuildContext context) {
return Scaffold(
body: IndexedStack(
index: currentTab,
children: pages,
),
bottomNavigationBar: BottomNavigationBar(
The solution is described here: https://medium.com/#codinghive.dev/keep-state-of-widgets-with-bottom-navigation-bar-in-flutter-bb732214bd11
I'm trying to implement pagination but I can't find any examples of how I should create the controller Listener function - or where I should put it. Please advise. Let me know if I should add more info too.
Currently, my listener function looks like this:
(within initState)
pagecontroller.addListener(() {
print(pagecontroller.page);
if (pagecontroller.page == _postslist.length-1) {
fetchMore();
}
});
What happens currently is that the function is only called once, and subsequently never called later on.
I don't know if this problem still exists (it's been six months since you've asked), but since this question still doesn't have an answer that is marked as correct I'll try.
If I understand correctly you want to load more items into your PageView once you've reached the last item of your PageView. You don't need a listener in your initState for that. You can just check if you've reached the last item in onPageChanged and then load more items.
It should work like this:
PageView.builder(
controller: _pageController,
itemCount: _items.length,
onPageChanged: (i) {
if (i == _items.length - 1) {
getMoreItems().then((value) {
setState(() {
_items= value;
});
});
}
},
)
I guess you are trying to listen to pageController to get the currentPage. If that's the case, you should fire an event using the PageController by using its methods (animateToPage, jumpToPage, nextPage, previousPage), so that it can evoke your listener.
I assume my page transitions are handled by the PageView.builder
You can find the PageView.builder description in the documentation like this:
This constructor is appropriate for page views with a large (or infinite) number of children because the builder is called only for those children that are actually visible.
So it supports you in building the screens efficiently in case of large number of pages. You'll still need to handle navigation between pages on your own.
The link I've included above has an example you can refer to in terms of PageController usage. I'll include it here for convenience:
class MyPageView extends StatefulWidget {
MyPageView({
Key key
}): super(key: key);
_MyPageViewState createState() => _MyPageViewState();
}
class _MyPageViewState extends State < MyPageView > {
PageController _pageController;
#override
void initState() {
super.initState();
_pageController = PageController();
}
#override
void dispose() {
_pageController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: PageView(
controller: _pageController,
children: [
Container(
color: Colors.red,
child: Center(
child: RaisedButton(
color: Colors.white,
onPressed: () {
if (_pageController.hasClients) {
_pageController.animateToPage(
1,
duration: const Duration(milliseconds: 400),
curve: Curves.easeInOut,
);
}
},
child: Text('Next'),
),
),
),
Container(
color: Colors.blue,
child: Center(
child: RaisedButton(
color: Colors.white,
onPressed: () {
if (_pageController.hasClients) {
_pageController.animateToPage(
0,
duration: const Duration(milliseconds: 400),
curve: Curves.easeInOut,
);
}
},
child: Text('Previous'),
),
),
),
],
),
),
);
}
}