I've been developing android apps for a while now and I'm currently porting an android app to flutter which I started not long ago. I have been able to make tabs scrollable in android but I'm finding it difficult to do that in flutter. I am able to create the tabs but they are about 7 and they exceed the screen width. Hence I want to make it scrollable to avoid that.
Below is what I did in the android app and I want to achieve something similar. Any help would be appreciated. Thanks.
You can use a DefaultTabController widget , also the Tab widget has a property called : isScrollable , set true and you will see.
This is a basic sample:
final List<Tab> myTabs = List.generate(
10,
(index) => Tab(text: 'TAB $index'),
);
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: myTabs.length,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
isScrollable: true,
tabs: myTabs,
),
),
body: TabBarView(
children: myTabs.map((Tab tab) {
return Center(child: Text(tab.text));
}).toList(),
),
),
);
}
You can find more info here: https://docs.flutter.io/flutter/material/DefaultTabController-class.html
Related
#override
Widget build(BuildContext context) {
super.build(context);
SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
),
child: Scaffold(
key: _scaffoldKeyProfilePage,
body: DefaultTabController(
length: 2,
child:RefreshIndicator(
onRefresh: _onRefresh,
child: NestedScrollView(
headerSliverBuilder: (context, _) {
return [
SliverList(
delegate: SliverChildListDelegate(
[ BuildMainProfile(
....//
),
Padding(
...//another design
),
];
},
// You tab view goes here
body: Column(
children: <Widget>[
TabBar(
tabs: [
Tab(text: 'A'),
Tab(text: 'B'),
],
),
Expanded(
child: TabBarView(
children: [
BuildPost(,
),
BuildWings()
],
),
),
],
),
),),
),
}
Refresh Indicator not working with NestedScrollView, is there any way to implement RefreshIndiactor?
I tried adding an empty ListView in Stack, Refresh indicator start showing but because of that my NestedScrollView doesnt scroll.
Did you try setting NestedScrollView widgets physics to AlwaysScrollableScrollPhysics()?
Please see the documentation for RefreshIndicator.
Refresh indicator does not show up
The RefreshIndicator will appear if its scrollable descendant can be
overscrolled, i.e. if the scrollable's content is bigger than its
viewport. To ensure that the RefreshIndicator will always appear, even
if the scrollable's content fits within its viewport, set the
scrollable's Scrollable.physics property to
AlwaysScrollableScrollPhysics:
ListView(
physics: const AlwaysScrollableScrollPhysics(),
children: ... )
A RefreshIndicator can only be used with a vertical scroll view.
Please try to wrap 'body' of the NestedScrollView with RefreshIndicator widget if the headers won't change when refreshed but only the content change happens for 'body'.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('My form'),
),
body: new Scrollbar(
child: TextField(
maxLines: 99999,
),
isAlwaysShown: true,
controller: ScrollController(),
),
);
}
I'm making Windows and Web apps with Flutter.
I want to be able to drag the scroll bar of the input field with the mouse.
But with this code I do nothing when I drag the bar with the mouse.
How can I drag it?
Flutter's SDK is Channel master, 1.22.0-10.0.pre.380.
I'm currently trying to get a multi tabbed form working. I am using the package flutter_form_builder for that.
The problem is, that the FormBuilder requires all descendant form fields to be loaded at least once to run validations and to provide the correct value of the field. When the user visits every tab once the thing works fine, but I cannot assume that this will always happen.
The simplest solution in my eyes would be, to somehow get the TabBarView to render all tab pages at startup, so that every tab-widget and the form-fields exist.
I have the main page where I define the form builder and the tabview inside of it. The important part looks like this:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: 'title',
bottom: TabBar(
controller: tabController,
tabs: <Widget>[
Tab(icon: Icon(Icons.title)),
Tab(icon: Icon(Icons.image)),
Tab(icon: Icon(Icons.category)),
],
),
),
body: FormBuilder(
key: formBuilderKey,
autovalidate: true,
child: TabBarView(
controller: tabController,
children: <Widget>[
MainTab(),
CoverTab(),
GroupsTab()
],
)
)
);
}
One tab page looks more or less like this:
class GroupsTab extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return GroupsTabState();
}
}
class GroupsTabState extends State<GroupsTab> with AutomaticKeepAliveClientMixin {
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
padding: EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
FormBuilderTextField(
attribute: "name",
decoration: InputDecoration(
labelText: "Name",
icon: Icon(Icons.title),
),
validators: [FormBuilderValidators.required()],
),
// Page content with form fields
],
),
);
}
#override
bool get wantKeepAlive => true;
}
I'm already using the AutomaticKeepAliveClientMixin to only call the build method of every tab page once but I need a bit more.
So my question: Is it possible to get the TabBarView to render all the widgets at startup or do you have an idea for a different solution.
Thank you all guys in advance
I have used SilverAppBar but don't know how to add a drawer to it. I just want an app bar with a drawer that hides on scrolling
Note that the Scaffold takes care of all of the major behavior associated with Material design.
If you add the drawer field to your Scaffold, it will automatically add a hamburger menu icon to the left hand side of your SilverAppBar in flutter.
Code:
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
title: Text('Drawer - Sliver AppBar'),
)],
),
drawer: Drawer(
child: Column(
children: <Widget>[
DrawerHeader(
child: Text(' I am Drawer'),
curve: SawTooth(12),
),
],
),
),
);
}
This issue has been haunting me for some time and even though I read countless web pages, I still cannot solve it. Maybe you're able to help out!
I got the following scenario:
A Flutter app has a PageView with just 3 pages.
First page has a simple GridView (vertical scrolling) and no problem there with nested scrolling.
Third page is a simple ListView with lists of items, no problem here also with scrolling.
The second page has a NestedScrollView, with two widgets for its headerSliverBuilder: SliverAppBar and SliverPersistentHeader. Nothing fancy here.
The body of the NestedScrollView contains a TabBarView which contains 3 tabs, and it's possible to swipe between them using a horizontal swipe -- the same swipe direction as the PageView which contains this page.
The body is where the scrolling problem occurs.
Swiping between the 3 tabs works like a charm. However, when the current tab is the first and you try to swipe further to the left (finger motion is from left-to-right), the first page (belonging to PageView) doesn't show. Conversely, when the current tab is the 3rd and you try to swipe further to the right (finger motion is from right-to-left), nothing happens.
If you do the same finger motion on the header contained in the second page, the pages turn fine (either to the first or third pages).
Here's the code inside the second page, would love to know why swiping motion inside the TabBarView isn't propagating to the container when tabs reach the edges:
Scaffold(
appBar: _generateAppBar(),
body: DefaultTabController(
length: 3,
child: NestedScrollView(
headerSliverBuilder: (_, __) => [
SliverAppBar(
backgroundColor: backgroundColor,
elevation: 0.0,
expandedHeight: 200.0,
floating: true,
pinned: false,
flexibleSpace: backgroundImageView,
),
SliverPersistentHeader(
floating: false,
delegate: _SliverAppBarDelegate(
TabBar(
labelColor: Theme.of(context).primaryColor,
unselectedLabelColor: Colors.black26,
indicatorWeight: 2.5,
tabs: const [
Text('Tab 1'),
Text('Tab 2'),
Text('Tab 3'),
],
),
),
pinned: true,
),
],
body: TabBarView(
children: [
Center(child: Text('Body 1')),
Center(child: Text('Body 2')),
Center(child: Text('Body 3')),
],
),
),
),
);
Auxiliary class:
class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
_SliverAppBarDelegate(this._tabBar);
final TabBar _tabBar;
#override
double get minExtent => _tabBar.preferredSize.height;
#override
double get maxExtent => _tabBar.preferredSize.height;
#override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) =>
Container(child: _tabBar);
#override
bool shouldRebuild(_SliverAppBarDelegate oldDelegate) =>
false;
}
Any idea how to fix this? Thanks!
You should wrap the
NestedScrollView like
DefaultTabController(
length: tabs.length,
child: NestedScrollView())