How can i use TabBar inside SingleChildscrollView - flutter

Currently i have this structure SingleChildScrollView -> Column, my TabBar is inside the column
Here is my script
SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TabBar(
controller: _tabController,
labelColor: Colors.black,
unselectedLabelColor: Colors.black,
indicatorColor: CustomColors.mainRed,
tabs: [
Tab(text: 'Deskripsi Produk'),
Tab(text: 'Daftar isi'),
],
),
TabBarView(
controller: _tabController,
children: <Widget>[
Html(
data: widget.product.description!,
style: {
// tables will have the below background color
"p": Style(padding: EdgeInsets.all(2.w)),
},
),
GetBuilder<ProductDetailController>(
init: ProductDetailController(),
builder: (data) => ListView.builder(
shrinkWrap: true,
controller: scrollController,
padding: EdgeInsets.all(5.w),
physics: NeverScrollableScrollPhysics(),
itemCount: data.videos.length,
itemBuilder: (context, index) {
return ListTile(
dense: true,
leading: Icon(
Icons.check,
color: CustomColors.mainRed,
size: 12.sp,
),
title: Text(
data.videos[index].video!.title!.toString(),
style: TextStyle(
fontSize: 12.sp,
),
),
);
},
),
),
],
),
],
),
),
I got this error
══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
The following assertion was thrown during performResize():
Horizontal viewport was given unbounded height.
Viewports expand in the cross axis to fill their container and constrain their children to match
their extent in the cross axis. In this case, a horizontal viewport was given an unlimited amount of
vertical space in which to expand.
I don't set the height because, my tab 1 and my tab 2 will have dynamic content (so, the height cannot fixed) and below the tabbar i want to add another content too. How can i solve this ?

Try this, and remember to use a TabController and a PageController.
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children:[
DefaultTabController(
length: 2,
initialIndex: 0,
child: Column(
children: [
TabBar(
controller: _tabController,
labelColor: Colors.black,
unselectedLabelColor: Colors.black,
indicatorColor: CustomColors.mainRed,
tabs: [
Tab(text: 'Deskripsi Produk'),
Tab(text: 'Daftar isi'),
],
),
ExpandablePageView(
onScoll: (index) {
controller.animateTo(index);
},
controller: _pageController,
children: [
Html(
data: widget.product.description!,
style: {
// tables will have the below background color
"p": Style(padding: EdgeInsets.all(2.w)),
},
),
GetBuilder<ProductDetailController>(
init: ProductDetailController(),
builder: (data) => ListView.builder(
shrinkWrap: true,
controller: scrollController,
padding: EdgeInsets.all(5.w),
physics: NeverScrollableScrollPhysics(),
itemCount: data.videos.length,
itemBuilder: (context, index) {
return ListTile(
dense: true,
leading: Icon(
Icons.check,
color: CustomColors.mainRed,
size: 12.sp,
),
title: Text(
data.videos[index].video!.title!.toString(),
style: TextStyle(
fontSize: 12.sp,
),
),
);
},
),
),
],
),
],
),
),
],
);

Related

CLOSED: NestedScrollView briefly stutters before properly scrolling

So basically I am using a NestedScrollView which has a TabBarView as its body. My setup works pretty much as desired however there is a stutter while scrolling. When the TabBar reaches the top of the page/touches the bottom of the SliverAppBar while scrolling, there is a brief pause in scrolling before scrolling is resumed as normal. This pause also happens when we scroll back down.
Here is the error:
I cannot seem to figure out how to fix this pause. It is brief yet annoyingly noticeable. How could I fix this?
Thank you!
You can use only one CustomScrollView in this case. and For inner scrollable physics: NeverScrollableScrollPhysics(),
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: [
const SliverAppBar(
pinned: true,
title: Text('AppBar'),
collapsedHeight: 100,
backgroundColor: Colors.blue,
),
SliverToBoxAdapter(
child: Container(
alignment: Alignment.center,
height: 100,
color: Colors.redAccent,
child: const Text('Container'),
),
),
SliverPinnedHeader(
child: Container(
color: Colors.white,
child: TabBar(
controller: _tabController,
tabs: const [
Tab(icon: Icon(Icons.shopping_cart, color: Colors.black)),
Tab(icon: Icon(Icons.bookmark, color: Colors.black)),
],
),
),
),
SliverFillRemaining(
child: TabBarView(
// physics: NeverScrollableScrollPhysics(),
controller: _tabController,
children: [
ListView.builder(
itemCount: 44,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return ListTile(
tileColor: Colors.pinkAccent,
title: Text('index $index'),
);
},
),
ListView.builder(
itemCount: 44,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return ListTile(
tileColor: Colors.pinkAccent,
title: Text('index $index'),
);
},
),
],
)),
],
));
}

