Align child widgets to a positioned child widget - flutter

I need to position a child widget (w1) at a relative position to its parent (in the example see the white box at 30%), and to position two other child widgets (w2, w3) to the right and left.
The positioned child (w1) is the anchor and should remain in 30%, regardless of w2 and w3 width, while the other child widgets should positioned accordingly.
Here's what I'm trying to achieve:
I tried to use Stack widget as the parent
The problem is I can't place the position child at 30%, as it only excepts const values
I also tried to placed them in Container with FractionalOffset - it works for single children, but I can't add another children to this Container.
Container(
height: 50,
color: Colors.blue[200],
alignment: const FractionalOffset(0.3, 0),
child: Text("50",style: const TextStyle(fontSize: 16, color: Colors.black))),

You can use CompositedTransformTarget widget.
class TestF133 extends StatelessWidget {
const TestF133({super.key});
#override
Widget build(BuildContext context) {
final LayerLink link = LayerLink();
return Scaffold(
backgroundColor: Colors.deepPurple,
body: Stack(
children: [
Align(
alignment: Alignment(.3, 0),
child: CompositedTransformTarget(
link: link,
child: Container(
height: 50,
width: 50, // you can handle theses
color: Colors.white,
),
),
),
CompositedTransformFollower(
link: link,
followerAnchor: Alignment.centerLeft,
targetAnchor: Alignment.centerRight,
child: Text("dynamic right Text"),
),
CompositedTransformFollower(
link: link,
followerAnchor: Alignment.centerRight,
targetAnchor: Alignment.centerLeft,
child: Text("dynamic left Text"),
)
],
),
);
}
}

I hope I got your question right. So, a quick solution would be:
class MyBar extends StatelessWidget {
const MyBar({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
return Container(
color: Colors.blue,
child: Row(
children: [
SizedBox(
width: width * 3 / 10,
child: const Align(
alignment: Alignment.centerRight,
child: Text('left'),
),
),
Container(
height: 50,
color: Colors.lime.shade100,
margin: const EdgeInsets.symmetric(horizontal: 10),
child: const Text("50",
style: TextStyle(fontSize: 16, color: Colors.black)),
),
const Expanded(child: Text('right')),
],
),
);
}
}
For more accurate result, I think you can find the width of the handler and subtract the half of it from the width of the SizedBox (or something like that).
You can also use Stack with position with this approach.

Related

How To make Responsive Containers with the same sized in flutter

I have a list of strings for tabs, and want to give same width to all tabs instead of based on text length...
Like I have 4 tabs , it should be occupy same width ,
and if text length is bigger than text size should b adjusted..
DONT want to user listview, all tabs should be adjusted according to available width
like width is 300 and tabs are 2, each tab should be in width of 150(including padding etc..)
but I am getting following which I dont want to set widget based on text length
,
class HomeScreen extends StatelessWidget {
HomeScreen({Key? key}) : super(key: key);
List<String> titles=['All','Income','Expense','Debt','Others','Liabilities'];
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Container(
height: 100,
color: Colors.grey,
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: titles.map((e) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 2.0),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 8,vertical: 4),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.white,
),
child: Text(e)),
)).toList(),),
),
),
);
}
}
Wrap each child of Row inside Expanded and Replace Text With AutoSizeText https://pub.dev/packages/auto_size_text
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
final List<String> titles = const [
'All',
'Income',
'Expense',
'Debt',
'Others',
'Liabilities'
];
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Container(
height: 100,
color: Colors.grey,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: titles
.map((e) => Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 2.0),
child: Container(
height: 24,
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 4),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.white,
),
child: AutoSizeText(
e,
maxLines: 1,
textAlign: TextAlign.center,
)),
),
))
.toList(),
),
),
),
);
}
}
Output:
You can achieve this by wrapping each tab in a Container widget with a fixed width and set the mainAxisAlignment property of the parent Row widget to MainAxisAlignment.spaceBetween. This will distribute the tabs evenly across the available width like this.
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
width: 150.0,
child: Text("Tab 1"),
),
Container(
width: 150.0,
child: Text("Tab 2"),
),
Container(
width: 150.0,
child: Text("Tab 3"),
),
Container(
width: 150.0,
child: Text("Tab 4"),
),
],
)
You can adjust the width property of the Container widgets as per your requirements. If the text is larger than the container width, you can adjust the text size using the style property of the Text widget and set the overflow property of the Container widget to TextOverflow.ellipsis to display an ellipsis (...) when the text overflows the container.
Take a look at Boxy, which even has an example of doing what you want to do (make a series of items the width of the largest item).
You can use a LayoutBuilder.
This widget allows you to get the parent's widget width, and according to that you can then use N SizedBox to limit the width of your chips.

Center the trailing icon of expansion tile in Flutter

