Flutter layout expanded trouble - android

I trying this layout
Card
Row
Expanded (flex: 4)
Image
Expanded (flex: 4)
Column (this is the important column)
row, row, row
Now I want use MainAxisAlignment.spaceBetween of Column I see that column has not height of the parent row. Because image's height is for example 200.0
The Expanded(4) widgets I have for split card to two sides because original image size is bigger. If I set manually height of parent ROW then working fine but I dont want set height manually.
If I try use another Expanded in Column, I have got exception.
One more litle question, what's different between Container and SizedBox ?
Thanks for help
edit: add code and screen
#override
Widget build(BuildContext context) {
return new Card(
child: new Container(
padding: new EdgeInsets.only(left: 5.0),
child: new Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[new Expanded(flex: 4, child: new Image.network(_tour.hotel.thumbnail)), new Expanded(flex: 4, child: _buildInfoColumn())],
),
),
);
}
Widget _buildInfoColumn() {
return new Container(
padding: new EdgeInsets.only(left: 3.0),
child: new Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween, //this is not working
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(_tour.hotel.name, style: new TextStyle(fontSize: 14.0, fontFamily: 'Lato')),
new Text(_tour.hotel.country + ', ' + _tour.hotel.locality, style: new TextStyle(fontSize: 12.0, fontFamily: 'Lato', color: Colors.grey))
],
),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Container(
padding: new EdgeInsets.only(left: 5.0),
child: new Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Text(_tour.finalPrice.toString() + ',-', style: new TextStyle(fontSize: 15.0, fontWeight: FontWeight.bold, fontFamily: 'Lato', color: Colors.lightGreen)),
new Text(((_tour.discount > 0) ? ' ' + _tour.price.toString() + ',-' : ''), style: new TextStyle(fontSize: 12.0, fontFamily: 'Lato', color: Colors.red)),
],
),
),
new Container(
padding: new EdgeInsets.all(2.0),
decoration: new BoxDecoration(color: Colors.red),
child: new Text(
'-' + _tour.discount.toString() + '%',
style: new TextStyle(fontWeight: FontWeight.bold, fontSize: 11.0, fontFamily: 'Lato', color: Colors.white),
))
],
),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Row(
children: <Widget>[_buildTransportIcon(), _buildDates()],
),
new Container(
padding: new EdgeInsets.only(right: 5.0),
child: new Row(
children: ((_tour.hotel.stars != null)
? new List.generate(
_tour.hotel.stars,
(i) => new Icon(
Icons.star,
color: Colors.orangeAccent,
size: 13.0,
))
: []),
))
],
)
],
)
);

The reason why MainAxisAlignment.spaceBetween doesn't work is because the widget doesn't know the size that it'll divid evenly. You may want to consider setting a fixed height for the Card widget and just crop the image being displayed to fit in the widget.
As for your question regarding Container and SizedBox, it's best explained here.

Related

Flutter Align the widget onto the top in ROW

I have an issue in ROW that one child has many items so it is large and another child has fewer items so its height is small so the less item is showing in the center of the ROW, so I need it to align to the top inside the ROW, you can have a look at the image.
Please have a look at my code as well.
rowList = Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: mainBodyList,
);
MAIN BODY LIST
Container(
width: screenWidth * 0.49,
child: Card(
color: Colors.white,
child: Column(
children: <Widget>[
Container(
//width: 200,
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8),
decoration: BoxDecoration(
color: Colors.black12,
),
child: Row(
children: <Widget>[
ClipOval(
child: Material(
color: Colors.white,
child: SizedBox(
width: 40,
height: 40,
child:
/*Image.asset(
'assets/icons/doc_icon.png'),*/
Icon(
Icons.playlist_add_check,
color: AppTheme.primaryColor,
),
),
),
),
Flexible(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
_localization.localeString(name),
style: TextStyle(color: AppTheme.primaryColor),
),
],
),
),
),
],
),
),
Container(
child: Column(
children: _dynamicListWidget(list),
),
),
],
),
),
);
You need to set crossAxisAlignment as CrossAxisAlignment.start
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: mainBodyList,
);

TextOverflow in Row which is inside a Column in Flutter

