Adding item to widget dynamically doesn't update widget's height - flutter

When I add a widget to a sliding_up_panel widget dynamically after the initial load, the panel's height does not increase, meaning that the bottom of the panel gets cut off and I get the A RenderFlex overflowed by 27 pixels on the bottom. error.
What can I do to ensure the panel updates its height in this case please?
To Reproduce
Add a widget to the panel dynamically via the condition ? widget : widget logic. For example:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("SlidingUpPanelExample"),
),
body: Stack(
children: <Widget>[
Center(child: Text("This is the Widget behind the sliding panel"),),
SlidingUpPanel(
panel: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
myFirstVariable ? Text("This is a sliding Widget") : Container(),
mySecondVariable ? Text("This is another sliding Widget") : Container(),
],
),
)
)
],
)
);
}
Thanks so much!

the SlidingUpPanel widget doesn't adjust its height according to its children.
A solution to your problem would be add a SingleChildScrollView to your panel content and use the panelBuilder instead of the panel property.
The panelBuilder takes the burden of managing scrolling and sliding conflicts by providing you a controller that you can feed to your SingleChildScrollView, your code will change to be like the following :
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("SlidingUpPanelExample"),
),
body: Stack(
children: <Widget>[
Center(child: Text("This is the Widget behind the sliding panel"),),
SlidingUpPanel(
panelBuilder:(sc) => SingleChildScrollView(
controller: sc,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
myFirstVariable ? Text("This is a sliding Widget") : Container(),
mySecondVariable ? Text("This is another sliding Widget") : Container(),
],
),
)
)
],
)
);
}
Like this, you won't have any overflow issues, and when the content of the panel overflows the SingleChildScrollView will become scrollable.

hope this helps:
use a controller,
You can control the height of the panel depending on the items on the list (0.0 to 1.0). Ensure to update the UI once you add a new item.
use a List
This will solve the renderOverflow you mentioned
/// just for the example
List<Widget> items = <Widget>[];
//adding items
addItem() {
items.add(Container(
constraints: BoxConstraints(maxHeight: 200, minHeight: 200),
color: Color((Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0),
));
/// if you know in advance the height of the widgets been rendered: 200
/// if you know in advance the height of the panel: 500, or context.size.height / 2 (which would be 50% of screen) asume 600
///
/// increase panel height panel according to the number of items
///
_pc.panelPosition =
(items.length * 200) / 600 > 1.0 ? 1 : (items.length * 200) / 600;
/// Hey
/// SET State after adding the item
/// to refresh UI
}
Widget _scrollingList(ScrollController sc) {
return ListView.builder(
controller: sc,
itemCount: items.length,
itemBuilder: (context, index) {
return items[index];
},
);
}
PanelController _pc = new PanelController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("SlidingUpPanelExample"),
),
floatingActionButton: FloatingActionButton(
onPressed: addItem,
),
body: Stack(
children: <Widget>[
Center(
child: Text("This is the Widget behind the sliding panel"),
),
SlidingUpPanel(
controller: _pc,
panelBuilder: (ScrollController sc) => _scrollingList(sc),
),
],
));

Plugin has the methods: minHeight and maxHeight to do the work. I think is not posible change it dynamically without set that attributes.

Related

Adding DraggableScrollableSheet to the bottom of a Sliver page

