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.
Related
I have a Text widget that sometimes can be fully displayed, sometimes not, depending on the widgets around.
If there is not enough space to fully display the widget, I want the widget to not show at all, I don't want it to show partially like with the overflow attribute.
If you know a way to do this, thanks.
LayoutBuilder to the rescue for you!
Builds a widget tree that can depend on the parent widget's size.
Reference
Try this! Play around with the allowedTextHeightInPixels value to see how it works.
/// Breakpoint or condition to WHEN should we display the Text widget
const allowedTextHeightInPixels = 150.0;
/// Test height for the [Text] widget.
const givenTextHeightByScreenPercentage = 0.3;
class ResponsiveTextWidget extends StatelessWidget {
const ResponsiveTextWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: LayoutBuilder(
builder: (context, constraints) {
print('Text height in pixels: ${constraints.maxHeight * givenTextHeightByScreenPercentage}');
return Column(
children: [
Container(
color: Colors.red,
height: constraints.maxHeight * 0.5,
),
if (constraints.maxHeight * givenTextHeightByScreenPercentage > allowedTextHeightInPixels)
const SizedBox(
child: Text(
'Responsive Me',
style: TextStyle(fontSize: 15.0),
),
),
Container(
color: Colors.blue,
height: constraints.maxHeight * 0.2,
),
],
);
},
),
),
);
}
}
I don't know why you need to do this but i thing overflow is good enough for most case, you can also use Fittedbox to scale the text with the box with no redundant space.
In case you still want do it, you need to find the RenderBox of that specific widget, which will contain its global position and rendered size from BuildContext. But BuildContext can be not exist if the widget is not rendered yet.
If by "fully displayed" you mean that, for example, you have a SingleChildScrollView and only half of your Text widget is visible, you can try out this library :
https://pub.dev/packages/visibility_detector.
You can retrieve the visible percentage of your widget with the method visibilityInfo.visibleFraction.
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
I want to reuse mobile app code for flutter web. I already coded with AppBar() and body widgets in scaffold in all screens. Now i am taking 400 width and center for web, it is good except appbar.
Scaffold(
appBar: this.getAppBarWidget(),
body: Center(
child: Container(
width: kIsWeb ? 400.0 : MediaQuery.of(context).size.width,
child: this.getBodyWidget(),
),
))
Above code is perfectly working for all screens of mobile and web except appbar in web.
How do i change width of appbar to fit width 400 ?
If i use Size.fromWidth(400) getting error.
Below code is working for mobile and web.
Scaffold(
body: Center(
child: Container(
width: kIsWeb ? 400.0 : MediaQuery.of(context).size.width,
child: Column(
children: [
this.getCustomAppbarWidget(),
this.getBodyWidget(),
],
),
),
))
Please suggest me.
The size this widget would prefer if it were otherwise unconstrained.
In many cases it's only necessary to define one preferred dimension. For example the [Scaffold] only depends on its app bar's preferred height. In that case implementations of this method can just return new Size.fromHeight(myAppBarHeight).
But we can provide customAppBar like
class MyAppBar extends StatelessWidget implements PreferredSizeWidget {
const MyAppBar({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.centerLeft,
child: Container(
alignment: Alignment.center,
color: Colors.pink,
// we can set width here with conditions
width: 200,
height: kToolbarHeight,
child: Text("MY AppBar"),
),
);
}
///width doesnt matter
#override
Size get preferredSize => Size(200, kToolbarHeight);
}
and use
Scaffold(
extendBodyBehindAppBar: true,
appBar: MyAppBar(),
body: ......
if it cover the 1st item of body, and in this case use SizedBox(height: kToolbarHeight) to handle the situation if needed.
Result
As i know, width did not allow in AppBar. Only height is allowed in AppBar
toolbarHeight: 60,
But if you want to apply manually width in your AppBar you can wrap your AppBar in Padding component
return Scaffold(
body: Column(
children: [
Container(
width: kIsWeb? 400 : double.maxFinite,
child: AppBar(
title: Text('hello'),
),
),
Expanded(child: HomePageOne()), // this expanded is you page body
],
),
);
I have a certain Text widget , when it overflows I have 3 options. Either fade ,visible, ellipsis or clip. But I don't want to choose between them . I want if a text has overflow then don't show the text.
Edit :
I'm working on a code clone to this design
Assuming that the textStyle is unknown.
How could I achieve that?
Code:
class SwipeNavigationBar extends StatefulWidget {
final Widget child;
SwipeNavigationBar({this.child});
#override
_SwipeNavigationBarState createState() => _SwipeNavigationBarState();
}
class _SwipeNavigationBarState extends State<SwipeNavigationBar> {
#override
Widget build(BuildContext context) {
return Consumer<Controller>(
builder: (_, _bloc, __) {
return SafeArea(
child: AnimatedContainer(
duration: Duration(seconds: 01),
color: Colors.white,
curve: Curves.easeIn,
height: !_bloc.x ? 50 : 200,
child: Row(
children: [
Column(
verticalDirection: VerticalDirection.up,
children: [
Expanded(child: Icon(Icons.dashboard)),
Expanded(
child: RotatedBox(
quarterTurns: -45,
child: Text(
'data',
softWrap: false,
style: TextStyle(
textBaseline: TextBaseline.alphabetic
),
),
),
),
],
)
],
),
),
);
},
);
}
}
To mimic the design you might want to look into using the Stack widget. However, to answer your question, you'd want to set softWrap to false.
Align(
alignment: Alignment.topLeft,
child: SizedBox(
width: 100,
child: Text(
'Some text we want to overflow',
softWrap: false,
),
),
)
softWrap is really the key here. Although, I added the Align and SizedBox widgets to allow this to be used anywhere, regardless of what parent widget you are using (since some widgets set tight constraints on their children and will override their children's size preference).
CodePen Example
Edit: 5/6/2020
With the release of Flutter v1.17 you now have access to a new Widget called NavigationRail which may help you with the design you're looking for.
Use ternary operator to check the length of the text that you are passing to the Text widget and based on that pass the text itself or an empty string.
String yourText;
int desiredLengthToShow = 10; //Change this according to you.
...
Text(
child: yourText.length > desiredLengthToShow ? "" : yourText,
);
I display a custom-made bottom app bar in a Stack because of keyboard padding reasons. The custom widget is fully opaque as it should be until it's a child of a Stack in which case, the content behind it starts to be visible since the color's opacity somehow changes.
As you can see, it's only the "main" color that's transparent. Icons remain opaque.
This is the build method of my custom BottomBar widget which is then just regularly put into a Stack. I have tried using a Material and even a simple Container in place of the BottomAppBar widget but the results are the same.
#override
Widget build(BuildContext context) {
return BottomAppBar(
color: Colors.blue.withOpacity(1),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(
icon: Icon(MdiIcons.plusBoxOutline),
onPressed: () {},
),
Text('Edited 11:57'),
IconButton(
icon: Icon(MdiIcons.dotsVertical),
onPressed: () {},
),
],
),
);
}
Can you interact with the BottomAppBar ? It looks like an order problem. Try to put the BottomAppBar as last in the Stack children.
Note that BottomAppBar doesn't have a constant size, if you did not add it to Scaffold bottomNavigationBar named parameter has a size if this is not null. Below is peace of code in Scaffold dart file:
double bottomNavigationBarTop;
if (hasChild(_ScaffoldSlot.bottomNavigationBar)) {
final double bottomNavigationBarHeight = layoutChild(_ScaffoldSlot.bottomNavigationBar, fullWidthConstraints).height;
bottomWidgetsHeight += bottomNavigationBarHeight;
bottomNavigationBarTop = math.max(0.0, bottom - bottomWidgetsHeight);
positionChild(_ScaffoldSlot.bottomNavigationBar, Offset(0.0, bottomNavigationBarTop));
}
You can even develop your own Widget without BottomAppBar but if you want things like centerDocked and things like circular notched, you will have to do more stuff (anyway you have flexibility to custom design the way you want).
Here is a simple example to do that(one way to do that):
import 'package:flutter/material.dart';
class CustomBottomBar extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
Container(
margin: EdgeInsets.only(bottom: 50),
color: Colors.greenAccent, // if you want this color under bottom bar add the margin to list view
child: ListView.builder(
itemCount: 100,
itemBuilder: (_, int index) => Text("Text $index"),
),
),
Positioned(
bottom: 0,
child: Container(
color: Colors.amber.withOpacity(.5),
width: MediaQuery.of(context).size.width,
height: 50,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(4, (int index) => Text("Text $index")), // you can make these clickable by wrapping with InkWell or any gesture widget
),
),
),
],
),
);
}
}