I'm trying to develop a Card with some text widget beneath it. Look at the image below.
The problem I'm facing is when the text next to location icon is large, it overflows. I've tried with Flex, but it throws an exception. There's also a star icon at the right bottom of the card.
Here's what I want :
I want the text to be single line ending with .. if it's too long.
star should be placed at the bottom right
The location icon doesn't consider the left padding I gave (Padding widget)
Please help! Thanks in advance.
Here's my code :
Scaffold buildOffersList(OfferModel offerModel) {
return Scaffold(
body: Stack(
children: <Widget>[
Center(
child: Image.network(
'https://b.zmtcdn.com/data/pictures/2/19250332/0fe23bee17b60d181fd43421ca3480d4_featured_v2.jpg',
fit: BoxFit.cover,
width: size.width,
height: size.height,
color: Colors.black.withOpacity(.6),
colorBlendMode: BlendMode.darken
),
),
Column(
children: <Widget>[
Container(
child: PageHeader(pageTitle: 'Popular Offers', numberOfOffers: '20 venues', sortByText: 'Sort By: Location', filterText: 'Filter'),
),
Expanded(
child: GridView.count(
crossAxisCount: 2,
mainAxisSpacing: 5.0,
crossAxisSpacing: 5.0,
padding: const EdgeInsets.only(left: 10.0, right: 10.0),
children: List.generate(offerModel.payload.offers.length, (index) {
return Center(
child: offerCard3(offerModel.payload.offers[index]),
);
}),
),
),
],
),
],
)
);
}
Widget offerCard3(Offer offer) {
return GestureDetector(
child: Card(
elevation: 1.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(0.0),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
AspectRatio(
aspectRatio: 18.0 / 8.0,
child: Image.network(
"https://b.zmtcdn.com/data/pictures/2/19250332/0fe23bee17b60d181fd43421ca3480d4_featured_v2.jpg",
fit: BoxFit.cover,
),
),
Padding(
padding: EdgeInsets.fromLTRB(7.0, 5.0, 4.0, 5.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
getBrandName(offer),
getOfferTitle(offer),
SizedBox(height: 15.0),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
getLocationIcon(),
getOfferContactAddressView(offer),
],
),
getKmText(),
],
),
//Spacer(),
getStarIcon(),
],
),
],
),
),
],
),
),
);
}
Text getOfferContactAddressView(Offer offer) {
return Text(
offer.offerContactAddress,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: Colors.black38,
fontSize: 9.0,
),
);
}
Icon getStarIcon() {
return Icon(
Icons.star,
color: Colors.orange,
size: 25,
);
}
There is a flutter package for auto resize text to contain the full text.
auto_size_text 2.1.0 here
FIrst Solution Highly Recommend
First of all, you can use Listtile.
ListTile(title: Text("ListTile"),
subtitle: Text("Sample Subtitle. \nSubtitle line 3"),
trailing: Icon(Icons.home),
leading: Icon(Icons.add_box),
isThreeLine: true,
)
Second Solution
SizedBox(
width: 500,
child: new Text(
'Text largeeeeeeeeeeeeeeeeeeeeeee',
//Overflow: TextOverflow.ellipsis will make you large text end with ....
overflow: TextOverflow.ellipsis,
style: new TextStyle(
fontSize: 13.0,
),
),
),
I think you have to use like below code:-
Expanded(
child: Wrap(
direction: Axis.horizontal,
runAlignment: WrapAlignment.start,
children: <Widget>[
getOfferContactAddressView(offer),
],
),
flex: 1,
),
It happens because the Text Widget doesn't know how big the width of the Row.
Please try this code out DartPad to help you find where you went wrong with your code. I still believe, wrapping the Text Widget with Expanded and give overflow property will give what you want right away.
Here's the SS of it:

Is there a way to make a long text fit in a small widget?