controller for SingleChildScrollView

I have a SingleChildScrollView and I want to use ScrollController for it. because I want to when the scroll, Reached the top of the page, physics become NeverScrollView .
I want to scroll my list and when I reached the top of the page, can scroll all pages.
and by the way, I use the tab bar for it.
:
Container(
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.grey, width: 0.3))),
child: TabBar(
indicatorColor: Colors.transparent,
labelColor: Colors.red,
unselectedLabelColor: Colors.black,
tabs: <Widget>[
Tab(
text: "list1",
),
Tab(
text: "list2",
),
Tab(
text: "list",
),
]),
);
here is body :
Container(
height: 2 * pageWidth,
width: pageWidth,
child: TabBarView(
physics: NeverScrollableScrollPhysics(),
children: <Widget>[
SingleChildScrollView(
child: Html(
shrinkWrap: true,
data: resultEp!['Description'],
),
),
SingleChildScrollView(
controller: scrollBarController,
child: ShowCommentEpisodes(
podId: resultEp!['podcast']['Pod_ID'].toString(),
epId: resultEp!['Ep_ID'].toString(),
),
),
SingleChildScrollView(
child: QueuePlaying(
podId: resultEp!['podcast']['Pod_ID'].toString(),
),
),
],
),
),
TabBarView can scroll and when reached the top, all screens can scroll.

Working with partial tabview and soft keyboard in to edit text in flutter

I have a screen where the bottom half of the content is wrapped in a TabBarView while the top half remains constant. I want to be able to edit text in the bottom half, but the soft keyboard doesn't resize the entire page - it only attempts to eat into the TabBarView's space
My code looks like this:
return DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
'Edit Profile',
),
),
//major column
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
SizedBox(height: 20),
UserInfo()
TabBar(
labelPadding: EdgeInsets.zero,
labelColor: Colors.black,
tabs: [
Tab(text: 'INFO'),
Tab(text: 'BIO'),
Tab(text: 'ACCOUNT'),
],
),
Expanded(
//All tab view content
child: TabBarView(
children: [
Info(),
Bio(),
Account(),
],
),
),
),
);
I think you can wrap it inside a SingleChildScrollView:
SingleChildScrollView(
child:
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
SizedBox(height: 20),
UserInfo()
TabBar(
labelPadding: EdgeInsets.zero,
labelColor: Colors.black,
tabs: [
Tab(text: 'INFO'),
Tab(text: 'BIO'),
Tab(text: 'ACCOUNT'),
],
),
Expanded(
//All tab view content
child: TabBarView(
children: [
Info(),
Bio(),
Account(),
],
),
),
)
Or You can wrap the UserInfo() inside an Expanded:
Expanded(
child: UserInfo()
),

Pin Row to bottom of Scroll View on top of other UI widgets