I’m working on the concept that you can see on the screenshot below:
design concept
Note: the arrows are not the part of the UI, but were added to demonstrate the draggable functionality.
The screen has a SliverAppBar that displays location title, Sliver body that contains location description, and has a DraggableScrollableSheet (or a similar alternative).
When the location description is scrolled up, the title collapses.
When the DraggableScrollableSheet is scrolled up it expands to the full height of the screen.
I tried many times to put it together, but something is always off.
My last attempt was to add DraggableScrollableSheet as a ‘bottom sheet:’ in Scaffold. Since I have a BottomAppBar, it breaks the UI, and looks the following way:
current UI behavior
Scaffold
#override
Widget build(BuildContext context) {
return Scaffold(
body: body,
extendBody: true,
appBar: appBar,
bottomSheet: hasBottomSheet
? DraggableScrollableSheet(
builder:
(BuildContext context, ScrollController scrollController) {
return Container(
color: Colors.blue[100],
child: ListView.builder(
controller: scrollController,
itemCount: 25,
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text('Item $index'));
},
),
);
},
)
: null,
backgroundColor: Colors.white,
floatingActionButtonLocation: fab_position,
floatingActionButton: hasActionButton ? ScannerFAB() : null,
bottomNavigationBar: AppBarsNav(hasNavButtons: hasNavButtons));
}
Scaffold body
class LocationPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ScaffoldWithNav(
hasBottomSheet: true,
body: CustomScrollView(
slivers: <Widget>[
SliverBar(
title: "Location",
hasBackground: true,
backgroundImagePath: 'assets/testImage.jpg'),
SliverToBoxAdapter(
child: Text("very long text "),
),
SliverPadding(
padding: EdgeInsets.only(bottom: 70),
),
],
),
);
}
}
BottomAppBar FAB
class ScannerFAB extends StatelessWidget {
#override
Widget build(BuildContext context) {
return FloatingActionButton(
child: WebsafeSvg.asset('assets/qr-code.svg',
color: Colors.white, height: 24, width: 24),
);
}
}
The FAB jumps, the content is hidden.
When I set a fixed-sized container, the content comes back, but the FAB is still living its own life:)
current UI behavior2
If anyone has any idea how to solve this issue/those issues please share, I’ll be very grateful!
You can try to add another Scaffold on current body and put the DraggableScrollableSheet inside it. Then the DraggableScrollableSheet won't affect the FAB outside.
#override
Widget build(BuildContext context) {
return Scaffold(
body: Scaffold(
body: body,
bottomSheet: ... // move DraggableScrollableSheet to here
),
...
floatingActionButton: ... // keep FAB here
...
)
You can use Stack into Body, for example:
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children. [
SingleChildScrollView(),
DraggableScrollableSheet(),
]
),
...
floatingActionButton: ... // keep FAB here
...
)

Expand Widget to fill remaining space in ListView

As in the image shown above, I want widget 2 to always be at least the height of the remaining space available.
But widget 2 might contain so many ListTiles so that they can not be displayed without scrolling. But scrolling should affect widget 1 and widget 2. What is the best way to implement something like this?
Wrap Widget 2 in an Expanded Widget.
To scroll both Widget 1 and Widget 2, wrap both of them in a SingleChildScrollView Widget.
If you can distinguish between the case with a few and many elements (for example during loading), you can use CustomScrollView with SliverFillRemaining for this:
var _isLoading = true;
#override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
_buildWidget1(),
_buildWidget2(),
],
);
}
Widget _buildWidget1() {
return SliverToBoxAdapter(
child: Container(height: 400, color: Colors.blue),
);
}
Widget _buildWidget2() {
if(_isLoading) {
return SliverFillRemaining(
hasScrollBody: false,
child: Center(child: const CircularProgressIndicator()),
);
} else {
return SliverFixedExtentList(
delegate: SliverChildBuilderDelegate(
_buildItem,
childCount: childCount,
),
itemExtent: 56,
);
}
}
A simple way to do that would be to place your widgets in Column and wrap it with a single child scroll view. For the ListView use shrinkWrap as true and physics you can set to NeverScrollableScrollPhysics
Here is an example
SingleChildScrollView(
child: Column(
children: [
Container(
height: MediaQuery.of(context).size.height / 2,
color: Colors.red,
),
ListView.builder(
shrinkWrap:true,
physics:NeverScrollableScrollPhysics(),
itemCount: 100,
itemBuilder: (context, index) => Text("$index"),
),
],
),
);
Hope this helps!
var widgetHeight = MediaQuery.of(context).size.height - fixedSize;
return SingleChildScrollView(
child: Container(
height: widgetHeight,
child: Widget2
)
)

Flutter - How to get width of a FlatButton in a horizontal ListView

I want to get the width of a FlatButton in an horizontal ListView but i only can get Width: Infinity.
I can get width in an isolated FlatButton succesfully, but when the FlatButton is inside of a ListView i cannot, but i don't know why. Could you help me to get the width of a FlatButton when it is inside a ListView?
Thanks.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter App'),
),
body: Container(
height: 70.0,
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
_flatButtonStoreWidth(),
_flatButtonStoreWidth(),
_flatButtonStoreWidth(),
_flatButtonStoreWidth(),
_flatButtonStoreWidth(),
],
),
),
);
}
Widget _flatButtonStoreWidth (){
return FlatButton (
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
double _width = constraints.maxWidth;
print('Width: $_width');
return Text('This is a FlatButton');
},
),
onPressed: (){},
);
}
To get width of the object in ListView you are supposed to:
Give widget a GlobalKey.
When build is complete, access the context through the GlobalKey.
Using context you can get size by context.size.
You can get width from Size object.
Following is the working code for your reference:
Widget _flatButtonStoreWidth() {
GlobalKey globalKey = GlobalKey();
WidgetsBinding.instance.addPostFrameCallback((_) {
double _width = globalKey.currentContext.size.width;
print('Width: $_width');
});
return FlatButton(
key: globalKey,
child: Text('This is a FlatButton'),
onPressed: () {},
);
}
I hope this helps, in case of any doubt please comment. In case this this answer helps you please accept and up-vote it.
That's because the ListView with a horizontal axis has an infinite width. You'll have to provide a width for each FlatButton.
FlatButton gets its size from the parent. In this case the parent provides an infinite width. Therefore you should size the button yourself

