Widget with width and offset relative to parent - flutter

I would like to render something that looks a bit like a scrollbar to indicate that I am on page 2/5. To do this, I would need a widget with the following:
The width is 20% width relative to the size of the parent
Top-left of the widget is offset by 40% relative to the size of the parent
I was able to accomplish the first point using a FractionallySizedBox but I'm not sure how to compose this to accomplish the offset. Thanks!
Here is a Flutter codepen illustrating what I have so far. I would like to offset this by 40% relative to the parent while still preserving the 20% width.
https://codepen.io/venkatd-the-bashful/pen/jOWYQXz
Snippet of the example below
class PagePositionDisplay extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: SizedBox(
height: 30,
width: 300,
child: Container(
color: Colors.grey,
child: FractionallySizedBox(
alignment: Alignment.topLeft,
heightFactor: 1,
widthFactor: 0.2,
child: Container(
decoration: BoxDecoration(
shape: BoxShape.rectangle,
color: Colors.blue,
),
),
),
),
),
),
);
}
}

Try using Layout Builder with some row:
class PagePositionDisplay extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: SizedBox(
height: 30,
width: 300,
child: Container(
color: Colors.grey,
child: LayoutBuilder(builder: (context, constraints) {
return Row(
children: <Widget>[
SizedBox(
// your offset percentage * total width
width: (2 / 5) * constraints.maxWidth,
),
Container(
// your 'scrollbar' percentage * total width
width: (1 / 5) * constraints.maxWidth,
decoration: BoxDecoration(
shape: BoxShape.rectangle,
color: Colors.blue,
),
),
],
);
}),
),
),
),
);
}
}

Related

how a child can get the width / height of it's parent dynamically

let's say I have a ChildWidget() and ParentWidget() and I want to say something like :
however, the parent width is, the child's width should be 20% of it
example :
if a parent has a width: 200, the child's width should be width: 40.
and I want a way that's dynamic and not actually hardcoded values, so I will change the parent width and expect that the child
any ideas are welcome.
As pskink mentioned, FractionallySizedBox is handy in your case.
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
width: 400,
height: 400,
color: Colors.deepPurpleAccent,
child: FractionallySizedBox(
widthFactor: 0.2, //20% width
heightFactor: .5, //50% height
alignment: FractionalOffset.center,
child: DecoratedBox(
decoration: BoxDecoration(
color: Colors.amber,
),
),
),
),
),
);
}
}
Also, you can check eamirho3ein's answer on LayoutBuilder.
Lets say your parent widget is this container:
Container(
height: 200,
width: 300,
),
you can do this to get its size:
Container(
height: 200,
width: 300,
color: Colors.red,
alignment: Alignment.center, // very important part is set alignment
child: LayoutBuilder(builder: (context, constraints) {
return Container(
color: Colors.blue,
width: constraints.maxWidth * 0.2,
height: constraints.maxHeight * 0.3,
);
},),
),
result:
you should use the MediaQuery class like in the next example :
MediaQuery.of(context).size.width * .20
MediaQuery.of(context).size.height * .20
this will give the width and the height for the parent child * 20%
for getting the width and height of the parent widget you could use this way : you can put the child widget in a LayoutBuilder widget , this widget will allow you to get the parent width and height , and this is an example about this :
#override
Widget build(BuildContext context) {
debugPrint("screen width ${MediaQuery.of(context).size.width}");
debugPrint("screen height ${MediaQuery.of(context).size.height}");
return Scaffold(
body: Center(
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(color: Colors.black,border: Border.all(color: Colors.red,width: 5)),
height: 200,
width: 200,
child: LayoutBuilder(
builder: (context, constraints) {
return SizedBox(
width: constraints.maxWidth * 0.50,
height: constraints.maxHeight * 0.50 ,
child: ElevatedButton(onPressed: (){}, child: const Text("stack overflow")));
},
),
),
),
);
}
try to run this build method and you will understand the example.

Flutter OverflowBox is behind the next widget in a column