I'm trying to pin a Row container that has a text field input and an adjacent icon button within a ScrollView. Unfortunately, the Row will stay at the bottom but not with the view of the screen so the user will have to scroll down to see the Row container. How can I pin the bottom bar to the screen so that it is always at the bottom within the view of the screen and over the top of the other objects in the ScrollView?
Bar UI:
class TextBarAtBottom extends StatelessWidget {
TextEditingController commentController = TextEditingController();
#override
Widget build(BuildContext context) {
return Row(children: [
// First child is TextInput
Expanded(
child: Container(
child: TextFormField(
autocorrect: false,
decoration: new InputDecoration(
labelText: "Some Text",
labelStyle: TextStyle(fontSize: 16.0, color: Colors.black),
fillColor: Colors.black,
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black)),
),
),
)),
// Second child is button
IconButton(
icon: Icon(Icons.send),
iconSize: 16.0,
onPressed: () {},
)
]);
}
}
Screen UI:
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('App'),
),
body: SingleChildScrollView(
child: Column(mainAxisSize: MainAxisSize.min, children: [
Flexible(
fit: FlexFit.loose,
child: ExpandableTheme(
data: ExpandableThemeData(
iconColor: Colors.blue,
useInkWell: true,
animationDuration: const Duration(milliseconds: 500),
tapBodyToExpand: true,
tapHeaderToExpand: true,
tapBodyToCollapse: true,
hasIcon: true,
iconPlacement: ExpandablePanelIconPlacement.right),
child: ExpandablePanel(
header: Text(widget.postData.title,
style: TextStyle(fontSize: 24)),
collapsed: Text(widget.postData.text,
style: TextStyle(fontSize: 16),
softWrap: true,
maxLines: 10,
overflow: TextOverflow.ellipsis),
expanded: Text(widget.postData.text,
style: TextStyle(fontSize: 16),
softWrap: true)))),
// Second child is spacing
SizedBox(height: 16),
// Third child is list view of Cards that are populated from the request post
Flexible(
fit: FlexFit.loose,
child: Container(
child: FutureBuilder<Map<String, String>>(
future: post,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data.length,
itemExtent: 128.0,
itemBuilder: (BuildContext context, int index) {
return Card(Text('$index'));
});
} else if (snapshot.hasError) {
return Flex(direction: Axis.horizontal, children: [
Expanded(
child: new Container(),
)
]);
}
return CircularProgressIndicator();
},
),
)),
// Fourth child is text bar and send button
Flexible(fit: FlexFit.loose, child: TextBarAtBottom())
]))));
}
Check my code, it's having textfield at the bottom, and scrollview in the center.
Problem with your code is you are adding Textfield inside scrollview so always at the end of SingleChildScrollview.
Solution:
Add your SingleChildScrollView inside column view with Expanded widget. and add your Textfield as the second child to Column widget.
Now TextField will be at the bottom and the rest of the space will be taken by SingleChildScrollView.
import 'package:flutter/material.dart';
class Design extends StatefulWidget {
#override
_DesignState createState() => _DesignState();
}
class _DesignState extends State<Design> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('TextField at Bottom'),
),
body: Column(
children: <Widget>[
Expanded(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
Text('Flutter'),
],
),
),
),
Row(children: [
// First child is TextInput
Expanded(
child: Container(
child: TextFormField(
autocorrect: false,
decoration: new InputDecoration(
labelText: "Some Text",
labelStyle: TextStyle(fontSize: 16.0, color: Colors.black),
fillColor: Colors.black,
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black)),
),
),
)),
// Second child is button
IconButton(
icon: Icon(Icons.send),
iconSize: 16.0,
onPressed: () {},
)
])
],
),
);
}
}
The results in the screenshot look like this.
1. image at the top of the list
2. image at the bottom of the list
I modified your own code, like this below
MaterialApp(
title: 'App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Document Thread'),
),
body: Column(
children: <Widget>[
Expanded(
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// First child is ExpandableTheme with minHeight of 0.5 screen but expandable to fill up as much screen as needed
Flexible(
fit: FlexFit.loose,
child: ExpandableTheme(
data: ExpandableThemeData(
iconColor: Colors.blue,
useInkWell: true,
animationDuration: const Duration(milliseconds: 500),
tapBodyToExpand: true,
tapHeaderToExpand: true,
tapBodyToCollapse: true,
hasIcon: true,
iconPlacement: ExpandablePanelIconPlacement.right
),
child: ExpandablePanel(
header: Text('Title',
style: TextStyle(fontSize: 24)),
collapsed: Text('Some text',
style: TextStyle(fontSize: 16),
softWrap: true,
maxLines: 10,
overflow: TextOverflow.ellipsis),
expanded: Text('widget.postData.docAbstract',
style: TextStyle(fontSize: 16),
softWrap: true)
)
),
),
// Second child is spacing
SizedBox(height: 16),
// Third child is max height of 0.5 screen with ListView of Card objects or Empty container
Flexible(
fit: FlexFit.loose,
child: Container(
//this is limiting your list not to scroll to the bottom
// constraints: BoxConstraints(
// minWidth: MediaQuery.of(context).size.width,
// maxHeight: MediaQuery.of(context).size.height / 2,
// ),
child: ListView.builder(
shrinkWrap: true,
itemCount: 15,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.fromLTRB(90,0,0,10),
child: Text('Text $index'),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
IconButton(
icon: Icon(Icons.thumb_up, color: Colors.green,),
onPressed: (){},
),
IconButton(
icon: Icon(Icons.thumb_down, color: Colors.red,),
onPressed: (){},
)
],
),
Divider(color: Colors.black12,)
],
);
},
),
),
),
// Fourth child is text bar and send button
]
)
),
),
TextBarAtBottom()
],
)
)
);

