Android TextView's Lines equivalent in flutter - android

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.

Related

Text is placed on the screen but it scroll

android studio 3.6
I need to scroll text only if text does not fit the screen. So if text is placed on the screen it MUST NOT scroll.
snippet:
class MainScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Colors.orange,
body: SafeArea(
child: SingleChildScrollView(
child: new Container(
color: Colors.white,
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: new Column(
children: [
new Text("column_1", style: TextStyle(backgroundColor: Colors.yellow)),
new Text("column_2", style: TextStyle(backgroundColor: Colors.blue)),
new Text("column_3", style: TextStyle(backgroundColor: Colors.black12))])))));
}
}
result
but I can scroll. Why?
It is scrolling as your column sits inside a singleChildScrollView() which enables scrolling by default.
As our container was using a MediaQuery to set its height, the singleChildScrollView() has no vertical space to expand into and thus resulted in the scrolling behaviour.
Instead we should wrap our singleChildScrollView() inside a container and then perform the MediaQuery on that container instead.
Please see the below code:
return new Scaffold(
backgroundColor: Colors.orange,
body: SafeArea(
child: Container(
color: Colors.white,
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: SingleChildScrollView(
child: new Container(
child: new Column(
children: [
new Text(
"column_1",
style: TextStyle(backgroundColor: Colors.yellow),
),
new Text(
"column_2",
style: TextStyle(backgroundColor: Colors.blue),
),
new Text(
"column_3",
style: TextStyle(backgroundColor: Colors.black12),
),
],
),
),
),
),
),
);
Here my solution
class MainScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: SingleChildScrollView(
child: new Column(children: [
new Container(height: 64.0, color: Colors.blue),
new Container(
height: Constants.CARD_VIEW_HEIGHT, color: Colors.yellow),
new Container(height: 356.0, color: Colors.red)
]))));
}
}
ListView is the simplest answer I think;
class MainScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Colors.orange,
body: SafeArea(
child: new Container(
color: Colors.red,
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: new ListView(
shrinkWrap: true,
children: [
Center(child: new Text("column_1", style: TextStyle(backgroundColor: Colors.yellow))),
Center(child: new Text("column_2", style: TextStyle(backgroundColor: Colors.blue))),
Center(child: new Text("column_3", style: TextStyle(backgroundColor: Colors.black12)))]))));
}
}
Maybe use height and width on the ScrollView itself, rather than Column. The Column is taking more space on screen, causing it to scroll.

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

Row,tooltip, one line text

i want to make one line text with additional tooltip text then another text. I've tried like this. But this row overflowing screen size.
Widget tree example
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Color(0xFFE4E4E4),
body: new SingleChildScrollView(
child: new Stack(
children: <Widget>[
_getBackground(),
_getGradient(),
_getContent()
],
),
),
Widget _getContent() {
return Padding(
padding: EdgeInsets.fromLTRB(15, 300, 15, 0),
child: new Column(
children: <Widget>[
new Text(
overviewText,
style: style1,
maxLines: 1,
),
Row(children: <Widget>[
Text("dsdsd4233333333333334dsad "),
TapTooltip(child:Text(" dsds"),message: "dsds342",),
Text(" dsasddddddddddddddsaaaaaaaaaaaasds"),
]));}}
error image

How to set a BackdropFilter using dynamic-sized widgets in Flutter

I have a column: header with text, body with image, footer with text, all widgets have transparent backgrounds.
I want to set the background using a blur of the main image but I keep reaching dead ends.
In some situations this would be straight forward but in my scenario the image could be of any size and aspect ratio, and I need the effect to be wrapped with the column.
Here are my two failed attempts:
Method 1
I have a Stack with the image as the first item, then a BackdropFilter with ImageFilter blur, then my Column.
This works but the Image bleeds out from under the Column because of the image size (which can be any size).
I want to constrain it to the height of my Column.
return Container(
child: Stack(
alignment: AlignmentDirectional.topCenter,
children: <Widget>[
Positioned.fill(child: Image.network(_imgUrl)),
BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
child: Container(
decoration: BoxDecoration(color: Colors.white.withOpacity(0.0)),
)),
Container(
child: Column(
mainAxisSize: MainAxisSize.min,
// https://stackoverflow.com/a/41846093/3429021
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Header(),
BodyPhoto(),
Footer()
],
),
),
],
),
Method 2
Putting the column in a Container with a DecorationImage, which sizes the image perfectly, but I have no way of applying the blur effect.
(_streamItem is my Column wrapped in a container)
body: Container(child: _streamItem,
decoration: new BoxDecoration(image: DecorationImage(
image: NetworkImage(_streamItem.imgUrl),
fit: BoxFit.cover)
)
)
Any ideas?
I think you can consider using Positioned widget - it has width and height property. We can combine these widgets: Positioned > ClipRect > BackdropFilter. Please refer to the Gist: https://gist.github.com/anticafe/dc84cf6488d9defea437b702b13e2749#file-blur_multiple_widgets_with_dynamic_region-dart
Let take a look at this article to see more about BackdropFilter.
You can explicitly give a fix height to the container that contains the image, which will even look better.
In this example I have set three images of very different dimensions and has no problem rendering.
Refer the below code:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('So Help'),
),
body: new ListView(
children: <Widget>[
MyContainer(
imageUrl:
'https://i.dailymail.co.uk/i/pix/2017/01/16/20/332EE38400000578-4125738-image-a-132_1484600112489.jpg',
),
MyContainer(
imageUrl:
'http://static.guim.co.uk/sys-images/Guardian/Pix/pictures/2014/4/11/1397210130748/Spring-Lamb.-Image-shot-2-011.jpg',
),
MyContainer(
imageUrl:
'http://wackymania.com/image/2011/6/vertical-panoramic-photography/vertical-panoramic-photography-15.jpg',
),
],
),
);
}
}
class MyContainer extends StatelessWidget {
final String imageUrl;
MyContainer({#required this.imageUrl});
#override
Widget build(BuildContext context) {
return new Container(
height: 300.0,
child: new Stack(
children: <Widget>[
new Container(
child: Image.network(
this.imageUrl,
width: MediaQuery.of(context).size.width,
fit: BoxFit.cover,
),
),
BackdropFilter(
filter: Dui.ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
child: new Container(
color: Colors.transparent,
),
),
new Container(
height: 300.0,
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width,
),
Padding(
padding: const EdgeInsets.all(20.0),
child: new Text(
'Header',
style: new TextStyle(color: Colors.white),
),
),
new Expanded(
child: Image.network(imageUrl),
),
Padding(
padding: const EdgeInsets.all(20.0),
child: new Text(
'Footer',
style: new TextStyle(color: Colors.white),
),
),
],
),
)
],
),
);
}
}

Flutter layout expanded trouble

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.

Categories

Resources