What i'm trying to achieve is that, depending on the content of the TabBarView
component, expand it to take as much space as it needs ( height ) and make the whole screen scrollable, not only the Container
of the TabBarView
.
In the attached example I have a Container
which wraps the TabBar
component. It has a fixed height at the moment because it throws errors if not. Actually that's the problem i want to fix. Get rid of that fix height, and have it somehow dinamically set.
Here is my code with comments:
import 'package:flutter/material.dart';
import 'package:livescore/models/leaguesModel/leagues_model.dart';
import 'package:livescore/models/livescores/livescore_data_model.dart';
import 'package:livescore/pages/matchDetailsPage/components/matchDetailsHeaderWidgets/match_details_header.dart';
import 'package:livescore/pages/matchDetailsPage/components/matchDetailsStatsWidgets/match_details_stats_component.dart';
// ignore: must_be_immutable
class MatchDetailsPage extends StatefulWidget {
LeaguesModelData leaguesModelData;
LivescoreDataModel matchDetails;
MatchDetailsPage(this.leaguesModelData, this.matchDetails, {super.key});
@override
State<MatchDetailsPage> createState() => _MatchDetailsPageState();
}
class _MatchDetailsPageState extends State<MatchDetailsPage>
with SingleTickerProviderStateMixin {
late TabController _tabController;
@override
void initState() {
_tabController = TabController(length: 10, vsync: this);
super.initState();
}
@override
void dispose() {
super.dispose();
_tabController.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Container(
// whole screen background and border
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
border: Border.all(
color: Theme.of(context).colorScheme.primary, width: 5),
),
child: Column(
children: <Widget>[
MatchDetailsHeader(
widget.leaguesModelData,
widget
.matchDetails), // upper side of the screen, above the TabBar component
Padding(
padding: const EdgeInsets.only(top: 30, right: 20, left: 20),
child: Container(
// the container representing the TabBar zone
height: 400,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
border: Border.all(color: Colors.white),
color: Colors.white,
borderRadius: const BorderRadius.all(Radius.circular(10)),
),
child: Padding(
padding: const EdgeInsets.only(left: 10, right: 10),
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(top: 15, bottom: 20),
child: SizedBox(
child: TabBar(
labelPadding:
const EdgeInsets.symmetric(horizontal: 10),
isScrollable: true,
indicatorWeight: 0,
labelStyle: const TextStyle(fontSize: 13),
unselectedLabelColor: Colors.grey.shade700,
labelColor: Colors.white,
indicator: const ShapeDecoration(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(15))),
color: Colors.pink),
tabs: const [
Tab(
text: "Stats",
),
Tab(
text: "Info",
),
Tab(
text: "Line-up",
),
Tab(
text: "H2H",
),
Tab(
text: "Table",
),
Tab(
text: "News",
),
Tab(
text: "Info",
),
Tab(
text: "Info",
),
Tab(
text: "Info",
),
Tab(
text: "Info",
),
],
controller: _tabController,
indicatorSize: TabBarIndicatorSize.tab,
),
),
),
Expanded(
flex: 1,
child: TabBarView(
physics: const NeverScrollableScrollPhysics(),
controller: _tabController,
children: [
(widget.matchDetails.stats != null &&
widget
.matchDetails.stats!.data.isNotEmpty)
? MatchDetailsStatsComponent(
widget.matchDetails.localTeam.data.id,
widget.matchDetails.visitorTeam.data.id,
widget.matchDetails.stats)
: Column(
children: const [
Text("stats not available yet"),
Text("stats not available yet"),
Text("stats not available yet"),
Text("stats not available yet"),
Text("stats not available yet"),
Text("stats not available yet"),
Text("stats not available yet"),
Text("stats not available yet"),
Text("stats not available yet"),
Text("stats not available yet"),
Text("stats not available yet"),
Text("stats not available yet"),
Text("stats not available yet"),
Text("stats not available yet"),
Text("stats not available yet"),
Text("stats not available yet"),
Text("stats not available yet"),
Text("stats not available yet"),
Text("stats not available yet"),
Text("stats not available yet"),
Text("stats not available yet"),
Text("stats not available yet"),
],
),
const Text("abcd"),
const Text("abcd"),
const Text("abcd"),
const Text("abcd"),
const Text("abcd"),
const Text("abcd"),
const Text("abcd"),
const Text("abcd"),
const Text("abcd"),
],
),
),
],
),
),
),
),
],
),
),
),
);
}
}
I tried getting it work with NestedScrollView
, ListView
, have ScrollPhysics
on the parent SingleChildScrollView
and NeverScrollableScrollPhysics
on the TabBarView
component, but didn't get it to work.
CodePudding user response:
Use Layout Builder as a parent of SingleChildScrollView like this and remove fixed height of Container. Follow the docs
https://api.flutter.dev/flutter/widgets/SingleChildScrollView-class.html
CodePudding user response:
You can use this simple structure as a reference. In detail, I'm using both TabBar
and TabBarView
within a NestedScrollView
which is able to take the full height. In this way, you can achieve dynamic height with TabBarView
.
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: MyHomePage()));
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
late TabController tabController;
@override
void initState() {
super.initState();
tabController = TabController(length: 2, vsync: this);
}
@override
void dispose() {
tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: NestedScrollView(
headerSliverBuilder: (context, value) {
return [
SliverToBoxAdapter(
child: TabBar(
controller: tabController,
labelColor: Colors.redAccent,
isScrollable: true,
tabs: [
Tab(
child: Text(
"Tab 1",
style: TextStyle(color: Colors.black),
),
),
Tab(
child: Text(
"Tab 1",
style: TextStyle(color: Colors.black),
),
),
],
),
),
];
},
body: Container(
child: TabBarView(
controller: tabController,
children: [
/// Each content from each tab will have a dynamic height
Container(),
Container()
],
),
),
),
);
}
}