I'm new to flutter, I have created a multistate toggle button but I want to convert it into dropdown in case the container doesn't have enough space to show the widget. Earlier I was using the LayoutBuilder context width but it is taking the whole width of the page not of the container containing the widget. Can you please help me with this ?
You are using the right approach. LayoutBuilder would work for you, but you should factor the entire widget into its own StateLess widget and use that context to do your measurements.
LayoutBuilder provides a BoxConstraints object with minWidth, maxWidth, minHeight, maxHeight properties that you can use in your code to decide which widget to embed in the tree. The dimension of that BoxConstraints object are calculated from your Widget's immediate ancestor.
Supposed you create MyMultistateToggleBoxOrDropdownWidget() and implement its build method like this:
#override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
// If constraints.maxWidth isn't wide enough,
// return a dropdown Widget,
// otherwise return the multistate toggle box.
}
}
Now that you have a Widget that returns what you want based on width, you need to now wire it into the correct context.
What you're probably missing is that you need to wrap your custom widget inside of something that controls the screen space that you want to present your Widget inside. A SizedBox() will do for this example.
Your solution took the whole page width because that was the width of your Widget's immediate ancestor in the Widget tree.
SizedBox(
width: 100.0,
height: 100.0,
child: MyMultistateToggleBoxOrDropdownWidget()
)
I am unable to make the buttons not overlap so I can tap on them separately like below
As you can see I cannot tap on the button which lies beneath those other 3 buttons.
Here is the normal picture of the screen where the clouds seems to be clickable but it isn't reachable easily.
Here is the code for my Cloud Button
class Cloud extends StatelessWidget {
Cloud({this.width,this.height,this.bottom,this.left,this.lineUpLink,this.right,this.top,this.videoLink});
final String videoLink;
final String lineUpLink;
final double bottom;
final double left;
final double right;
final double top;
final double height;
final double width;
#override
Widget build(BuildContext context) {
return Positioned(
bottom: bottom,
left: left,
width: width,
height: height,
top: top,
right: right ,
child: IconButton(
icon: Image.asset('images/cloud30.png'),
onPressed: () {
final getLink = GetLink(
link: videoLink,
lineLink: lineUpLink,
);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => VideoApp(link: getLink.link,lineupLink: getLink.lineLink,)),
);
},
),
);
}
}
Here is my Stack code in the main screen.
fit: StackFit.expand,
children: [
//T Smokes
Center(child: Image.asset('images/nuke.png')),
Cloud(top: 310/782 * height,left: 185/392 * width,videoLink: 'https://giant.gfycat.com/NarrowImpassionedCero.webm',lineUpLink: 'https://firebasestorage.googleapis.com/v0/b/flash-chats-2f263.appspot.com/o/Nuke%2F1.png?alt=media&token=1116e338-07b3-4780-b919-4ce3fa1b68a6',),//Ramp
Cloud(top: 350/782 * height,right: 125/392 * width,videoLink: 'https://giant.gfycat.com/ThreadbareSecondBat.webm', lineUpLink: 'https://firebasestorage.googleapis.com/v0/b/flash-chats-2f263.appspot.com/o/Nuke%2F2.png?alt=media&token=884fed00-8d42-41be-87f5-65cc81c2a684',),//Heaven
Cloud(top: 355/782 * height,right: 95/392 * width,videoLink: 'https://giant.gfycat.com/InformalHeartfeltAfricanclawedfrog.webm',lineUpLink: 'https://firebasestorage.googleapis.com/v0/b/flash-chats-2f263.appspot.com/o/Nuke%2F3.png?alt=media&token=f0d61fd2-8527-48cf-8062-5187f6be7cf1',),//Outside Heaven
Cloud(bottom: 290/782 * height,left: 180/392 * width,videoLink: 'https://giant.gfycat.com/AdolescentThisCornsnake.webm',lineUpLink: 'https://firebasestorage.googleapis.com/v0/b/flash-chats-2f263.appspot.com/o/Nuke%2F4.png?alt=media&token=ce9e6dca-4dbc-42b1-8de3-c5f68576ca47',),//T Red
Cloud(bottom: 325/782 * height,left: 205/392 * width,videoLink: 'https://giant.gfycat.com/JovialQuaintHackee.webm',lineUpLink: 'https://firebasestorage.googleapis.com/v0/b/flash-chats-2f263.appspot.com/o/Nuke%2F6.png?alt=media&token=37d4ca8e-e39b-479c-a7cc-c8dac7c37ec0',),//Mini Inside
Cloud(bottom: 275/782 * height, right: 130/392 * width,videoLink: 'https://giant.gfycat.com/HomelyGiganticGallinule.webm',lineUpLink: 'https://firebasestorage.googleapis.com/v0/b/flash-chats-2f263.appspot.com/o/Nuke%2F7.png?alt=media&token=73d4f4bd-9f78-42da-8102-cdb341c8ebef',),//Outside passing red
Cloud(bottom: 300/782 * height,right: 100/392 * width,videoLink: 'https://giant.gfycat.com/WarpedGrandioseHerald.webm',lineUpLink: 'https://media.discordapp.net/attachments/688396703685935154/826611169145126932/unknown.png',),//Garage
Cloud(bottom: 335/782 * height,left: 180/392 * width,videoLink: 'https://giant.gfycat.com/DazzlingUnsightlyHairstreakbutterfly.webm',lineUpLink: 'https://media.discordapp.net/attachments/763777060636065812/826612884212678656/unknown.png',),// Vent
Cloud(bottom: 300/782 * height,left: 205/392 * width,videoLink: 'https://giant.gfycat.com/ForcefulExaltedErne.webm',lineUpLink: 'https://firebasestorage.googleapis.com/v0/b/flash-chats-2f263.appspot.com/o/Nuke%2F5.png?alt=media&token=189d94eb-cde6-452d-a0a3-56ec7c544c11',),//T red T side left
Cloud(bottom: 330/782 * height,right: 112/392 * width,videoLink: 'https://giant.gfycat.com/FeistyReasonableEkaltadeta.webm',lineUpLink: 'https://media.discordapp.net/attachments/763777060636065812/826614730097426522/unknown.png',),//CT Red
],
),
Please someone can help me find the solution for this problem?
Thank you.
Please post your logic for handling tap gestures. Based on the pictures you posted, it appears that you are using stacks of containers with 'clouds' inside them, and your gesture detector is wrapping the the parent containers.
I would advise you to use two stacks.
The first stack is exactly like the one you have now, but without wrapping a gesture detector around your containers, just simply keep them container+cloud.
Use a second stack, that sits infront of your current stack, and only consists of gesture detectors that wrapping empty containers, but have a width and height equal to the inner diameter of your clouds. Position this stack infront of the cloud stack, while aligning the centers of these empty containers to the centers of your clouds. And in your gesture detector here use the property of behavior: HitTestBehavior.translucent.
Assuming your clouds have a width and height of 30 pixels[PAy attention, the dimensions of the clouds, not their parent containers), use this:
GestureDetector(
behavior: HitTestBehavior.translucent,
child: Container (height: 30, width:30),
onTap: (){//your logic here})
Sorry if this is a dup, I see a lot of questions regarding text wrapping, but not generic widget wrapping in a row.
I have a dynamic row of buttons within a row. I'd like to wrap the buttons to create a second row if the list becomes longer than the width of the screen. Is it possible to do this automatically, or do I need to manually detect and create the correct number of rows.
If the latter, does anybody have pointers to measuring a widget's width vs screen width? Right now I'm doing something like:
...
return Row(
children: List.generate(count*2 + 1, (i) {
if (i %2 == 0) {
return Spacer();
}
return RaisedButton(child: Text((i / 2).round().toString(), onPressed: (){...});
});
Row is useful when you need to organize child widgets in a single line. Wrap with default direction is an alternative to Row that moves child widgets to the next line if there is no enough space
I am trying to draw red dots over the child textbox widget like this:
For that, I wrapped the child widget with CustomPaint() widget:
return CustomPaint(
painter: DotsPainter(), //draws red dots based on child's size
child: child, //textbox
);
But the result is this:
How to make CustomPainter "overlay" its child widget?
Thanks.
The CustomPaint has 2 possible painters:
When asked to paint, CustomPaint first asks its painter to paint on the current canvas, then it paints its child, and then, after painting its child, it asks its foregroundPainter to paint.
(emphasis mine)
So if you move your painter to the foregroundPainter instead, it should work fine:
return CustomPaint(
foregroundPainter: DotsPainter(), //draws red dots based on child's size
child: child, //textbox
);
I'm creating a widget that presents a Stack inside a Container. Inside the Stack there is a dynamic Column inside a Positioned widget, which sticks the Column to the Bottom.
I am trying to wrap the Stack in a SingleChildScrollView, that if the dynamic Column will have lots of children it will be able to scroll.
But after I add the scroll view I get this error message:
RenderStack object was given an infinite size during layout.
A scrollView doesn't have height, it will use infinite height for it's children. So the stack should be wrapped in a sizedBox widh a known height in case that you want that. If you want the stack to fill the screen then remove the singleChildScrollview completely. And if you want the stack to be scrollable from the inside. Just add SingleChildScrollView inside the stack
return Scaffold(
body: Container(
color: Colors.blue[100],
child: Stack(
children: [
Positioned.fill(child: SingleChildScrollView(child: MyColumn()))
],
),
),
);
EDIT 1:
Ok the problem is the layout itself. Since you only use the stack to position the image. And you know the widht and height of the image, and the background shape fills all the items. We could
Isolate the stack only to the image, and use padding and some calculation to have the layout build in a similar way.
Then render everything else inside a normal column
My implementation https://dartpad.dev/230b14d8f0b22b45929a75c208786257
From the RenderStack documentation:
First, the non-positioned children (those with null values for top, right, bottom, and left) are laid out and initially placed in the upper-left corner of the stack. The stack is then sized to enclose all of the non-positioned children. If there are no non-positioned children, the stack becomes as large as possible.
Since all of your Stack's children are positioned, Stack will match the maximum size constraint passed down by the SingleChildScrollView. This size has infinite height, so the Stack is forced to have infinite height as well.
To fix this, you will need to find another way to accomplish what you want. One option that comes to mind involves a ConstrainedBox providing a minimum height (obtained from a LayoutBuilder), a non-positioned Column, and a bottomCenter alignment on the Stack itself. This is similar to the first code sample in the SingleChildScrollView documentation:
LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
// This ensures that the Stack fills the entire viewport,
// even if the Column is small.
constraints: BoxConstraints(
minHeight: constraints.maxHeight,
),
child: Stack(
// Place the only non-positioned child (the column) at the bottom
alignment: Alignment.bottomCenter,
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [ /* ... */ ]
)
]
)
)
);
}
)