I'm working on a Flutter project and I am trying to use the OverflowBox widget.
I have a list of widgets in a Column, one of them, in the middle is supposed to overflow the others based on some events by the user.
Here is a simplified version of my code.
The red Container needs to display the green Container that overflows it at the top and the bottom.
But as you can see on the image, the green Container is only visible above the previous Container (the blue one) but not on the next one (the black Container). It looks like it is behind.
class MyScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
height: 100,
width: 100,
color: Colors.blue,
),
Container(
height: 100,
width: 100,
color: Colors.red,
child: Center(
child: OverflowBox(
maxHeight: 150,
child: Container(
color: Colors.green,
height: 150,
width: 50,
),
),
),
),
Container(
height: 100,
width: 100,
color: Colors.black,
)
],
);
}
}
How can I get my green Container to be above the black one too ?
EDIT: For functionality purposes, I need the green Container to be a child/be created by the red Container (and not by the list where I could use a Stack widget). I need the logic to be inside the red and green ones.
It still uses Stack, but Green Container is still part of Red Container.
And it might be difficult to calculate margin if Container has dynamic height.
class MyScreen extends StatelessWidget {
const MyScreen({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
Container(
height: 100,
width: 100,
color: Colors.blue,
),
Container(
margin: const EdgeInsets.only(top: 200),
height: 100,
width: 100,
color: Colors.black,
),
Container(
margin: const EdgeInsets.only(top: 100),
height: 100,
width: 100,
color: Colors.red,
child: Center(
child: OverflowBox(
maxHeight: 150,
child: Container(
height: 150,
width: 50,
color: Colors.green,
),
),
),
),
],
),
);
}
}
Use of overlay, maybe solve your problem.
OverlayState? overlayState = Overlay.of(context);
I tried your code snipped and failed to getting the design that you particularly wishing to achieve.
I have anther way to get such type of design. Which ia using Stacl() widget
Here is an complete example code snippet
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyScreen(),
),
),
);
}
}
class MyScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Stack(
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
height: MediaQuery.of(context).size.height/3,
width: MediaQuery.of(context).size.width,
color: Colors.blue,
),
Container(
height: MediaQuery.of(context).size.height/3,
width: MediaQuery.of(context).size.width,
color: Colors.red,
),
Container(
height: MediaQuery.of(context).size.height/3,
width: MediaQuery.of(context).size.width,
color: Colors.black,
)
],
),
Positioned(
// to set a specific position of your widget use Positioned inside a Stack() widget
/*
bottom: 50,
top: MediaQuery.of(context).size.height/3,
left: 100,
right: 100,
*/
child: OverflowBox(
child: Container(
color: Colors.green,
height: MediaQuery.of(context).size.height/2,
width: 100,
),
),
),
],
);
}
}
Output:

transform crushed the container above flutter

I have a code that contains a column, and in the column there are 3 widgets, a widget container that has a height of 200 and a width of 200 in red, and the second widget contains a container with a child a transform scale that contains an image that I want to scale, and widget 3 contains the same as the first widget, every time I scale the image, what happens to the second container is always past the first container but does not occur with continaer to 3, if in css I will definitely use zindex, is there some kind of flutter zindex
this is the code
SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: Column(
children: <Widget>[
Container(
height: 300,
color: Colors.red,
),
Container(
// height: 397,
child: Transform.scale(
scale: 2.0,
child: Container(
width: MediaQuery.of(context).size.width,
child: Image(
image: NetworkImage(
"https://s3-ap-southeast-1.amazonaws.com//kriyapeople/8fa208d6-1486-4028-bd23-243581b4d3a7"),
fit: BoxFit.fitWidth,
),
),
),
),
Container(
height: 300,
color: Colors.red,
),
],
)));
and the result of that code
Use Stack widget,
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: <Widget>[
_buildHeader(),
for (final i in List.generate(20, (i) => i))
ListTile(title: Text("Tile $i")),
],
),
);
}
_buildHeader() {
double height = 250;
return SizedBox(
height: height,
child: Stack(
children: <Widget>[
Column(
children: <Widget>[
Container(
color: Colors.red,
height: height * 2 / 3,
),
Container(
color: Colors.grey[200],
height: height / 3,
),
],
),
Align(
alignment: Alignment.bottomCenter,
child: Image(
image: NetworkImage(
"https://s3-ap-southeast-1.amazonaws.com//kriyapeople/8fa208d6-1486-4028-bd23-243581b4d3a7"),
height: height * 2/3,
width: height * 2/3,
fit: BoxFit.cover,
),
),
],
),
);
}
}

Why the Image widget can not set special width and height in the Container with specified width and height?