I would like to horizontally center the trailing icon of my expansionTile,
Here is my expansionTile with the trailing on the bottom right :
I already tried to encapsulate the Icon in a Align and a Container but doesn't work, I also tried Padding but it's not stable if you change the size of the screen.
Code with Align :
trailing : Align(
alignment: Alignment.center,
child: Icon(
BeoticIcons.clock,
color: BeoColors.lightGreyBlue
)
),
With Container :
trailing: Container(
alignment: Alignment.center,
child: Icon(
BeoticIcons.clock,
color: BeoColors.lightGreyBlue
)
),
Thanks for your help.
This will work for you. Use LayoutBuilder to get parent widget width, and set relative padding using constraints. For example, use constraints.maxWidth * 0.5, to center across width. Your padding will be stable if you change the size of the screen:)
trailing: LayoutBuilder(builder: (ctx, constraints) {
return Padding(
padding: EdgeInsets.only(
right: constraints.maxWidth * 0.5,
),
child: Icon(
Icons.menu,
),
);
}),
you can use column and align your icon like this way hope this code will help you, thank you
import 'package:flutter/material.dart';
class Hello extends StatelessWidget {
const Hello({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 140,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
color: Colors.deepPurple[200],
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Center(child: Text("Hello")),
Text("Hello"),
SizedBox(height: 50,),
Align(
alignment: Alignment.center,
child: Icon(Icons.lock_clock))
],
),
),
),
),
),
);
}
}
Ok, I found how to do it.
Simply put the icon in the title attribute of the ExpansionTile :
return ExpansionTile(
title: Icon(
BeoticIcons.simply_down,
color: BeoColors.lightGreyBlue,
),

Align widgets round a circle

I want to align a list of widgets round a circle, so the whole thing could appear circluar like this image
is there any widgets i can use, or a list of widgets that are could go and read up on, that can help me to achieve something like this?.
Using Aling widget is simpler than Positioned widget. On Positioned widget it was having extra size beyond text, and it might be handled by providing height and weight.
class CCSh extends StatelessWidget {
final double size;
const CCSh({Key? key, required this.size}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
width: size,
height: size,
decoration: BoxDecoration(
color: Colors.green,
shape: BoxShape.circle,
border: Border.all(color: Colors.red, width: 4)),
child: Stack(
children: [
Align(
alignment: Alignment(1, 0),
child: Text("D"),
),
Align(
alignment: Alignment(0, -1),
child: Text("W"),
),
Align(
alignment: Alignment(-1, 0),
child: Text("O"),
),
Align(
alignment: Alignment(0, 1),
child: Text("R"),
),
],
),
);
}
}
It is having Container size, you need to calculate if the widget gets beyond radius.
More about Align

I am getting an error, The method '*' was called on null

