Alignment properties doesn't work so I use empty expanded widget - flutter

I want make text to the right, what am I doing so far
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _judul = 'Private Chat';
static var _warnaTema = Colors.pink[100];
Widget _dummyExpanded() {
return Expanded(
child: Container(), //contain empty data,
); //just for fill remaining space
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _judul,
theme: ThemeData(
primaryColor: _warnaTema,
),
home: Column(
children: [
Container(
child: Row(
children: [
this._dummyExpanded(),
Text('this is real data 1'),
],
),
),
Container(
child: Row(
children: [
this._dummyExpanded(),
Text('this is real data 2'),
],
),
)
],
),
);
}
}
The layout output is what I expected (the text is in right), however there's unneeded code.
As you see I use unnecessary method _dummyExpanded to fill
available space which it's just expanded with empty container. Of course it will be hard to read since there are many nested row and column, how I remove that unneeded method without loss layout output what I expect?
I believe I should have use alignment but I don't know how to

Method 1.
Container(
child: Row(
mainAxisAlignment:MainAxisAlignment.end,
children: [
Text('this is real data 2'),
],
),
)
Method 2.
I prefer this method, You can wrap text with this method.
You can also use Flexible widget instead of Expanded
Container(
child: Row(
children: [
Expanded(child: Text('this is real data 2', textAlign:TextAlign.end )),
],
),
)
Method 3.
If you have only Text widgets as children of Column widget then you can set crossAxisAlignment: CrossAxisAlignment.end, for your parent Column widget.

Related

In Flutter, why Scaffold's body can't directly use Row()?

If I use Row() instead of Center(), it will not be displayed,just blank.
I expect a music player like layout.
Make 2 Row, the 1st Row contain "LeftMenu" and "Expanded Container" for content .
Putting this in scaffold gives you the left menu:
drawer: const Drawer(
child: Text("Left Menu")
),
Putting this inside scaffold body works. Expanded and a row:
Column(
children: [
Expanded(
child: Container(
color: Colors.green,
child: const Center(child: Text("1")),
)
),
Row(
children: const [
Text("1"),
SizedBox(width: 10),
Text("2"),
],
),
],
)
If you replace center with row, it probably displays but in the top left corner and not middle. Try to wrap your Row with Center and it should display in the middle. For the row you need to add a mainAxisAlignment.
import 'package:flutter/material.dart';
const 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: Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children:[ Text('Left menu'),Text('Place container here')]
),),
),
);
}
}
This is actually the wrong question.
The real problem is: if the ListView is nested by Column, Row, it will not be displayed.
You need to use Expanded or Container on the outside and then nest it with Colmn or Row.

How to expand fixed aspect ratio widget in row as much as possible while leaving minimum amount of space for second widget?

I have two widgets I need to place side by side (will shift to vertical depending on screen size). The first widget has a fixed aspect ratio - this widget should expand as much as possible to fill the space - up until some minimum size constraint for the second widget (pixels preferred, but percentage is workable)
One, will have a fixed aspect ratio of 1 / 1.2 - for the sake of example, we'll keep it simple:
AspectRatio(
aspectRatio: 1 / 1.2,
child: ColoredBox(color: Colors.red),
)
The second widget will be a list of rows of small text items - example implementation with blue for visibility:
ColoredBox(
color: Colors.blue,
child: ListView(
children: [
Row(
children: const [
Expanded(child: Center(child: Text("small"))),
Expanded(child: Center(child: Text("text"))),
]
),
Row(
children: const [
Expanded(child: Center(child: Text("will"))),
Expanded(child: Center(child: Text("be"))),
],
),
Row(
children: const [
Expanded(child: Center(child: Text("here"))),
Expanded(child: Center(child: Text(""))), // avoid unnecessary widget tree structure changes when item is added here?
]
),
]
)
)
So, the first thing I did was just throw them in a Flex widget, wrapped in Flexible:
Flex(
direction: getDirection(),
children: [
Flexible(child: MyFixedAspectRatioWidget()),
Flexible(child: MyStringGridWidget()),
]
)
This works ok for some screen aspect ratios, but:
As the screen width is increased, I get a white bar along the right hand side.
As the width is decreased, I get white bars along the top and bottom
of the fixed aspect ratio widget.
The widgets will always have an equal width.
What I would like to happen:
As the width is increased, the string grid widget expands to fill the remaining space.
As the width is decreased, the string grid decreases in width, while the fixed aspect
ratio widget stays the same size, up until that would mean the string grid
widget would have less than some minimum size, and only then begin
to decrease the size of the aspect ratio widget (white bars on top and bottom).
What I've tried to get this behavior:
Setting a much larger flex for the fixed aspect ratio widget, while using Expanded for the string grid widget.
I was hoping that the large flex would allow it to take up as much size as it wants, while the Expanded, would cause the string grid to fill any remaining space.
At first this seemed promising - the AspectRatio grid had the behavior I wanted, filling all available space while keeping its aspect ratio, and also leaving a minimum amount of space for the string grid! The string grid however, would never expand beyond 1/10th of the width of the fixed aspect ratio widget.
Flex(
direction: getDirection(),
children: [
Flexible(flex: 10, child: MyFixedAspectRatioWidget()),
Expanded(flex: 1, child: MyStringGridWidget()),
]
);
I've tried various other combinations of flex and Expanded, but no luck improving on the initial take. Placing the ListView within Expanded just throws an exception.
Using ConstrainedBox with a very large maxWidth for the aspect ratio widget, and Expanded for the string grid widget seems to work properly when increasing the width; however, it leads to an overflow when decreasing the width, and does not save space for the grid.
I'm sure I could get this working with LayoutBuilder and SizedBox, but I was wondering if there's any built in way to get this kind of behavior.
Full example
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Example App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomePage()
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}): super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return const Scaffold(
body: BothWidgets()
);
}
}
Axis getDirection() => Axis.horizontal;
class BothWidgets extends StatelessWidget {
const BothWidgets({super.key});
#override
Widget build(BuildContext context) {
return Flex(
direction: getDirection(),
children: [
const Flexible(
flex: 10,
child: AspectRatio(
aspectRatio: 1 / 1.2,
child: ColoredBox(color: Colors.red),
),
),
Expanded(
flex: 1,
child: ColoredBox(
color: Colors.blue,
child: ListView(
children: [
Row(
children: const [
Expanded(child: Center(child: Text("small"))),
Expanded(child: Center(child: Text("text"))),
]
),
Row(
children: const [
Expanded(child: Center(child: Text("will"))),
Expanded(child: Center(child: Text("be"))),
],
),
Row(
children: const [
Expanded(child: Center(child: Text("here"))),
Expanded(child: Center(child: Text(""))), // avoid unnecessary widget tree structure changes when item is added here?
]
),
]
),
)
),
]
);
}
}

