Flutter PageView remove page Indicator - flutter

Does anyone know if there is a way to remove the PageView indicator which is shown for a couple of seconds after I change the Page?
return Scaffold(
bottomNavigationBar: CubertoBottomBar(
tabStyle: CubertoTabStyle.STYLE_FADED_BACKGROUND,
selectedTab: _selectedIndex,
tabs: [
TabData(
iconData: Icons.assignment,
title: "Logbuch",
tabColor: Colors.deepPurple,
),
....
],
onTabChangedListener: (position, title, color) {
setState(() {
_selectedIndex = position;
});
},
),
body: PageView(
controller: _pageController,
pageSnapping: true,
onPageChanged: (index) {
setState(() {
_selectedIndex = index;
});
},
// physics: NeverScrollableScrollPhysics(),
children: <Widget>[
LogBookView(),
...
],
),
);
I couldn't find anything about it in the documentation of the PageView widget and the BottomNav widget.

I think you need to provide a little context to your code since there are loads of ways to implement PageView and indicator. I think you are using TabBarView as parent to the PageView because By default PageView doesn't have indicator itself, TabBarView has.
assuming I am right you really don't need to use TabBarView unless you want to use different tabs, and each tab has different PageView or other widgets. Judging your UI i think PageView with controller can satisfy your UI need.
Class XYZ extends StatefullWidget{
.......
}
Class _XYZ extends State<XYZ>
with SingleTickerProviderStateMixin{
PageController _pageController;
int pageNumber = 0;
void initState() {
super.initState();
_pageController = PageController();
}
..................
//inside build PageView
PageView(
controller: _pageController,
onPageChanged: (pageIndex) {
setState(() {
pageNumber = pageIndex;
});
},
children: <Widget>[
Notes(), // scaffold or widget or other class
Wochenplan(), scaffold or widget or other class
ETC(), // scaffold or widget or other class
],
),
..................
//inside build bottom nav icons
Row(
children: <Widget>[
buildTabButton(int currentIndex, int pageNumber, String image),
buildTabButton2....,
buildTabButton3...,
],
)
.......
buildTabButton1........
buildTabButton2(int currentIndex, int pageNumber, String image) {
return AnimatedContainer(
height: _height,
width: currentIndex == pageNumber ? 100 : 30,
padding: EdgeInsets.all(10),
duration: Duration(milliseconds: 300),
decoration: BoxDecoration(),// use currentIndex == pageNumber to decorate current widget and others
child: ../*ClickableWidget*/, //onClckWochenplan() // and so on
);
}
buildTabButton3........
........................
//onPressed or onTap functions which you can implement inside widgets as well..
void ABC() {
_pageController.animateToPage(0,
duration: Duration(milliseconds: 500), curve: Curves.decelerate);
}
void onClckWochenplan() {
_pageController.animateToPage(1,
duration: Duration(milliseconds: 500), curve: Curves.decelerate);
}
void DEF() {
_pageController.animateToPage(2,
duration: Duration(milliseconds: 500), curve: Curves.decelerate);
}
I hope It helps.. else provide some code to get help from the community.. cheers

I see you are using library CubertoBottomBar which is not default TabBarView that flutter provides. So I looked into the library. The thing is, it should not suppose to show the indicator at all. So i am going to take 2 wild guesses here and 1 suggestion..
1. You might have another parents with TabBarView wrapping up this scaffold (may be from previous class/widget where this scaffold is being wrapped)..
Scaffold(
bottomNavigationBar: CubertoBottomBar(
tabStyle: CubertoTabStyle.STYLE_FADED_BACKGROUND,
selectedTab: _selectedIndex,
tabs: [
..............
if you are building it on IOS it might not rendering the library widget correctly. (this is since i tried to build this app in the same way you did and i did not get any indicator at all with 3 of my devices). So,if you are currently building it on IOS, Try to build on android device then you might know whats really going on and report an issue to the library owner.
Apart from my inability to help you, i suggest you to try to replace the PageView with TabBar then you can control the indicator (Though the PageView should not give you indicator either but just a suggestion)..
TabBar(
indicatorWeight: 0.0, // then you can control height of indicator
indicatorColor: Colors.transparent, // then you can control color with transparent value
tabs: <Widget>[
tab();
tab2();
],
),
//**TODO ----------------------
My bet is on my 1st Point.. check your widget tree thoroughly...

Related

Switch horizontal tabs on vertical scroll flutter

How can I switch tabs on a vertical scroll as shown above. What would be the best way to do this? And upon clicking on certain tab, control should be transfer to selected tab content. I tried to find solution on google but in vain.
Currently my code looks something like this but I know thats not it.
class SingleRestView extends StatefulWidget {
Restaurant singleRestaurant;
SingleRestView({#required this.singleRestaurant});
#override
_SingleRestViewState createState() => _SingleRestViewState();
}
class _SingleRestViewState extends State<SingleRestView>
with SingleTickerProviderStateMixin {
var _tabController;
#override
void initState() {
super.initState();
_tabController = TabController(length: 3, vsync: this);
}
#override
Widget build(BuildContext context) {
var tabBar = TabBar(
controller: _tabController,
//This property will allow your tabs to be horizontally scrollable
isScrollable: true,
indicatorColor: Colors.black,
labelColor: Colors.black,
tabs: [
Text("Tab 1"),
Text("Tab 2"),
Text("Tab 2"),
],
);
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (context, isScrolled) => [
SliverAppBar(
expandedHeight: 300,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
title: Text('Title'),
//Without this padding the title appears behind the tabs.
//This is the whole reason why the tabBar is in a local variable, to
//be able to use its height here.
titlePadding: EdgeInsetsDirectional.only(
start: 72, bottom: tabBar.preferredSize.height + 16),
// background:
),
// I did this this way to have a white bottom bar like in your photo,
// however, you could just pass the tabBar. The background image would
//be behind it.
bottom: PreferredSize(
child: Container(
//This will keep your tabs centered if you have not enough to fill
//the display's width
alignment: Alignment.center,
width: double.infinity,
color: Colors.white,
child: tabBar,
),
preferredSize: Size(double.infinity, tabBar.preferredSize.height),
),
),
],
body: TabBarView(
controller: _tabController,
children: <Widget>[
Container(height: 50,width: 100,color: Colors.red,),
Container(height: 50,width: 100,color: Colors.blue,),
Container(height: 50,width: 100,color: Colors.green,),
],
),
),
);
}
}
Video of what i want to achieve
nestedScrollController has a property called offset which will give you the current offset.
nestedScrollController.offset
But remember, screen sizes can be different for different devices. So using only offset will not help.
1. Naive Option using MediaQuery
With MediaQuery you can get to know the height of your device & then you can globally change the tab_index based on a comparison between offset & the height of the device. You can use some threshold value after which horizontal tab_index changes. Setting proper offset values might be a tough job !
double new_height = MediaQuery.of(context).size.height;
if(new_height/2<=offset)
{
//change my tab_index to 2
}
2. Using Listeners in Controller
Combining listeners & offsets
_TabController.addListener(() {
if (_controller.position.atEdge) {
if (_controller.position.pixels == 0) {
// You're at the top so tab_index=1
}
//At the bottom of screen
if(_controller.offset>=_controller.position.maxScrollExtent)
{
//set your tab_index
}
//middle of screen multiply by 0.5
if(_controller.offset>=_controller.position.maxScrollExtent*0.5)
{
//set your tab_index
}
//3/4 of screen multiply by 0.75
if(_controller.offset>=_controller.position.maxScrollExtent*0.75)
{
//set your tab_index
}
}
Further Reading -
https://medium.com/#diegoveloper/flutter-lets-know-the-scrollcontroller-and-scrollnotification-652b2685a4ac
Scroll Position Class
How to check if scroll position is at top or bottom in ListView?
Maybe you can try to use this plugin => https://pub.dev/packages/vertical_scrollable_tabview/score
import 'package:vertical_scrollable_tabview/vertical_scrollable_tabview.dart';
// Required it
TabBar(
onTap: (index) {
VerticalScrollableTabBarStatus.setIndex(index); <- Required
},
)
and
VerticalScrollableTabView(
tabController: tabController, <- Required TabBarController
listItemData: data, <- Required List<dynamic>
eachItemChild: (object,index){
return CategorySection(category: object as Category); <- Object and index
},
verticalScrollPosition: VerticalScrollPosition.begin,
),
I think this plugin can solve it.

Flutter: Make a custom bottom bar sliding up when it appears

I am trying to design a music playlist page. So far I am able to create a listview with song cards. When I click on any song, a custom bottom bar appears and the audio starts playing. However, I just hold a state with boolean and show the bottom bar according to that. Instead, I want it to appear like sliding up and reach to the position. Let say in 0.5 seconds.
I have a custom NavBar class
class NavBar extends StatefulWidget
And I use this class in build similar to:
return Column(
children: [
SizedBox(
height: constraints.maxHeight * 0.5,
hild: SlidingBanners(),
),
Expanded(
child: Lists(),
),
NavBar()
],
);
How can I such animation?
Use a SizeTransition widget https://api.flutter.dev/flutter/widgets/SizeTransition-class.html
"SizeTransition acts as a ClipRect that animates either its width or
its height, depending upon the value of axis. The alignment of the
child along the axis is specified by the axisAlignment."
Widget build(BuildContext context) {
return SizeTransition(
sizeFactor: CurvedAnimation(
curve: Curves.fastOutSlowIn,
parent: _animationController,
),
child: Container(height: 100, color: Colors.blue)
);
}
init animation controller in stateful widgets initState()
#override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this, duration: const Duration(milliseconds: 500));
}
Make sure your stateful widget uses SingleTickerProviderStateMixin
class _NavBarState extends State<NavBar>
with SingleTickerProviderStateMixin {
late AnimationController _animationController;
then open and close with
_animationController.forward()
_animationController.reverse()
You can pass the _animationController into the NavBar widget's constructor from its parent if you want the parent to control the animation.
Alternatively you can use an AnimatedContainer widget and setState with its height 0 or 100 depending on if Nav should be shown. This becomes a problem for some widgets that cannot be squished to height of 0 though and I would not recommend for any container that contains anything but text
One solution would be to use a SnackBar widget. Since it's automatically animated, you wouldn't want to worry about manually animating the bottom bar. You can insert your Audio Player (bottom bar) widget to the child of the SizedBox.
The bottom bar is made visible by,
ScaffoldMessenger.of(context).showSnackBar(snackBar);
This bottom bar is dismissed (hidden) by dragging down or by,
ScaffoldMessenger.of(context).hideCurrentSnackBar();
There maybe many other solutions as well to this, but reading your question, I hope this is what you wanted.
return Center(
child: ElevatedButton(
onPressed: () {
final snackBar = SnackBar(
duration: Duration(days: 365),
content: SizedBox(
height: 100,
//insert your audio player widget here
child: Column(
children: [
Text("YOUR AUDIOPLAYER WIDGET HERE"),
Text("Audio Controls Here"),
ElevatedButton(
onPressed: () {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
},
child: Text("Audio Player Minimize"),
),
],
),
),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
},
child: Text('Open Audio Player'),
),
);

How to scroll withing a widget with a button?

I am building a WebApp in flutter and I have a SingleChildScrollView with some widgets inside. I want the buttons on the appbar to take me to the correspondent widget when I press on the buttons.
Is that possible? Here I attach the part of the code.
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
appBar: CustomAppBar(),
backgroundColor: Colors.white,
body: SingleChildScrollView(
controller: widget.homeController,
child: Column(
children: [
Inicio(),
Services(),
QuienesSomos(),
ContactForm(),
BottomInfo(),
],
),
),
);
}
So I have one button on the appbar per each children in the SingleChildScrollView and I would like that when I press the correspondent button, it scrolls down to the correspondent section on the widget. I tried with Navigator.of().PushNamed but it opens a new screen instead of scrolling down. Any ideas? Thanks in advance!
To control the position, you have to manage the controller of the SingleChildScrollView .
If you want to smoothly go a section, you can attach functionality to control the SingleChildScrollView controller to the button:
widget.homeController.animateTo(
0.0, // change 0.0 {double offset} to corresponding widget position
duration: Duration(seconds: 1),
curve: Curves.easeOut,
);
If you just want to instantly jump to the position:
widget.homeController.jumpTo(0.0); // change 0.0 {double value} to corresponding widget position
Make a scroll controller:
ScrollController myController = ScrollController();
and attach it to your SingleChildScrollView widget:
SingleChildScrollView(
controller: myController,
child: ...
Now create a GlobalKey:
final anchor = GlobalKey();
Attach it to any of your widget:
Container(
key: anchor,
child: ...
),
That's it, now you can programmatically scroll to this widget using scroll controller:
myController.position.ensureVisible(
anchor.currentContext.findRenderObject(),
alignment: 0.5,
duration: const Duration(seconds: 1),
);
I could achieve my goal by using,
onPressed: () {
Scrollable.ensureVisible(servicesKey.currentContext,
duration: Duration(seconds: 1),
curve: Curves.easeOut);
},
and by asigning the corresponding key in each widget.

Flutter PageView, can i animate removing items from list?

I'm pretty new to flutter and i'm trying to do some animation on a PageView. to be precise, I want to animate removing an item.
I've tried serveral ways to animate it and apart from a solution, the way how you guys would solve such a problem would also be helpful for my flutter skils.
What I've tried so far:
Animating the padding and opacity
the problem with this is that when i set the padding in the setState in the onLongPress it rebuilds the widget and it overrides the padding again with the active or inactive CardPadding (i think)
Animating the width and height
I just can't seem to get both of these values to work
Animating the viewportFraction on the PageViewController
Would not know how to go about this and if it would be possible to do this only for a specific 'Page'
Below is the (stripped down) code I've written thus far.
class Main extends StatefulWidget {
#override
_MainState createState() => _MainState();
}
class _MainState extends State<Main> {
int activeCard = 0;
EdgeInsets inActiveCardPadding = EdgeInsets.symmetric(vertical: 120.0, horizontal: 20.0);
EdgeInsets activeCardPadding = EdgeInsets.symmetric(vertical: 105.0, horizontal: 10.0);
PageController pageController = PageController(
initialPage: 0,
viewportFraction: 0.8,
);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Stack(
children: <Widget>[
PageView.builder(
itemCount: PlantCareApp.plants.length,
controller: pageController,
onPageChanged: (activeCardIndex) {
setState(() {
this.activeCard = activeCardIndex;
});
},
itemBuilder: (context, cardIndex) {
return AnimatedContainer(
padding: (activeCard == cardIndex) ? activeCardPadding : inActiveCardPadding;,
duration: Duration(milliseconds: 250),
child: PlantCard(
PlantCareApp.plants[cardIndex],
onTap: () {
Navigator.pushNamed(context, PlantDetailScreen.route, arguments: PlantCareApp.plants[cardIndex]);
},
onLongPress: () {
setState(() {
//
// ANIMATE OR TRIGGER ANIMATION HERE
//
// do the actual removing
/*
PlantCareApp.plants[cardIndex].remove(); // remove from db
PlantCareApp.plants.removeAt(cardIndex); // remove from List
*/
});
//PlantCareApp.plants[cardIndex].remove();
},
),
);
},
),
],
),
),
);
}
}
Any help will be greatly appreciated! How would you guys tackle a problem like this, or how would you tackle this specific use case.
I guess actually animating viewportFraction would be the nicest because of the adjecent 'Pages' moving toward each other as well?
Thanks!
I'm not certain if this is what you are looking for, but here goes.
One way of doing this is simply using the provided Widgets within Flutter. Two of these will help you out: AnimatedList and Dismissible.
Now, you could do something like this:
// define somewhere
final _animatedListGK = GlobalKey<AnimatedListState>();
// put in a function somewhere
return AnimatedList(
key: _animatedListGK,
padding: const EdgeInsets.all(0),
initialItemCount: PlantCareApp.plants.length,
itemBuilder: (context, index, animation) {
return FadeTransition(
opacity: animation,
child: _buildDismissibleRow(context, index, PlantCareApp.plants[index])
);
}
);
Note: you don't have to use the _animatedListGK global key per se, it depends on whether you can use AnimatedList.of(context) or not. Although it is the easier way.
The _animatedListGK is simply a Global Key that provides access to the AnimatedList so you can perform insertions/removals with animation.
Your dismissible row might look something like:
Widget _buildDismissibleRow(BuildContext context, int index, PlantModel plantModel) {
return Dismissible(
key: ValueKey<String>(plantModel.someKey),
direction: DismissDirection.startToEnd,
background: Container(color: Colors.red),
onDismissed: (direction) {
// You could use:
// AnimatedList.of(context)
_animatedListGK.currentState.removeItem(
index,
(context, animation) => Container(),
duration: Duration.zero
);
},
child: _buildContent(context, index, plantModel)
);
}
You could also do it without a dismissible row or even within the child of the dismissible row (_buildContent() for example). Something similar to:
// You could use:
// AnimatedList.of(context)
_animatedListGK.currentState.removeItem(
index,
(context, animation) {
return FadeTransition(
opacity: CurvedAnimation(parent: animation, curve: Interval(0.5, 1.0)),
child: SizeTransition(
sizeFactor: CurvedAnimation(parent: animation, curve: Interval(0.0, 1.0)),
child: _builContent(context, index, plantModel)
)
);
},
duration: const Duration(milliseconds: 300)
);
Notice how the SizeTransition simply "calls itself" by calling _builContent(context, index, plantModel)? That's how you can animate the row itself (out of existence).
Be sure to watch the videos in the aforementioned documentation pages! They will help understanding certain constructs.
A preview of what the dismissible might look like:
A preview of what the SizedTransition might look like:

How to remove blue/grey scroll animation of tabbarview in Flutter?

I have a TabBarview when slide from one page to another splash appear in the very side of the page.
I don't want the splash highlight to appear on both sides.
Although tabbarview has physics and when set to bouncingscrollphysics() this shape shouldnt appear, like what occur in list view, but nothing changed.
Tried another solution: I wrapped the tabbarview with a theme and changed the highlight color and splash color to colors.transparent but that didn't work either. Here is the code for my TabBarview.
and here is the ui, and how it looks.
Theme(
data: new ThemeData(
splashColor: Colors.transparent,
highlightColor: Colors.transparent),
child: TabBarView(
physics: BouncingScrollPhysics(),
controller: _controller,
children: model.types.map((String type) {
List<Subscription> subssOfThisType =
model.historySubscription.where((Subscription sub) {
return sub.package.name == type;
}).toList();
final cards = subssOfThisType.map(
(s) {
return HistoryCard(
sub: s,
);
},
).toList();
return ListView(
physics: BouncingScrollPhysics(),
padding:
EdgeInsets.symmetric(horizontal: 14, vertical: 8),
children: cards ?? Container(),
);
}).toList(),
),
)
If you don't want to make some breaking changes in the original code of TabBar hten use the below package
https://pub.dev/packages/flutter_tab_bar_no_ripple
=== For your use case ===
To keep things simple ... change physics to BouncingScrollPhysics()
If you don't want that bouncy effect then check the link below
https://stackoverflow.com/a/51119796/10104608
change physics to BouncingScrollPhysics()
Would you like to try ScrollConfiguration?
it works fine.
body: ScrollConfiguration(
behavior: MyBehavior(),
child: const TabBarView(
children: [
TabPage(icon: Icons.directions_car),
TabPage(icon: Icons.directions_bike),
],
),
),
class MyBehavior extends ScrollBehavior {
#override
Widget buildViewportChrome(
BuildContext context, Widget child, AxisDirection axisDirection) {
return child;
}
}
https://stackoverflow.com/a/51119796/9819094