Positioned widgets must be placed directly inside Stack widgets - flutter

I am trying to implement gridview with image and a text inside it. where i want text at the bottom of image with black background. Here is my code for ListItem
class ListItem extends StatelessWidget {
String url;
String name;
ListItem(this.url, this.name);
#override
Widget build(BuildContext context) {
return new Container(
child: new Column(
children: <Widget>[
new Image.network('${url}', fit: BoxFit.cover),
new Positioned(
child: new Container(
child: new Text('${name}',
style: new TextStyle(fontSize: 20.0, color: Colors.white)),
decoration: new BoxDecoration(color: Colors.black),
padding: new EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 16.0)),
left: 0.0,
bottom: 108.0,
)
],
));
}
}
With this code it is showing error
Positioned widgets must be placed directly inside Stack widgets.
Positioned(no depth, dirty) has a Stack ancestor, but there are other widgets between them:
- Column(direction: vertical, mainAxisAlignment: start, crossAxisAlignment: center)

Issue was with Column, after changing few lines from here and there i finally found that it was because of Column
Once i change Column to Stack, it works fine.
return new Container(
child: new Stack(

We were just discussing this yesterday. Positioned can actually be used in more than just a Stack, so the docs aren't exactly right about that. It can't be used in anything that renders, and the docs are very specific about RenderObjectWidget:
"A Positioned widget must be a descendant of a Stack, and the path from the Positioned widget to its enclosing Stack must contain only StatelessWidgets or StatefulWidgets (not other kinds of widgets, like RenderObjectWidgets).
Source: https://docs.flutter.io/flutter/widgets/Positioned-class.html
Column is descended from RenderObjectWidget:
... Widget > RenderObjectWidget > MultiChildRenderObjectWidget > Flex > Column
Most people starting out in Flutter are only aware of StatelessWidget and StatefulWidget, but there are others and knowing them can be very important at times.
Widget:
StatefulWidget
StatelessWidget
RenderObjectWidget
ProxyWidget
PreferredSizeWidget
More at:
https://docs.flutter.io/flutter/widgets/Widget-class.html

Related

How to fix a widget to the right side of a ListView on Flutter Web

I have a Flutter Web application where I need to show a widget on the right side of a ListView when I click an item and this widget should always be visible on screen. I can achieve my objective puting both on a Row and using a scrollable only for the ListView, but that requires the ListView to be wrapped by a widget with defined height.
Defining a container with height to wrap the ListView breaks the responsiveness when I resize the browser, as the container doesn't fit the height of the screen.
I thought of using the shrinkWrap property of the ListView so I don't have to wrap it in a widget with predefined height, but that makes the whole Row scrollable vertically, eventually causing the widget to leave the viewport.
I would appreciate if somebody knows how could I keep this right side widget fixed on screen so I can achieve my objective without losing responsiveness.
Here's something similitar to what I've got so far:
class PageLayout extends StatefulWidget {
const PageLayout({Key? key, required this.items}) : super(key: key);
final List<String> items;
#override
State<PageLayout> createState() => _PageLayoutState();
}
class _PageLayoutState extends State<PageLayout> {
final rightSideWidget = Container(
decoration: BoxDecoration(
color: Colors.red,
border: Border.all(color: Colors.white, width: 2),
),
height: 200);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.49,
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (context, index) => Container(
decoration: BoxDecoration(
color: Colors.blue,
border: Border.all(color: Colors.white, width: 2),
),
height: 200,
child: Center(
child: Text(
widget.items[index],
style: const TextStyle(color: Colors.white),
),
),
),
itemCount: widget.items.length,
),
),
Expanded(child: rightSideWidget),
],
),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
I want rightSideWidget to be always centered on screen or follow the scroll.
You can divide your screen into two sections, right section and left section; thereby being able to control behaviour of widgets in both sections.
Divide the overall screen into 2 proportional sections using a Row
widget
Put this Row widget inside a Container with height equal to screen height for preserving responsiveness | Use MediaQuery to get current height of page
Now left hand section can individually scroll, and on click of any option from this section you can define behaviour for right section; while keeping the left section constant throughout page lifecycle

How to expand all children of a Stack that includes a CustomPainter in Flutter

Let's say in Flutter we have a Stack that contains:
A CustomPainter with size of Size.infinite
Any other widget that is not a Custom Painter (that we also want to fill all available space exactly the same way that the custom painter does)
In this example, I'm using an Icon for item 2:
#override
Widget build(BuildContext context) {
return Expanded(
child: Container(
color: Colors.white,
child: Stack(
children: [
Icon(Icons.star),
CustomPaint(
painter: MyCustomPainter(percentTimeElapsed: 0.5),
size: Size.infinite)
],
),
),
);
}
Now, obviously, we don't get the desired result yet -- the custom painter is "expanded" but the icon is not.
But I have tried all the following with no luck:
Wrapping the Icon with Expanded (causes exception)
Wrapping the Stack widget with Expanded (causes exception)
Defining the size of the Icon to be Size.infinite (will not build because size param expects a double)
Using fit: StackFit.expand as a parameter for the Stack, but this just seems to center the Icon and doesn't change it's size.

Multiple columns in container