flutter image placeholder (FadeInImage) without setting fixed size?

How can I use something like FadeInImage to setup and hold the layout of a page before images have downloaded? As expected, just using Image.network causes the page to jump around once the images load and become visible. I don't have set image sizes (i allow them to resize based on screen/etc) and want to avoid setting a fixed height. The images load and show fine using FadeInImage however the screen still jumps a lot.
#override
Widget build(BuildContext context) {
return
Scaffold(
appBar: AppBar(
title: Text('Welcome!'),
),
drawer: sideDrawer(),
body: new SingleChildScrollView(
padding: const EdgeInsets.all(8.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
SizedBox(height: 28),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(width: 64),
Flexible( // tried Expanded too
child:
FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
image: 'https://www.xyzserver.com/images/dummyimage.png',
fit: BoxFit.scaleDown,
),
),
SizedBox(width: 64),
],
),
SizedBox(height: 28),
Text("stuff below the image"),
],
),
)
);
}
When using "Expanded" the image row/area is very tall vertically (the text "stuff below the image" is at the bottom of the page so the page jumps up when the image loads. When using "Flexible" the image row/area is somewhat smaller and the page jumps down when the image loads.
In the image I'm playing around with now, it's a horizontal image that is larger than the available screen space, so it will get scaled down. I guess I was thinking that since flutter can calculate the max width of what's available to the expanded/flexible, it should be able to calculate the height, but as I write this I'm thinking that's impossible since it doesn't know the height/width ratio so it can't predict the height.
How can I set this up so that images can be resized and show correctly and the page doesn't jump around? I can't imagine using fixed height/width settings is the way to go. Maybe my approach to images is all wrong and I should always use a set height/width although that can be rather difficult when people are allowed to upload their own images/etc.
Thanks!
Check this one
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Uint8List? imageData;
Future<Uint8List> dosometinhdd() async {
return (await rootBundle.load('assets/images/a.png')).buffer.asUint8List();
}
#override
void initState() {
dosometinhdd().then((value) {
setState(() {
imageData = value;
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Welcome!'),
),
body: new SingleChildScrollView(
child: Container(
height: MediaQuery.of(context).size.height * 0.8,
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
imageData != null
? Expanded(
child: FadeInImage.memoryNetwork(
placeholder: imageData!,
image:
'https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Image_created_with_a_mobile_phone.png/1200px-Image_created_with_a_mobile_phone.png',
fit: BoxFit.scaleDown,
),
)
: Container(),
Text("stuff below the image"),
],
),
),
));
}

Widget flickers and disappears when scrolling

I'm already losing sleep over this.
I'm trying to display a chart inside a ListView (for scrolling). For some reason the contents of the Card flickers when scrolling and randomly completely disappears (the Card itself stays visible though).
Any idea why would that happen?
(...) ListView (...)
children: [Row ( children: [buildChartBox()] )] (...)
Expanded buildChartBox() {
return Expanded(
child: Card(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
chartTitles(
title: 'Items',
subtitle: 'by value'),
SizedBox(
height: 300,
child: ValuesChart(data: calculateValues(items)))
],
),
],
),
),
),
);
}
Row chartTitles({String title = '', String subtitle = ''}) {
return Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: text_charttitle),
Text(subtitle, style: text_chartsubtitle),
],
)
],
);
}
Things tried:
Both of these were originally Stateless Widgets; I changed to simple
methods to simplify but it didn't change the weird behaviour.
Replacing the chartTitles return with an empty Container (i.e. removing the titles) does mitigate the issue. The chart then stays displayed but also flickers slightly.
Replacing the ListView with a SingleChildScrollView doesn't change anything.
EDIT: Code for the ValuesChart:
import 'package:fl_chart/fl_chart.dart';
class ValuesChart extends StatelessWidget {
final Map<String, int> data;
const ValuesChart({required this.data});
#override
Widget build(BuildContext context) {
return Container(
child: PieChart(
_theData(data),
));
}
}
Note I'm using a package called 'fl_chart'. _theData just returns various parameters for the chart, I don't think it's relevant.
Try to replace ListView with SingleChildScrollView
ListViews in flutter by default using what it is called in Android RecyclerView to efficiently use render resources.
If you are interested here an article
https://medium.com/1mgofficial/how-recyclerview-works-internally-71290de5d2c4

TextOverFlow Flutter

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,
);