I'm making a notes app that contains notes with different sizes. Is there any way to set a max and min height to the note. I don't think the staggered view would help!
SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: notesview,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
if (index < notes.length) {
EdgeInsets.all(10);
return notes[(notes.length - 1) - index];
}
},
),
),
Here's my note Custom widget :
it is generally a button to take the note to the edit page, and for the text whenever i paste a long one it over pass the tile limit, i don't if the problem is in the upper grid view or in the note itself.
class _CustomCardState extends State<CustomCard> {
double font = 13;
var now = new DateTime.now();
var formatter = new DateFormat('yyyy-MM-dd' + ' At ' + 'H:m');
String date;
#override
Widget build(BuildContext context) {
date = formatter.format(now);
return new Card(
color: widget._color,
elevation: 2,
margin: EdgeInsets.all(5),
child: RaisedButton(
splashColor: Colors.blueAccent,
elevation: 10,
onPressed: () {
Navigator.pushReplacement(
context,
new MaterialPageRoute(
builder: (context) =>
EditNote(2, widget.index, widget._title)));
},
color: widget._color,
padding: EdgeInsets.only(left: 5, top: 5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
new Text("${widget._title}" + " => ${widget.index}",
style: new TextStyle(
fontSize: font,
)),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Padding(
padding: EdgeInsets.only(bottom: 5, top: 5, right: 5),
child: Align(
alignment: Alignment(1, 0),
child: Text('$date',
style: new TextStyle(
fontSize: font,
color: Colors.grey,
)),
),
),
],
),
],
),
),
);
}
}
```
You can wrap your widget which contains too long text with SingleChildScrollView
or
String longText = "Longgggggggggggggggggggggggg text";
Tooltip(// onPress to text it shows the full text.
message: longText,
child: Text(
longText.length < 20
? longText
: longText.substring(0, 16) + '...',
// I divide my text in my case 16 length was enough.
style: TextStyle(
fontWeight: FontWeight.bold, color: Colors.white),
),
)

How do I wrap content of PageView so that Indicators appear right below where PageView ends?

How do I wrap content of PageView so that Indicators appear right below where PageView ends ?. Right now PageView fills entire screen and Indicators are at bottom of screen. Below is how each child in PageView is created. In each child I have a Image with default height of 200 and TextView with maxLines of 2 . Though actual height of each child in PageView is half of device screen , it fills entire screen .
final List<Widget> _pages = <Widget>[
new Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Image.network(
'imageurl',
height: 200.0,
fit: BoxFit.fitWidth,
),
new Padding(
padding: EdgeInsets.all(20.0),
child: new Text(
"Order from wide range of restaurants",
maxLines: 2,
style: new TextStyle(fontSize: 25.0, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
)
],
),
new Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Image.network(
'imageurl',
height: 200.0,
fit: BoxFit.fitWidth,
),
new Padding(
padding: EdgeInsets.all(20.0),
child: new Text(
"Order from wide range of restaurants",
maxLines: 2,
style: new TextStyle(fontSize: 25.0, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
],
),
new Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Image.network(
'imageurl',
height: 200.0,
fit: BoxFit.fitWidth,
),
new Padding(
padding: EdgeInsets.all(20.0),
child: new Text(
"Order from wide range of restaurants",
maxLines: 2,
style: new TextStyle(fontSize: 25.0, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
)
],
)
];
Stateful Widget's Builder method
Widget build(BuildContext context) {
return new Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Flexible(
child: new PageView.builder(
physics: new AlwaysScrollableScrollPhysics(),
controller: _controller,
itemCount: _pages.length,
itemBuilder: (BuildContext context, int index) {
return _pages[index % _pages.length];
},
),
fit: FlexFit.loose,
),
new Container(
color: Colors.black,
padding: const EdgeInsets.all(20.0),
child: new Center(
child: new DotsIndicator(
controller: _controller,
itemCount: _pages.length,
onPageSelected: (int page) {
_controller.animateToPage(
page,
duration: _kDuration,
curve: _kCurve,
);
},
),
),
)
],
);
}
Here my solution, as you didn't pasted entire source code, i have omitted dots section
import 'package:flutter/material.dart';
class PageViewIssue extends StatefulWidget {
PageViewIssue({Key key, this.title}) : super(key: key);
static const String routeName = "/PageViewIssue";
final String title;
#override
_PageViewIssueState createState() => new _PageViewIssueState();
}
class _PageViewIssueState extends State<PageViewIssue> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: _getBodyContent(),
floatingActionButton: new FloatingActionButton(
onPressed: _onFloatingActionButtonPressed,
tooltip: 'Add',
child: new Icon(Icons.add),
),
);
}
void _onFloatingActionButtonPressed() {}
List<Widget> _getPageViews() {
final String imgUrl =
"https://images.pexels.com/photos/45201/kitty-cat-kitten-pet-45201.jpeg?auto=compress&cs=tinysrgb&h=320&w=320";
final List<Widget> _pages = <Widget>[
new Center(
child: new Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Center(
child: new Image.network(
imgUrl,
height: 200.0,
fit: BoxFit.fitWidth,
)),
new Padding(
padding: EdgeInsets.all(20.0),
child: new Text(
"Order from wide range of restaurants",
maxLines: 2,
style: new TextStyle(fontSize: 25.0, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
)
],
)),
new Center(
child: new Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Center(
child: new Image.network(
imgUrl,
height: 200.0,
fit: BoxFit.fitWidth,
)),
new Padding(
padding: EdgeInsets.all(20.0),
child: new Text(
"Order from wide range of restaurants",
maxLines: 2,
style: new TextStyle(fontSize: 25.0, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
],
)),
new Center(
child: new Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Center(
child: new Image.network(
imgUrl,
height: 200.0,
fit: BoxFit.fitWidth,
)),
new Padding(
padding: EdgeInsets.all(20.0),
child: new Text(
"Order from wide range of restaurants",
maxLines: 2,
style: new TextStyle(fontSize: 25.0, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
)
],
))
];
return _pages;
}
Widget _getBodyContent() {
var controller = new PageController(initialPage: 0);
var pageView = new PageView(
children: _getPageViews(), pageSnapping: true, controller: controller);
var width = MediaQuery.of(context).size.width;
var expansion1 = new Expanded(
child:
new Container(width: width, child: pageView, color: Colors.green),
flex: 9);
var expansion2 = new Expanded(
child: new Container(
width: width,
child: new Center(child: new Text("Text 2")),
color: Colors.redAccent),
flex: 1);
return new Column(children: <Widget>[expansion1, expansion2]);
}
}
What you were looking for is Constrained Box.

Android TextView's Lines equivalent in flutter

So, I need to make a Text widget to have an exact number of lines. In android studio, I only need to add property android:Lines = 2 and then the TextView will be 2 lines, regardless of how long the text is (if less than 2 lines, then fill the second line with an empty space) and regardless of what's the user's device font size.
The problem is, I have difficulty in replicating such behavior in flutter dynamically. The screenshot below works only on a particular user device's fontSize, since it uses an exact height (32.0).
new Container(
height: 32.0,
child: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
new Expanded(
child: new Text('Curry Rice'), maxLines: 2, overflow: TextOverflow.ellipsis))
])
)
The problem arise when user is increasing / decreasing their device's font size, it will make the fixed-height container's doesn't work anymore.
So, any idea how to replicate android:Lines behavior in flutter Text widget regardless of the user's device text size?
UPDATE: Added comprehensive code for better context
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
// final wordPair = new WordPair.random();
return new MaterialApp(
title: 'App Title',
theme:
new ThemeData(primaryColor: Colors.white, accentColor: Colors.blue),
home: new Scaffold(
appBar: new AppBar(
title: new Text('App Title'),
actions: <Widget>[
new IconButton(icon: new Icon(Icons.list), onPressed: null),
],
),
body: new Center(
child: new Padding(
padding: new EdgeInsets.all(16.0),
child: new TestWidget()))));
}
}
class TestWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new SizedBox(
width: 150.0,
child: new Card(
child: new Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Image.asset(
'assets/thumb2.jpg',
color: Colors.red,
),
new InkWell(
onTap: () {
// _showMenuDescription(context);
},
child: new Padding(
padding: new EdgeInsets.all(8.0),
child: new Column(
children: <Widget>[
new Container(
height: 32.0,
child: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
new Expanded(
child: new Text(
'Curry Rice With Tandoori Chicken and Sunny Side Fried Egg',
maxLines: 2,
overflow: TextOverflow.ellipsis),
)
]),
),
new Container(height: 8.0),
new Row(
children: <Widget>[
new Expanded(
child: new Text(
'BBQ Sauce',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: new TextStyle(color: Colors.black45),
),
),
new Padding(
padding: new EdgeInsets.only(left: 8.0),
child: new Text(
'20,000',
maxLines: 1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.end,
style: new TextStyle(
color: const Color(0xffffa000)),
))
],
),
],
))),
],
),
));
}
}
The problem is that you are setting a finite height for your column. And that height is not enough to display 2 lines with this text style.
Increase the column height or remove that constraint entirely should solve the problem.

Categories

Resources