I am learning Flutter, I want to achieve this look:
Does Container only allow one child? I want to have multiple of columns, like on the picture I will need 3 for logo, text box and for two buttons. How do I set this up properly? Maybe I should not use container?
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
Text("test"),
Text("test")
]
)
Also, what does this code do?
const MyApp({Key? key}) : super(key: key); I haven't seen that in any of the tutorials. is that some sort of constructor?
For the top logo part, you can simply use appBar of Scaffold.
Next comes the large box TextBox, you can use Expanded with Align widget inside column for this.
While we used Expanded it will take available height.
Therefore next two button will be at the bottom side.
I will suggest visiting and learn more about widgets, there are many ways you can handle this UI. You can search and read about every widget.
class TX extends StatelessWidget {
const TX({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: Text("logo"),
),
body: LayoutBuilder(
builder: (context, constraints) => Column(
children: [
Expanded(
child: Container(
color: Colors.cyanAccent,
child: const Align(
alignment: Alignment(0, .5),
child: Text("TextBox"),
),
),
),
SizedBox(
width: constraints.maxWidth,
child: ElevatedButton(
onPressed: () {},
child: Text("Button"),
),
),
SizedBox(
height: 10,
),
SizedBox(
width: constraints.maxWidth,
child: ElevatedButton(
onPressed: () {},
child: Text("Buttonx"),
),
),
],
),
),
);
}
}
And for the key constructor already describe on comments by #Midhun MP. It is used to identify the widget tree. Check this video
Does Container only allow one child?
Yes, Container() can only have one child widget.
Widgets are like lego blocks. You have to pick a widget that best suits your requirements. For Showing widgets in a single column, You can use Column() Widget. Similarly in case of row, You can represent widgets in single Row using Row() Widget. Similarly for stacking of widgets, use Stack() widget. This list goes on just like the availablility of lego blocks.
Now back to your implementation, you are going the right way. You don't need Container() at the top, Just add 4 child widgets in Column.
Column(
children: [
Image(),
TextField(),
TextButton(),
TextButton(),
],
)
Study about the available customization options of these widgets and you will be able to implement this UI as per your requirements.
P.S. There are many type of buttons available in flutter. If TextButton() doesn't work for you, you can pick any other button.

Flutter baseline text alignment with Wrap class

Using the Row class, I can make the text baseline aligned with this property:
crossAxisAlignment: CrossAxisAlignment.baseline,
But this property seems not to be available on the Wrap class.
The benefit of using Wrap instead of Row is that it allows having multiline text. While the Row class force the content to stay into one line.
How can I keep the benefit of Wrap, while making the text baseline aligned?
I also had this problem. There is an open issue in the Flutter Repo addressing this. While the built-in solution is not implemented yet, I did come up with a slightly-hacky workaround.
Basically, depending on your font and your needs...
Set your Wrap() to have crossAxisAlignment: WrapCrossAlignment.end,. Then you can make one of the children of your Wrap() a Column() that has a SizedBox() as the lowest child, with the height that you need to make it appear like your texts are using the does-not-exist WrapCrossAlignment.baseLine
Example of the problem:
Example of the solution as outlined above (I did point out that it's kind of hacky):
The Code:
class WrapBaselineHackWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return DecoratedBox(
decoration: BoxDecoration(border: Border.all(color: Colors.red)),
child: Wrap(
crossAxisAlignment: WrapCrossAlignment.end,
spacing: 8,
children: [
Text(
'\$50,000.00',
style: TextStyle(fontSize: 24),
),
Column(
children: [
Text('Is a lot of money'),
//this is needed because Wrap does not have WrapCrossAlignment.baseLine
const SizedBox(height: 3),
],
),
],
),
);
}
}
Keep using Row and simply wrap Text widget with Expanded or Flexible widget.

Flutter two widgets in body?

So my flutter app works fine, however I want to make some changes to it.
The 1st change I want to do is create a horizontal scroll widget that has images that are clickable that change stations.
But to do this I first need to join two widgets into one.
In my home_widget.dart file I have this code:
final List<Widget> _children = [TracksWidget(),
NewsWidget(),
AboutWidget()];
The code above changes the body section of the home_widget.dart section. But now what I want to do is add StationsWidget() to the bottom of the TrackWidget() - Note this widget refreshes every 30 seconds. So ideally I need to make sure it does not refresh with it.
So can a body have two widgets?
Full code of test.dart (which is where I am trying to add the widget)
import 'package:flutter/material.dart';
import 'trackswidget.dart';
class TestWidget extends StatelessWidget {
// final Color color;
// PlaceholderWidget(this.color);
#override
Widget build(BuildContext context) {
double c_width = MediaQuery.of(context).size.width;
return new Container (
padding: const EdgeInsets.all(16.0),
margin: const EdgeInsets.only(bottom: 0.0),
width: c_width,
child: new SingleChildScrollView(
child: new Column (
children: <Widget>[
Column(
children: <Widget>[
Child: TracksWidget()
],
),
Column(
children: <Widget>[
new Text('Advertise on ',style: TextStyle(color: Colors.black, fontSize: 20.0),),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children:
),
],
),
]
),
),
);
}
}
The error I am getting is
'Widget' is from 'package:flutter/src/widgets/framework.dart' ('/C:/src/flutter/packages/flutter/lib/src/widgets/framework.dart').
Try changing the type of the parameter, or casting the argument to 'List'.
children: TracksWidget,
Just so you all know what I am trying to achieve. We redesigned our iOS Swift app and now want our flutter app to match.
Strictly speaking, no, the body takes exactly one Widget. You could say it takes none if you pass null, but you cannot pass more than one.
However, there are widgets that group other widgets. Your one body widget could as well be a Row and that row can have multiple child widgets.
You already did that in your title.
A nice graphical representation can be found in the documentation.