How to put Expandable list view inside scroll view in flutter?

Hello there i am making a flutter application in which inside ScrollView in need to put Expandable list view.First of all here is my build method.
return Scaffold(
appBar: AppBar(
backgroundColor: app_color,
iconTheme: IconThemeData(
color: Colors.white, //change your color here
)),
//debugShowCheckedModeBanner: false,
//key: scaffoldKey,
backgroundColor: app_color,
body: SingleChildScrollView(
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children:<Widget>[
Text("Header"),
new ListView.builder(
itemCount: datas.length,
shrinkWrap: true,
itemBuilder: (context, i) {
return new ExpansionTile(
title: new Text(datas[i].title, style: new TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold, fontStyle: FontStyle.italic),),
children: <Widget>[
new Column(
children: _buildExpandableContent(datas[i]),
),
],
);
},
),
Text("Footer"),
],
),
)
)
);
}
Now the problem is that without SingleScrollChidView this works fine But after using SingleScrollChidView it does not shows anything and gives error RenderBox was not laid out.What is wrong here ? How can i use Expandable list view inside Singlechildscroll view in flutter.
I was able to achieve Expanded ListView within ScrollView with text by
- Use of Wrap inside SingleChildScrollView, provided you make all ListView using shrinkWrap: true
SingleChildScrollView(
child: Wrap(
direction: Axis.horizontal,
children: <Widget>[
_textBody, // text body, with 1000+ words
Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
children: <Widget>[
ListViewOne(_genericListDataOne()),
],
),
),
Column(
children: <Widget>[
ListViewTwo(_genericListDataTwo())
],
)
],
),
),
part of the Code for ListViewOne
ListViewOne(
shrinkWrap: true,
padding: new EdgeInsets.symmetric(vertical: 8.0),
children: // build list here,
);
Give your ListView a fixed height using SizedBox or similar
SingleChildScrollView(
child: Column(
children: <Widget>[
Text("Header"),// tested with 20 of these for scrolling
SizedBox(
height: MediaQuery.of(context).size.height / 2,
child: new ListView.builder(
itemCount: 20,
shrinkWrap: true,
itemBuilder: (context, i) {
return new ExpansionTile(/* whatever */ );
},
),
),
Text("Footer"),// tested with 20 of these for scrolling
],
),
)
Use SizedBox.expand for this problem,
SizedBox.expand(
child : ListView.builder(
itemCount: datas.length,
shrinkWrap: true,
itemBuilder: (context, i) {
return new ExpansionTile(
title: new Text(datas[i].title, style: new TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold, fontStyle: FontStyle.italic),),
children: <Widget>[
new Column(
children: _buildExpandableContent(datas[i]),
),
],
);
},
),
);
Edited answer
Try this, you should get the desired output you are looking for.
You can find the output here.
Column(
children: <Widget>[
Text(),
ListView(
shrinkWrap: true,
physics: ScrollPhysics(),
children:[]),
Text()
]
)
adding below shown code in ListView will allow smooth scrolling of widget
shrinkWrap: true,
physics: ScrollPhysics(),