I am trying to create a tabbed bar layout screen without the AppBar though. I have already referred to the solution on this link: how to create the tab bar without app bar in flutter? but it is not working for me. Here is what my screen looks like when I place TabBar in the appbar: parameter:
My TabBar has moved to the top left corner under the status bar and its all squeezed in one corner. It's almost as if it's not there at all.
When I use the AppBar class but only pass the bottom: parameter here is what happens:
There is an ugly space on top of the TabBar which is obviously meant for the AppBar title. Here is my code:
return new Scaffold(
appBar: new TabBar(
tabs: widget._tabs.map((_Page page){
return Text(page.tabTitle);
}).toList(),
controller: _tabController,
isScrollable: true,
),
backgroundColor: Colors.white,
body: new TabBarView(
controller: _tabController,
children: widget._tabs.map((_Page page){
return new SafeArea(
top:false,
bottom: false,
child: (page.page == Pages.cart?new CartHomeScreen():_lunchesLayout())
);
}).toList()
),
);
How can I just have TabBar without that space on top and is it possible to make the two tab items and their indicators to stretch and fill the side spaces?
Your first screenshot actually shows it working just fine - the issue is that 'fine' isn't quite what you expect. The default text color is white for tabbar, so your labels aren't showing and instead just the bottom line is, which is what you see at the top left. Also, TabBar is a preferred size widget already, but it doesn't have the same height as an AppBar so if that's what you're going for, it won't look like it.
Here's an example that makes it look like the app bar. kToolbarHeight is the same constant that AppBar uses.
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() => new MyAppState();
}
class MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'msc',
home: new DefaultTabController(
length: 2,
child: new Scaffold(
appBar: new PreferredSize(
preferredSize: Size.fromHeight(kToolbarHeight),
child: new Container(
color: Colors.green,
child: new SafeArea(
child: Column(
children: <Widget>[
new Expanded(child: new Container()),
new TabBar(
tabs: [new Text("Lunches"), new Text("Cart")],
),
],
),
),
),
),
body: new TabBarView(
children: <Widget>[
new Column(
children: <Widget>[new Text("Lunches Page")],
),
new Column(
children: <Widget>[new Text("Cart Page")],
)
],
),
),
),
);
}
}
Which results in this:
Edit:
As noted in the comments and from this github issue, you could also use the flexibleSpace property of the AppBar to hold the tabbar to basically the same effect:
return new DefaultTabController(
length: 3,
child: new Scaffold(
appBar: new AppBar(
flexibleSpace: new Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
new TabBar(
tabs: [
new Tab(icon: new Icon(Icons.directions_car)),
new Tab(icon: new Icon(Icons.directions_transit)),
new Tab(icon: new Icon(Icons.directions_bike)),
],
),
],
),
),
),
);
Follow below 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: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
TabController _tabController;
#override
void initState() {
_tabController = new TabController(length: 2, vsync: this);
super.initState();
}
#override
void dispose() {
_tabController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
height: MediaQuery.of(context).size.height / 2,
child: Center(
child: Text(
"Tabbar with out Appbar",
style: TextStyle(
color: Colors.white, fontWeight: FontWeight.bold),
),
),
color: Colors.blue,
),
TabBar(
unselectedLabelColor: Colors.black,
labelColor: Colors.red,
tabs: [
Tab(
text: '1st tab',
),
Tab(
text: '2 nd tab',
)
],
controller: _tabController,
indicatorSize: TabBarIndicatorSize.tab,
),
Expanded(
child: TabBarView(
children: [
Container(child: Center(child: Text('people'))),
Text('Person')
],
controller: _tabController,
),
),
],
),
),
);
}
#override
void dispose() {
_tabController.dispose();
super.dispose();
}
}
view the result
I take the code from rmtmckenzie but only to create a widget without material app
return new DefaultTabController(
length: 3,
child: new Scaffold(
appBar: new PreferredSize(
preferredSize: Size.fromHeight(kToolbarHeight),
child: new Container(
height: 50.0,
child: new TabBar(
tabs: [
Tab(icon: Icon(Icons.directions_car,color: Colors.grey,)),
Tab(icon: Icon(Icons.directions_transit,color: Colors.grey)),
Tab(icon: Icon(Icons.directions_bike,color: Colors.grey)),
],
),
),
),
body: TabBarView(
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
),
),
);
You won't need to use appBar property:
Scaffold(
body: Column(
children: [
TabBar( // <-- Your TabBar
tabs: [
Tab(icon: Icon(Icons.camera)),
Tab(icon: Icon(Icons.settings)),
],
),
Expanded(
child: TabBarView( // <-- Your TabBarView
children: [
Container(color: Colors.blue),
Container(color: Colors.red),
],
),
),
],
),
)
Just use toolbarHeight property in AppBar widget with kMinInteractiveDimension value as shown below:
Scaffold(
appBar: AppBar(
toolbarHeight: kMinInteractiveDimension,
bottom: TabBar(
controller: _tabController,
tabs: [], // your tab bars
),
),
body: TabBarView(
controller: _tabController,
children: [], // your tab views
),
);
Just use the flexiblespace prop and not the bottom prop of the appBar.
All in the safeArea widget and you can add some vertical padding.
home: SafeArea(
top: true,
child: Padding(
padding: const EdgeInsets.only(top: 10.0),
child: DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
flexibleSpace: TabBar(
tabs: [
Tab(icon: Icon(Icons.1)),
Tab(icon: Icon(Icons.2)),
Tab(icon: Icon(Icons.3)),
],
),
),
body: TabBarView(
children: [
Icon(Icons.1),
Icon(Icons.2),
Icon(Icons.3),
],
),
),
),
),
)
Directly use TabBar in appBar property:
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: TabBar(
tabs: [
Tab(icon: Icon(Icons.call)),
Tab(icon: Icon(Icons.message)),
],
),
body: TabBarView(
children: [
Center(child: Text('Call')),
Center(child: Text('Message')),
],
),
),
);
}
From CopsOnRoad's answer, I've created a hidden TabBar like this:
Scaffold(
body: Column(
children: [
TabBar( // <-- Hidden TabBar
indicator: BoxDecoration(),
tabs: [
SizedBox.shrink(),
SizedBox.shrink(),
],
),
Expanded(
child: TabBarView( // <-- Your TabBarView
children: [
Container(color: Colors.blue),
Container(color: Colors.red),
],
),
),
],
),
)
It's very simple, all what you have to provide is height to your TabView.
Here is a simple example. You can either use DefaultTabController or TabController. In order to fully customizable, I'll use TabController.
_getTabBar function return list of tabs.
TabBar _getTabBar() {
return TabBar(
tabs: <Widget>[
Tab(icon: Icon(Icons.home, color: Colors.redAccent)),
Tab(icon: Icon(Icons.settings, color: Colors.redAccent)),
],
controller: tabController,
);
}
_getTabBarView take list of widgets as input argument and creates a tab view.
TabBarView _getTabBarView(tabs) {
return TabBarView(
children: tabs,
controller: tabController,
);
}
SafeArea is used to move content below status bar. _getTabBarView is wrapped with a Container so that we can allocate a height. This is one way of allocating height, you can use some other way also.
So here is the full code, wrap within a MaterialApp and you have got a fully customizable tab bar and view. life-cycle methods are used to create and dispose TabController
import 'package:flutter/material.dart';
class TabControllerScreen extends StatefulWidget {
#override
_TabControllerScreenState createState() => _TabControllerScreenState();
}
class _TabControllerScreenState extends State<TabControllerScreen> with SingleTickerProviderStateMixin {
TabController tabController;
#override
void initState() {
super.initState();
tabController = TabController(length: 2, vsync: this);
}
#override
void dispose() {
tabController.dispose();
super.dispose();
}
TabBar _getTabBar() {
return TabBar(
tabs: <Widget>[
Tab(icon: Icon(Icons.home, color: Colors.redAccent)),
Tab(icon: Icon(Icons.settings, color: Colors.redAccent)),
],
controller: tabController,
);
}
TabBarView _getTabBarView(tabs) {
return TabBarView(
children: tabs,
controller: tabController,
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: <Widget>[
_getTabBar(),
Container(
height: 100,
child: _getTabBarView(
<Widget>[
Icon(Icons.home),
Icon(Icons.settings),
],
),
)
],
),
),
);
}
}
Here you go. This is a widget, without any scafold or material app around it, so make sure you provide that tree yourself. Otherwise it's ready for copy-paste
import 'package:flutter/material.dart';
class MyWidget extends StatefulWidget {
const MyWidget({super.key});
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget>
with SingleTickerProviderStateMixin {
late final TabController _tabController;
#override
void initState() {
_tabController = TabController(length: 2, vsync: this);
super.initState();
}
#override
Widget build(BuildContext context) {
return Column(children: [
TabBar(controller: _tabController, tabs: const [
Tab(icon: Icon(Icons.cookie_outlined)),
Tab(icon: Icon(Icons.no_food))
]),
Expanded(
child: TabBarView(controller: _tabController, children: [
Container(color: Colors.greenAccent),
Container(color: Colors.yellowAccent)
]))
]);
}
}
Try to put TabBar inside AppBar in its flexibleSpace property.
Give toolbarHeight : 0 for Appbar
appBar: AppBar(
toolbarHeight: 0, // <--- Add this line to app bar
bottom: TabBar(tabs: [
Tab(
text: "Transactions",
),
Tab(
text: "Transfer",
)
]),
),
Recommended method using toolbarHeight property
By setting the toolbarHeight property of a AppBar to zero will remove them toolbar and leaving the tabbar at the bottom as set by theme.
Scafford(
appBar: AppBar(
toolbarHeight: 0,
bottom: TabBar(...)
)
)
Related
I'm a beginner trying to practice coding with Flutter so it would be helpful if the explanation or suggestion is easy to understand. :) Thanks in advance!
[Goal]
I've created a two folders and one of them is for parts that can be used in multiple places without having to create them every time. And the other one includes files with different pages (I like to keep them separate).
[Question]
I'm currently trying to navigate by using the side drawer and want to go to other pages, however it's not working and I'm getting blanks in black :( Please help...
In this case, should I use the "routes:" argument or should I use the MaterialPageRoute() or is there something else that can be suggested?
I apologize for posting the entire code, but I thought it would be best to understand the whole context. If there's anything that seems odd or have a better idea. Please do let me know!
[Code of Drawer]
class AppDrawer extends StatefulWidget {
#override
_AppDrawerState createState() => _AppDrawerState();
}
class _AppDrawerState extends State<AppDrawer> {
#override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
children: <Widget>[
UserAccountsDrawerHeader(
accountName: Text('John T.'),
accountEmail: Text('*********#gmail.com'),
currentAccountPicture: GestureDetector(
child: CircleAvatar(
backgroundColor: Colors.grey,
child: Icon(Icons.person, color: Colors.white))),
decoration: BoxDecoration(color: Colors.red)),
ListTile(
leading: Icon(Icons.home, color: Colors.redAccent),
title: Text('Home'),
trailing: null,
onTap: () {
Navigator.of(context).pop();
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
Home();
},
),
);
},
),
ListTile(
leading: Icon(Icons.person, color: Colors.redAccent),
title: Text('My Acount'),
trailing: null,
onTap: () {
Navigator.of(context).pop();
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
MyAccount();
},
),
);
},
),
ListTile(
leading: Icon(Icons.fitness_center, color: Colors.redAccent),
title: Text('My Workout'),
trailing: null,
onTap: () {},
),
ListTile(
leading: Icon(Icons.cancel, color: Colors.redAccent),
title: Text('My Nutrition'),
trailing: null,
onTap: () {},
),
Divider(color: Colors.red, indent: 20.0),
ListTile(
leading: Icon(Icons.settings, color: Colors.blue),
title: Text('Settings'),
trailing: null,
onTap: () {},
),
ListTile(
leading: Icon(Icons.help, color: Colors.green),
title: Text('About'),
trailing: null,
onTap: () {},
),
],
),
);
}
}
[Code of Home Page]
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 5.0,
title: Text('Home'),
backgroundColor: Colors.red,
centerTitle: true,
),
endDrawer: AppDrawer(),
body: Container(
color: Colors.white,
child: Center(
child: ListView(
children: <Widget>[],
),
),
),
);
}
}
[My Account Page]
class MyAccount extends StatefulWidget {
final String value;
MyAccount({Key key, this.value}) : super (key: key);
#override
_MyAccountState createState() => _MyAccountState();
}
class _MyAccountState extends State<MyAccount> {
final TextEditingController _ageFieldController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('My Account'),
centerTitle: true,
backgroundColor: Colors.blue,
),
endDrawer: AppDrawer(),
body: Container(
color: Colors.white,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
child: Column(
children: <Widget>[
TextField(
controller: _ageFieldController,
decoration: InputDecoration(
hintText: 'Example: 27',
),
autocorrect: true,
keyboardType: TextInputType.number,
),
Text('${widget.value}')
],
),
),
],
),
),
),
);
}
}
[Code of Main.dart]
void main(List<String> args) {
runApp(Bmi());
}
class Bmi extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'BMI',
theme: ThemeData(
primarySwatch: Colors.deepPurple,
),
home: Home(),
);
}
}
The Material Design guidelines suggest a Drawer for navigation between sites of equal importance, so Navigator.push() should not be used, because the animation it does looks like it's a linear navigation(like going to the next page, not one of equal importance.)
Here's a link regarding this topic: material.io site for Navigation Drawer Component
I always update my body according to the currently selected item in the drawer, similar as you would do it with a BottomNavigationBar.
An implementation of that would look similar to this:
return Scaffold(
drawer: Drawer(),
body: Stack(
children: <Widget>[
Offstage(
offstage: index != 0,
child: _buildAccountPage(),
),
Offstage(
offstage: index != 0,
child: _buildHomePage(),
),
],
),
);
You need to return New Page to the Builder Function of Navigator.
Correct Code:
ListTile(
leading: Icon(Icons.person, color: Colors.redAccent),
title: Text('My Acount'),
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => MyAccount()));
},
),
I'm struggling with the ListView.
My problem is that I've a Listview inside another Listview and the second Listview items height are not always the same. I want to get rid of the itemExtent and create an automatically height for the first Listview.
What I really want to acomplish is something like this:
#override
Widget build(BuildContext context) {
return
Column(
children: <Widget>[
TextField(),
Expanded(
child: ListView.builder(
key: new Key("ditisdekeyvoordelistview"),
itemBuilder: _makeMovieList,
padding: EdgeInsets.all(0.0),
itemCount: _movies.length,
itemExtent: 300.0,
),
),
],
);
}
//FIRST LIST
Widget _makeMovieList(BuildContext context, int index) {
return Container(
child: ListTile(
contentPadding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0),
leading: Container(
child: Column(mainAxisSize: MainAxisSize.max, children: <Widget>[
Image.network(
_movies[index].movieImage,
fit: BoxFit.cover,
width: 100.0,
)
])),
title: Text(
_movies[index].movieTitle,
),
subtitle: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
_makeStarRating(_movies[index].movieRating),
Text(_movies[index].movieDescription),
_makeCardDates(index)
],
),
),
);
}
//SECOND LIST
Widget _makeCardDates(int index) {
return Expanded(
child: ListView.builder(
physics: const NeverScrollableScrollPhysics(),
padding: EdgeInsets.all(0.0),
itemCount: _movies[index].dateTimeList.length,
itemBuilder: (context, indexx) {
return GestureDetector(
onTap: () {
print(_movies[index].dateTimeList[indexx].toString());
},
child: Card(
elevation: 8.0,
color: Color.fromRGBO(64, 75, 96, .9),
child: Column(
children: <Widget>[
Text(_movies[index].cinema),
Text(((dateFormatMovieHours
.format(_movies[index].dateTimeList[indexx]))
.toString())),
],
)));
},
itemExtent: 40.0,
),
);
}
Using itemExtent on a ListView isn't required, though ListView needs to have a finite height set for vertical scroll (default) and finite width is needed for horizontal scroll. Otherwise, the ListView will throw a "constraints are unbounded" error.
For your use case, you can either set height on the list items in the first ListView, or set height on the second ListView. However, if you'd like the second ListView to be non-scrollable and the list items in the first ListView will adapt dynamically, you can use a Column of Widgets similar to this sample.
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,
),
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> {
final items = [
'Apple',
'Banana',
'Carrot',
'Dog',
'Egg',
'Flower',
'Goat',
'Honey'
];
final subItems = ['1.00', '2.00', '3.00', '4.00'];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: firstList(),
),
);
}
firstList() {
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return Container(
padding: EdgeInsets.all(8.0),
child: Card(
child: Container(
color: Colors.lightBlue[50],
padding: EdgeInsets.all(16.0),
child: Row(
children: [
Expanded(
flex: 2,
child: Text('${items[index]}'),
),
Expanded(
flex: 1,
child: secondList(subItems),
),
],
),
),
),
);
},
);
}
secondList(List item) {
// Create List<Widget> for the second "List"
var subList = List<Widget>();
item.forEach((data) {
subList.add(
Card(
child: Container(
padding: EdgeInsets.all(16.0),
color: Colors.lightBlueAccent,
child: Text('$data'),
),
),
);
});
// Populate Column instead of ListView
return Column(
children: subList,
);
}
}
I have a small data table and i want to change the column and row background color.
But unfortunately there is no property in DataColumn or DataRow to achieve this.
The only way i found is through modifying the label of DataColumn
DataColumn(label: Container(child: Text('Person'),color: Colors.amberAccent,)),
but there is a default padding for the DataColumn and the color only applies to the text.
and here is my code:
class _ContactLocationsState extends State<ContactLocations> {
#override
Widget build(BuildContext context) {
return Center(
child: DataTable(columns: <DataColumn>[
DataColumn(label: Text('Person')),
DataColumn(label: Text('Rating')),
DataColumn(label: Text('Distance')),
DataColumn(label: Text('Max Price')),
DataColumn(label: Text('Fee')),
], rows: <DataRow>[
DataRow(
cells: <DataCell>[
DataCell(Text("test")),
DataCell(Text("test")),
DataCell(Text("test")),
DataCell(Text("test")),
DataCell(Text("test")),
],
),
]),
);
}
}
If you are still looking for answer, you can use MaterialStateColor property. Here is the working code
return DataRow.byIndex(
index: row.key,
color: MaterialStateColor.resolveWith(
(states) {
if (row.key % 2 == 0) {
return Colors.blue[50];
} else {
return Colors.white;
}
},
),
I found a way using that you can achieve exactly same look as table and also change the colors of background using Row and Expanded Widgets.
I hope that Following Code Help You.
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
debugShowCheckedModeBanner: false,
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
AnimationController _controller;
#override
void initState() {
_controller = AnimationController(vsync: this);
super.initState();
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Container(
color: Colors.green,
child: Text("person")
),
),Expanded(
child: Container(
color: Colors.red,
child: Text("Rating")
),
),Expanded(
child: Container(
color: Colors.green,
child: Text("Distance")
),
),Expanded(
child: Container(
color: Colors.red,
child: Text("Max Price")
),
),Expanded(
child: Container(
color: Colors.green,
child: Text("Free")
),
),
],
),
Row(
children: <Widget>[
Expanded(
child: Container(
color: Colors.red,
child: Text("Test")
),
),Expanded(
child: Container(
color: Colors.green,
child: Text("Test")
),
),Expanded(
child: Container(
color: Colors.red,
child: Text("Test")
),
),Expanded(
child: Container(
color: Colors.green,
child: Text("Test")
),
),Expanded(
child: Container(
color: Colors.red,
child: Text("Test")
),
),
],
),
],
),
)
),
);
}
}
In my MaterialApp I have a Column inside a horizontal ListView.
Inside that Column is a Text widget.
ListView(
children: [
Column(
children: [
Text('this is the text widget'),
// here I have another widget placed, just imagine a rectangle
],
],)
textAlign: TextAlign.center, nor surrounding it with a Center will change the position of the Text. The Text will always stay in the top left corner.
Also, I saw a lot about axis alignments in answers regarding similar problems, but I tried every axis settings I saw without success.
As you can see the text in the upper image is not centered.
You need crossAxisAlignment: CrossAxisAlignment.center
ListView(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text('this is the text widget'),
// here I have another widget placed, just imagine a rectangle
],
),
],
)
EDIT:
Since, you are unsatisfied with above answer. I re-did what you exactly want. Please refer below code:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'MediaQuery Demo',
theme: new ThemeData(
primarySwatch: Colors.red,
),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
Widget widgetToRepeat() {
return new Column(
children: <Widget>[
new Text('Hello'),
new Container(
width: 100.0,
height: 150.0,
color: Colors.green,
margin: new EdgeInsets.all(8.0),
)
],
);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Demo'),
),
body: new Column(
children: <Widget>[
new Container(
child: new ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
widgetToRepeat(),
widgetToRepeat(),
widgetToRepeat(),
widgetToRepeat(),
widgetToRepeat(),
],
),
height: 150.0 + 16.0 + 20.0 + 16.0,
padding: new EdgeInsets.all(10.0),
)
],
),
);
}
}
I hope this helps. I am able to achieve text at horizontally center.
return new ListView(children: [
new Center(
child: Column(
children: [
Text('this is the text widget'),
// here I have another widget placed, just imagine a rectangle
],
),
)
]);
warp with new Center Widget
I have been trying to add listeners when using DefaultTabController. However, every time I add a TabController in order to get the current index in either TabBar and TabBarView, I lose sync between them.
This is my code below:
#override
Widget build(BuildContext context) {
return new DefaultTabController(
length: subPages.length,
child: new Scaffold(
appBar: appBar('homepage'),
body: new Center(
child: new NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
new SliverAppBar(
backgroundColor: Colors.white,
title: new TabBar(
labelColor: Colors.black,
indicatorColor: Colors.black,
labelStyle: new TextStyle(fontWeight: FontWeight.bold),
tabs: subPages.map((String str) => new Tab(text: str)).toList(),
),
),
];
},
body: new TabBarView(
children: subPages.map((String str) {
return new ListView(
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
children: subPages.map((String str) {
return new Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: new Text(str),
);
}).toList(),
);
}).toList(),
),
),
),
floatingActionButton: new FloatingActionButton(
backgroundColor: Colors.black,
onPressed: null,
tooltip: 'Increment',
child: new Icon(Icons.add),
),
),
);
}
I use this:
new DefaultTabController(
child: Builder(
builder: (context) {
final tabController = DefaultTabController.of(context)!;
tabController.addListener(() {
print("New tab index: ${tabController.index}");
});
return Scaffold(
...
);
}
),
);
Define a tabController and a listener (once changing tab, it will be triggered twice)
class _ScreenState extends State<Screen> with SingleTickerProviderStateMixin {
late TabController tabController;
#override
void initState() {
super.initState();
this.tabController = TabController(length: 3, vsync: this);
this.tabController.addListener(() {
if (this.tabController.indexIsChanging) {
print(this.tabController.index);
print(this.tabController.previousIndex);
}
});
}
}
Pass it to the TabBar and TabBarView, like:
TabBar(
controller: this.tabController,
tabs: [
Tab(text: "0"),
Tab(text: "1"),
Tab(text: "2"),
],
)
TabBarView(controller: this.tabController, children: [...])