I have created a button class that extends a stateless widget for creating a customized button widget. I have used this button to create buttons in a class and it worked perfectly fine. But, when i tried to create a button in an another class, using the same button widget, i got an error,'The method '*' was called on null and RenderFlex overflowed' which i could not get why is it appearing. Can somebody help me, what and where did i do the blunder.
This one is the button widget
import 'package:flutter/material.dart';
import 'package:group_project/ui/size_config.dart';
import 'package:group_project/widgets/responsive_widget.dart';
// Button Widget
class Button extends StatelessWidget {
final IconData icon;
final String btnName;
final double height;
final double width;
final Color buttonColor;
final Color iconColor;
final double iconSize;
final Color textColor;
final double btnTextSize;
Border border;
BorderRadius btnBorderRadius;
MainAxisAlignment mainAxisAlignment;
CrossAxisAlignment crossAxisAlignment;
Button({
#required this.icon,
#required this.btnName,
this.height,
this.width,
this.buttonColor,
this.iconColor,
this.textColor,
this.border,
this.mainAxisAlignment,
this.crossAxisAlignment,
this.btnTextSize,
this.iconSize,
this.btnBorderRadius,
});
#override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
height: height,
width: width,
decoration: BoxDecoration(
color: buttonColor,
border: border,
borderRadius: btnBorderRadius,
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: mainAxisAlignment,
children: [
Text(
btnName,
style: TextStyle(
fontSize: btnTextSize * SizeConfig.textMultiplier,
color: textColor,
),
),
Icon(
icon,
color: iconColor,
size: iconSize * SizeConfig.imageSizeMultiplier,
),
],
),
),
);
}
}
This is the class where I got the error.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:eva_icons_flutter/eva_icons_flutter.dart';
import 'package:group_project/ui/size_config.dart';
import 'package:group_project/widgets/widgets.dart';
// import 'package:group_project/data/data.dart';
// import 'package:group_project/widgets/product_carousel_widget.dart';
class ProductsPage extends StatefulWidget {
#override
_ProductsPageState createState() => _ProductsPageState();
}
class _ProductsPageState extends State<ProductsPage> {
Size size;
bool visible = true;
void isVisible() {
if (visible == true) {
visible = false;
} else {
visible = true;
}
}
#override
Widget build(BuildContext context) {
size = MediaQuery.of(context).size;
return Scaffold(
backgroundColor: Color(0xfff0f0f0),
body: ListView(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
children: [
Container(
height: 233.33 * SizeConfig.heightMultiplier,
width: double.infinity,
color: Colors.blue,
child: Image(
image: AssetImage('images/jacket.jpg'),
fit: BoxFit.cover,
),
),
Stack(
children: [
// Products description
Visibility(
visible: visible,
child: Padding(
padding: const EdgeInsets.only(top: 40.0),
child: Container(
padding: EdgeInsets.fromLTRB(10.0, 40.0, 10.0, 10.0),
height: 400,
width: double.infinity,
decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(20.0),
// border: Border.all(color: Colors.blue),
color: Colors.blue,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Iphone Pro Max'
),
Text(
'Rs. 125000'
),
],
),
SizedBox(
height: 20.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'(Used)'
),
Text(
'Condition: Good'
),
],
),
SizedBox(
height: 20.0,
),
Text(
'This is iphone 11 pro max, 64 GB variant. The size of the mobile phone is 6.5 inches. Released 2019, September ',
),
SizedBox(
height: 20.0,
),
Row(
children: [
// This is the button where exactly I am getting the error
Button(
height: 25 * SizeConfig.heightMultiplier,
width: 80,
icon: Icons.shopping_cart,
btnName: 'Add',
),
],
),
],
),
),
),
),
FlatButton(
padding: EdgeInsets.all(0),
onPressed: () {
setState(() {
isVisible();
});
},
child: Button(
icon: EvaIcons.chevronDown,
btnName: 'Show Description',
height: 25.0 * SizeConfig.heightMultiplier,
width: double.infinity,
buttonColor: Colors.blue,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
btnTextSize: 8.0,
iconSize: 20,
textColor: Colors.white,
iconColor: Colors.white,
// btnBorderRadius: BorderRadius.circular(0),
),
),
],
),
],
),
],
),
],
),
);
}
}
Wrap it with Expanded Widget when using inside a Row or Column
Expanded(
child: Button(
height: 25 * SizeConfig.heightMultiplier,
width: 80,
icon: Icons.shopping_cart,
btnName: 'Add',
),
),
Your Row has no defined height or width. Try wrapping your row in an Expanded widget.
This also why you're getting the null reference exception. You're sizeConfig (Which I assume is based off of MediaQuery.of(context).size) Gets it's context from it's parent widget and since a Row widget doesn't define (It is a flexible widget) height or width, it will return null for size. Expanded will tell the Row to set its size to all available space.
#override
Widget build(BuildContext context) {
return SingleChildScrollView(child: Container(...));}
surround your code with SingleChildScrollView that's why render flex error is showing
for the '*' is called on null error click on the run button at the bottom of android studio and look at the log and click the link with ProductPage.dart and it will take you to the line where the error happens
Try giving it a width or wrapping with a Expanded
It is given infinite width because MediaQuery is always given the context of it's parent, and in this scenario it gets it from Row widget which doesn't have a defined width. Neither does a Column widget have a defined height. That's why it's giving the error.
Wrapping it with Expanded widget will make the Row take all of free space.

Create device height background element

I am very new to flutter so please be fair.
I would like to create the following.
Layout
Background which is always the entire screen-size (includes multiple stacked images)
Content (adapts to the the normal app ui behaviours -> ui element like keyboard)
I can't seem to figure out how to create this background element which should not resize when the keyboard is pulled out.
I have this and I hope someone could give me a hand.
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
var insetHeight = MediaQuery.of(context).viewInsets.bottom;
return Scaffold(
resizeToAvoidBottomPadding: false,
body: Stack(
children: <Widget>[
Stack(
children: <Widget>[
Positioned(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height + insetHeight,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/background.png"),
fit: BoxFit.cover,
alignment: Alignment.bottomCenter,
),
)
),
),
],
),
SizedBox(
width: 370,
child: SingleChildScrollView(
physics: PageScrollPhysics(), // dont really need this
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.all(20.0),
child: Text("Login to",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: "Opensans",
fontSize: 30,
letterSpacing: .6,
color: Colors.black45,
fontWeight: FontWeight.normal
)
),
),
Card(
child: Padding(padding: EdgeInsets.fromLTRB(20.0, 20.0, 20.0, 0), child: LoginForm()),
)
],
),
)
)
],
),
);
}
}
I have tried to use the MediaQuery.of(context).viewInsets.bottom; but it's always returning 0.
I am not sure how to solve this.
The Scaffold rebuilds its body when keyboard is visible.
So move your background widget outside the Scaffold.
class MainPage extends StatefulWidget {
#override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
SizedBox.expand(
child: Image.asset(
"assets/images/background.png",
fit: BoxFit.cover,
),
),
Scaffold(
backgroundColor: Colors.transparent, //Should be transparent
body: Center(
child: TextField(),
),
),
],
);
}
}
For background, Try following:
Create a variable Size _screensize in _MyHomePageState.
Override initState in _MyHomePageState and do following:
#override
void initState() {
super.initState();
_screenSize ??= MediaQuery.of(context).size;`
}
Use this _screenSize as width and height for Positioned as below:
Positioned(
width: _screenSize.width,
height: _screenSize.height,
),
Add other normal widgets as usual.
Summary for background:
step 1: creating a private reference for size to use.
step 2: updating the private size variable only when it is null, which is only when the widget state is initialized the first time.
step 3: using private size as height and width for the background.