How to Center SingleChildScrollView but make background stretch to fill screen?

I am use Flutter for web for make website. I want make webpage scroll when user scroll down like normal website.
I am try use Stack so I can place custom background behind widgets. This background must scroll when user scroll (must stick to widgets in front so background change).
(I cannot set background color using Scaffold because my background is use CustomPainter)
But I want center the widgets on webpage, so I wrap SingleChildScrollView in Center widget. But now on large horizontal screen the CustomPaintWidget() is not fill screen (there is blank space). I have try replace my CustomPaintWidget() with Container to test, but same issue.
Here my code:
Center(
child: SingleChildScrollView(
child:Stack(children: <Widget>[
CustomPaintWidget(),
Widgets(),
],),
Anyone know solution?
How to center widgets but also make background stretch?
Thanks!
SingleChildScrollView by definition shriknwraps it's child.
What you should try is
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: ConstrainedBox(
//Use MediaQuery.of(context).size.height for max Height
constraints: BoxConstraints(minHeight: MediaQuery.of(context).size.height),
child: Center(
child: //Widget,
),
),
);
I think you can try something like:
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
CustomPaintWidget(),
Center(
child: SingleChildScrollView(
child: Widgets(),
),
)
],
));
}
read that post, I think is all you need https://medium.com/#swav.kulinski/spike-parallax-in-flutter-seven-lines-of-code-16a1890d8d32
I know it is too late to answer but s.o may need it in future
You have to use Stack
for instance:
your MainClass:
class _BodyState extends State<Body> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
ScrollViewClass(),
Column(
children: [
//YOUR ITEMS
]),
);
ScrollviewClass:
class ScrollViewClass extends StatefulWidget {
#override
_ScrollViewClassState createState() => _ScrollViewClassState();
}
class _ScrollViewClassState extends State<ScrollViewClass> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
margin: EdgeInsets.only(top: 260, bottom: 100),
child: ListView(
children: [
Container(
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: ConstrainedBox(
//Use MediaQuery.of(context).size.height for max Height
constraints: BoxConstraints(
minHeight: MediaQuery.of(context).size.height),
child: Column(
children: [
//ADD YOUR ITEMS LIKE IMAGE, TEXT, CARD ETC...
Center(child: Image.asset('assets/app_name.png')),
Center(child: Image.asset('assets/app_name.png')),
Center(child: Image.asset('assets/app_name.png')),
Center(child: Image.asset('assets/app_name.png')),
Center(child: Text('fdgdfg')),
Center(child: Text('fdgdfg')),
],
)),
),
)
],
),
));
}
}
I know this is not the OP's scenario, but for others - If there is something above your scroll view, using the full height of the page will cause the scrollview to scroll prematurely, because the combined height of the widgets is now greater than the page height. Use LayoutBuilder instead of MediaQuery.of(context).size.height.
LayoutBuilder(builder: ((context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraints.maxHeight),
child: Center(child: child)),
);
})

Adding both vertical and horizontal scrolling to ListView

How can I make the Rows inside a vertical ListView, scrollable horizontally.
This is what my app looks like:
I want the user to be able to scroll the ListView both horizontally (to see the contents of the Row) and vertically to see new list items. This behavior is like how you would scroll a DataTable in Flutter:
Here is the build method (based on the Flutter project template):
#override
Widget build(BuildContext context) {
final List<String> rows = [
"This is a row with some very long text ... That goes on and on",
"This class is the configuration for the state.",
"case the title) provided by the parent (in this case the App widget) and",
"always marked \"final\"."
];
return Scaffold(
appBar: AppBar(title: Text("ListView")),
body: ListView(
padding: EdgeInsets.all(10),
children: <Widget>[
for (final String row in rows)
Row(
children: <Widget>[Text(row)],
)
],
),
);
}
Update: Wrapping the Text in Expanded doesn't work as it causes the text to wrap onto multiple lines. I want the text to remain on a single line.
Finally
After a deep search found this finally
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: new SizedBox(
width: 1000.0,
child: new ListView.builder(
itemBuilder: (BuildContext context, int i) {
return new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: new List.generate(5, (int j) {
return new Text("$i,$j");
}),
);
},
),
),
),
);
}
Original source Vote up his answer too