I`m using width and height params of Container to determine widget size. but the widget is not adaptive if tested on other devices. I came from native android where i used to use density independent pixels(dp) that is adaptive to any screen size. what is the equivalent to dp in flutter ?
I dont want to use MediaQuery every time to calculate screen width and height.
You can use the SizeBox.expand widget to let your widget expand to take the available space regardless of size documentation
SizedBox.expand(
child:MyButton(),
),
And if you want to keep an aspect ratio regardless of screen size you can use the AspectRatio widget documentation
AspectRatio(
aspectRatio: 3/2,
child:MyButton(),
),
If your widgets are just in a row or column and you want to add weights among them to fill the spaces you can use the Expanded widget
Expanded(
flex: 1,//weight for the widget
child: Container(
color: Colors.amber,
height: 100,
),
)
,
You can set the size of your UI widgets this way:
width: 100.0 * MediaQuery.of(context).devicPixelRatio ,
the function MediaQuery.of(context).devicPixelRatio will return the actual number of pixel in each logical pixel, so you'll be sure that the same 100.0 pixel on your test device are typical to those of the user whatever screen density they have.
i applied this way :
class SizeConfig {
static MediaQueryData _mediaQueryData;
static double screenWidth;
static double screenHeight;
static double blockSizeHorizontal;
static double blockSizeVertical;
void init(BuildContext context) {
_mediaQueryData = MediaQuery.of(context);
screenWidth = _mediaQueryData.size.width;
screenHeight = _mediaQueryData.size.height;
blockSizeHorizontal = screenWidth / 100;
blockSizeVertical = screenHeight / 100;
}
}
class HomeScreen extends StatelessWidget { #override Widget
build(BuildContext context) { SizeConfig().init(context); … } }
#override
Widget build(BuildContext context) {
return Center(
child: Container(
height: SizeConfig.blockSizeVertical * 20,
width: SizeConfig.blockSizeHorizontal * 50,
color: Colors.orange,
),
);
}
https://medium.com/flutter-community/flutter-effectively-scale-ui-according-to-different-screen-sizes-2cb7c115ea0a
Related
I have a Container widget inside of a ClipPath which uses a CustomClipper. Everything works fine, I have the desired widget shape.
However, I could not find a way to make a shadow for this custom shaped Widget.
Also, I want to have an outline(border) that follows the edges of this custom widget automatically.
Again no luck. I tried BoxDecoration:border, BoxDecoration:boxShadow, ShapeDecoration:shape, ShapeDecoration:shadows, Material:Elevation, etc..
based on #Bohdan Uhrynovskiy I investigated further and came up with this solution:
CustomPaint(
painter: BoxShadowPainter(),
child: ClipPath(
clipper: MyClipper(), //my CustomClipper
child: Container(), // my widgets inside
)));
class BoxShadowPainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
Path path = Path();
// here are my custom shapes
path.moveTo(size.width, size.height * 0.14);
path.lineTo(size.width, size.height * 1.0);
path.lineTo(size.width - (size.width *0.99) , size.height);
path.close();
canvas.drawShadow(path, Colors.black45, 3.0, false);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
You must need to provide your own custom paths in paint() method of BoxShadowPainter
Look at source code of the library. Feature implemented in this library seems very similar to your task.
You have to implement CustomPainter that draws shadows and borders.
return AspectRatio(
aspectRatio: 1.0,
child: CustomPaint(
painter: BoxShadowPainter(specs, boxShadows),
child: ClipPath(
clipper: Polygon(specs),
child: child,
)));
Was wondering is there a way to control textscalefactor for TextField widget in flutter. Basically I want to limit a text field from growing too large when a user increase font/text size in their devices accessibility settings.
Thanks.
You can wrap it with a MediaQuery with a custom textScaleFactor
Widget build(BuildContext context) {
final mqData = MediaQuery.of(context);
final mqDataNew = mqData.copyWith(textScaleFactor: mqData.textScaleFactor > 5.0 ? 5.0 : mqData.textScaleFactor)
return MediaQuery(data: mqDataNew, child: TextField());
}
The TextField does not need to be a direct child of MediaQuery.
You can set lower and upper bounds for the textScaleFactor of your entire app.
return MaterialApp(
builder: (context, child) {
const lowerLimit = 1.0;
const upperLimit = 1.2;
final mediaQueryData = MediaQuery.of(context);
final scale = mediaQueryData.textScaleFactor.clamp(lowerLimit, upperLimit);
return MediaQuery(
child: child,
data: MediaQuery.of(context).copyWith(textScaleFactor: scale),
);
},
);
Is there any way to mirror your text or any widget in Flutter? Like in Android, I can do
scaleY = -1
scaleX = -1
I couldn't find anything similar to this in Flutter. I tried following but it simply rotates your text by 90˚
Transform.scale(scale: -1.0)
Check out this post, it may have something that could help you.
#override
Widget build(BuildContext context) {
return Transform( // Transform widget
transform: Matrix4.identity()
..setEntry(3, 2, 0.001) // perspective
..rotateX(_offset.dy)
..rotateY(_offset.dx),
alignment: FractionalOffset.center,
child: _defaultApp(context), // <<< set your widget here
);
}
I'm trying to use BoxFit.scaleDown in a FittedBox's fit property to scale the font down in a Text widget to accommodate strings of varying length.
However, the below code will scale down the entire string and make it fit on one line, For the below example, I would like the font scaled down so that the string can fit on two lines (per maxLines property of the Text widget).
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Multi-Line Label Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Multi-Line Label Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
final textStyle = const TextStyle(fontSize: 28.0);
final text =
'Lorem Ipsum is simply dummy text of the printing and typesetting'
'industry. Lorem Ipsum has been the industry\'s standard dummy text'
'ever since the 1500s, when an unknown printer took a galley of type'
'and scrambled it to make a type specimen book.';
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new FittedBox(
fit: BoxFit.scaleDown,
child: new Text(
text,
maxLines: 2,
style: textStyle,
textAlign: TextAlign.center,
),
),
],
),
),
);
}
}
An easy drop-in solution is to use FittedBox with fit: BoxFit.scaleDown:
Container(
width: 100.0,
child: FittedBox(
fit: BoxFit.scaleDown,
// Optionally apply `alignment` to position the text inside the box:
//alignment: Alignment.topRight,
child: SizedBox(
child: Text('\$1,299.99'),
)
)
you can use the auto text package
https://pub.dartlang.org/packages/auto_size_text
after install it, just replace all of 'Text' to 'AutoSizeText' and you will find every things will be good :)
We got 2 ready-to-use solutions to this depending on the constraints you want to have.
1. Scale only
This solution works if you like how the layout looks on some reference screen size, want to treat the text area as a box and just scale up or down the entire box given other sized screens.
Take a reference screen. Lay everything out as intended. Find out the size of the box containing the text (by showing the render tree by pressing 't' during debug for instance). Then wrap the text containing box with a SizedBox of the same size as measured. Then wrap that with your FittedBox.
The restriction is basically that your text is laid out exactly the same way on all screens and you'll have the same aspect ratio for the text box.
2. Multiple references
Given a parent with variable size, first use a LayoutBuilder to get the parent's size during runtime, and then manually adjust the font size in the child text widget to make sure it fits.
The text layout is more fluid and the containing box can have different aspect ratios, but you'd have to check on as many screens sizes as the font size switches you have. Though it's easy to make sure that the text doesn't overflow at any screen size using widget tests
We can also create more complex but automatic means if there are more concrete examples of generalized use cases involving dependent font scaling
This happened in my app:
I solved by calculating the maximum number of chars shown in one line and reducing dynamically the Text FontSize if its string length is greater.
Get the char width of your text
First of all, I calculated the width of every char shown.
For doing that I needed the effective container width and the number of chars shown.
To get the screen width (that actually is the container width), I put my Text widget inside a LayoutBuilder:
new LayoutBuilder(builder: (context, constraint) {
//screen width got from the LayoutBuilder
double maxWidth = constraint.biggest.width;
//I'm going to change this dinamically
double fontSize = 33.0;
//return my widget
return new Text(
_brand.name,
maxLines: 1,
style: new TextStyle(fontSize: fontSize),
);
}
To get the chars shown before a new line, I put a big string in the Text and I manually counted how many chars were shown in one line. I put this value in a const (maxCharInOneLine) and then I was able to calculate the single char width: I divided the maximum witdh by maxCharInOneLine:
new LayoutBuilder(builder: (context, constraint) {
//screen width got from the LayoutBuilder
double maxWidth = constraint.biggest.width;
//chars shown manually counted
const int maxCharInOneLine = 17;
//single char width
int charWidth = (maxWidth / maxCharInOneLine).toInt();
//TO RUN IN DEBUG MODE
print("Char size with this screen and Text's TextStyle: " + charWidth.toString());
...
}
I runned the code above in the debug mode in order to get the charSize value, then I put is in a const and I removed that code that is useless at runtime.
Change dynamically the font
Now, with a constant char width and a variable container width (got from the LayoutBuilder) you can have every time the maximum number of chars that fits in one line.
new LayoutBuilder(builder: (context, constraint) {
const int charWidth=16;
//screen width got from the LayoutBuilder
double maxWidth = constraint.biggest.width;
//dinamically get the char number that fits in one line with this screen
int charsPerLine = (maxWidth / charWidth).toInt();
//if it doesn't fit in a line, reduce the fontSize
double fontSize = (_brand.name.length <= charsPerLine) ? 33.0 : 23.0;
return new Text(
_brand.name,
maxLines: 1,
style: new TextStyle(fontSize: fontSize),
);
}
The result:
My solution is not the best, but it works well in my case.
I'd like to get feedbacks. :)
EDIT Aug 2020: You can now simply use the library AutoSizeText
Just wrap your Text inside a FittedBox widget without setting any fit value.
SizedBox(
width: 10,
child: FittedBox(
child: Text('Your Text'),
),
)
Did you try using the Flexible widget
new Flexible(
child: new Text(
text,
style: textStyle,
textAlign: TextAlign.center,
),
),
The Flutter docs show an example of rotating a "div" by 15 degrees, both for HTML/CSS and Flutter code:
The Flutter code is:
var container = new Container( // gray box
child: new Center(
child: new Transform(
child: new Text(
"Lorem ipsum",
),
alignment: FractionalOffset.center,
transform: new Matrix4.identity()
..rotateZ(15 * 3.1415927 / 180),
),
),
);
And the relevant parts are new Transform and alignment: FractionalOffset.center and transform: new Matrix4.identity()..rotateZ(15 * 3.1415927 / 180)
I'm curious, is there a simpler way to rotate a Container in Flutter? Is there a short-hand for the case of "15 degrees" ?
Thanks!
In mobile apps, I think it's kind of rare to have things start out rotated 15 degrees and just stay there forever. So that may be why Flutter's support for rotation is better if you're planning to adjust the rotation over time.
It feels like overkill, but a RotationTransition with an AlwaysStoppedAnimation would accomplish exactly what you want.
new RotationTransition(
turns: new AlwaysStoppedAnimation(15 / 360),
child: new Text("Lorem ipsum"),
)
If you want to rotate something 90, 180, or 270 degrees, you can use a RotatedBox.
new RotatedBox(
quarterTurns: 1,
child: new Text("Lorem ipsum")
)
You can use Transform.rotate to rotate your widget. I used Text and rotated it with 45˚ (π/4)
Example:
import 'dart:math' as math;
Transform.rotate(
angle: -math.pi / 4,
child: Text('Text'),
)
If you are working with a canvas (as in a CustomPaint widget), you can rotate 15 degrees like this:
import 'dart:math' as math;
class MyPainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
canvas.save();
// rotate the canvas
final degrees = 15;
final radians = degrees * math.pi / 180;
canvas.rotate(radians);
// draw the text
final textStyle = TextStyle(color: Colors.black, fontSize: 30);
final textSpan = TextSpan(text: 'Hello, world.', style: textStyle);
TextPainter(text: textSpan, textDirection: TextDirection.ltr)
..layout(minWidth: 0, maxWidth: size.width)
..paint(canvas, Offset(0, 0));
canvas.restore();
}
#override
bool shouldRepaint(CustomPainter old) {
return false;
}
}
However, if you are doing something simple then I would use a RotatedBox or Transform.rotate as suggested by the other answers.
There is Two Main Flutter Widget available for this functionality, RotationTransition and Transform.rotate
another supported option is RotatedBox but this rotate widget only
supports quarter turns, which means they support vertical and only horizontal orientation.
and if you rotate already created widgets like Container so for the container by transformAlignmentyou can rotate widget.
RotationTransition: which animates the rotation of a widget, mainly we prefer when we need rotation with animation transition.https://api.flutter.dev/flutter/widgets/RotationTransition-class.html
Transform.rotate: which applies a rotation paint effect, they Create a widget that transforms its child using a rotation around the center.
RotationTransition Widget example:-
RotationTransition(
turns: AlwaysStoppedAnimation(15 / 360),
child: Text("flutter is awesome")
)
Transform.rotate Widget example :-
Transform.rotate(
angle: 15 * math.pi / 180,
child: Text("flutter is awesome")
)
Container(
decoration: BoxDecoration(borderRadius: BorderRadius.circular(50), color: Color(0xffF6F8FF),),
width: MediaQuery.of(context).size.width*0.6,
height: MediaQuery.of(context).size.height*0.4,
alignment:
new Alignment(0, 0),
transform:
new Matrix4.translationValues(MediaQuery.of(context).size.width * 0.55, -250.0, 0.0)
..rotateZ(28 * 3.1415927 / 180),
),