Why the Image widget can not set special width and height in the Container with specified width and height?
class HomeContent extends StatelessWidget{
#override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
child: Container(
child: Image.network(
"http://a1.att.hudong.com/60/38/01200000194369136323385641912.jpg",
width: 20,
height: 20,
),
width: 400,
height: 400,
decoration: BoxDecoration(
color: Colors.yellow,
),
),
);
}
}
The result is like this, you see the Image in the Container take up the width 400.0, rather than 20.
EDIT-01
I tried use MediaQuery to set the Image's width and height, but there is no effect.
class HomeContent extends StatelessWidget{
#override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
child: Container(
child: Image.network(
"http://a1.att.hudong.com/60/38/01200000194369136323385641912.jpg",
width: MediaQuery.of(context).size.height/2,
height: MediaQuery.of(context).size.height/2,
),
width: 400,
height: 400,
decoration: BoxDecoration(
color: Colors.yellow,
),
),
);
}
}
Use Mediaquery forheight and Width
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
And implement like this
class HomeContent extends StatelessWidget{
#override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
child: Container(
child: Image.network(
"http://a1.att.hudong.com/60/38/01200000194369136323385641912.jpg",
width: width,
height: height,
),
width: 400,
height: 400,
decoration: BoxDecoration(
color: Colors.yellow,
),
),
);
}
}
You should set the Container's Constants first:
Such as set the alignment.
class HomeContent extends StatelessWidget{
#override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
child: Container(
child: Image.network(
"http://a1.att.hudong.com/60/38/01200000194369136323385641912.jpg",
width: 20,
height:20,
),
width: 400,
height: 400,
decoration: BoxDecoration(
color: Colors.yellow,
),
alignment: Alignment.center,
),
);
}
}
The width and height on Container sets the width and height constraints of the child, at which point the width and height on the child are powerless to do anything.So you can take another widget and place the Image inside that.For example I can take Center.
Container(
child: Center(
child: Image.network(
"http://a1.att.hudong.com/60/38/01200000194369136323385641912.jpg",
width: 20,
height: 20,
),
),
width: 400,
height: 400,
decoration: BoxDecoration(
color: Colors.yellow,
),
)
and it'll work fine as expected

Flutter - Overlay card widget on a container

In flutter, is it possible to place a part of a card on another container? In CSS, we would set margin-top to a negative value or use translate property. In flutter as we cannot set negative values to margin-top, is there an alternative to that?
Yes, you can acheive it with a Stack widget. You can stack a card over the background and provide a top or bottom padding.
A simple example would look like:
class StackDemo extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Stack(
children: <Widget>[
// The containers in the background
new Column(
children: <Widget>[
new Container(
height: MediaQuery.of(context).size.height * .65,
color: Colors.blue,
),
new Container(
height: MediaQuery.of(context).size.height * .35,
color: Colors.white,
)
],
),
// The card widget with top padding,
// incase if you wanted bottom padding to work,
// set the `alignment` of container to Alignment.bottomCenter
new Container(
alignment: Alignment.topCenter,
padding: new EdgeInsets.only(
top: MediaQuery.of(context).size.height * .58,
right: 20.0,
left: 20.0),
child: new Container(
height: 200.0,
width: MediaQuery.of(context).size.width,
child: new Card(
color: Colors.white,
elevation: 4.0,
),
),
)
],
);
}
}
The output of the above code would look something like:
Hope this helps!
Screenshot:
Instead of hardcoding Positioned or Container, you should use Align.
Code:
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return Scaffold(
body: Stack(
children: [
Column(
children: [
Expanded(flex: 2, child: Container(color: Colors.indigo)),
Expanded(child: Container(color: Colors.white)),
],
),
Align(
alignment: Alignment(0, 0.5),
child: Container(
width: size.width * 0.9,
height: size.height * 0.4,
child: Card(
elevation: 12,
child: Center(child: Text('CARD', style: Theme.of(context).textTheme.headline2)),
),
),
),
],
),
);
}
Here is running example with overlay:
class _MyHomePageState extends State<MyHomePage> {
double _width = 0.0;
double _height = 0.0;
#override
Widget build(BuildContext context) {
_width = MediaQuery.of(context).size.width;
_height = MediaQuery.of(context).size.height;
return Scaffold(
backgroundColor: Colors.white,
body: Stack(
children: <Widget>[
// The containers in the background and scrollable
getScrollableBody(),
// This container will work as Overlay
getOverlayWidget()
],
),
);
}
Widget getOverlayWidget() {
return new Container(
alignment: Alignment.bottomCenter,
child: new Container(
height: 100.0,
width: _width,
color: Colors.cyan.withOpacity(0.4),
),
);
}
Widget getScrollableBody() {
return SingleChildScrollView(
child: new Column(
children: <Widget>[
new Container(
height: _height * .65,
color: Colors.yellow,
),
new Container(
height: _height * .65,
color: Colors.brown,
),
new Container(
margin: EdgeInsets.only(bottom: 100.0),
height: _height * .65,
color: Colors.orange,
),
],
),
);
}
}
Here is Result of code:
Scrollable Body under customised Bottom Bar