flutter, How to write precise responsive code from design - flutter

Is there any proper method to write responsive app without any additional package? I usually use MediaQuery but I feel it's not proper enough because it's hard to measure the size from figma since figma use number so i have to calculate it but im afraid everytime i calculate it's not precise and for the font size what is used to make it responsive?
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;

By using Sizer plugin we can make flutter app responsive.
https://pub.dev/packages/sizer
See the example below:
add into pubspec.yaml
dependencies:
flutter:
sdk: flutter
sizer: ^2.0.15
add import statement to code
import 'package:sizer/sizer.dart';
Wrap MaterialApp with ResponsiveSizer widget
main.dart
import 'package:flutter/material.dart';
import 'package:mediaquerydemo/sizer_demo.dart';
import 'package:sizer/sizer.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Sizer(
builder: (context, orientation, deviceType) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SizerDemo(),
);
}
);
}
}
Your actual code where you can show UI
SizerDemo.dart
import 'package:flutter/material.dart';
import 'package:sizer/sizer.dart';
class SizerDemo extends StatelessWidget {
#override
Widget build(BuildContext context) {
final deviceInfo = MediaQuery.of(context);
late var h = deviceInfo.size.height;
late var w = deviceInfo.size.width;
return Scaffold(
appBar: AppBar(
title: Text("Responsive App"),
),
body: deviceInfo.orientation == Orientation.portrait
? SizedBox(
width:30.w,
height: 20.h,
child: Container(
child: Center(child: Text("HELLO", style: TextStyle(fontSize: 20.sp),)),
color: Colors.green,
),
)
: SizedBox(
width:30.w,
height: 20.h,
child: Container(
child: Center(child: Text("World!", style: TextStyle(fontSize: 20.sp),)),
color: Colors.red,
),
)
);
}
}

Related

Dart Flutter display Icons

Im writing my first code and I want to display a Icon, and I try to use the command Icon (Icons.star, color: Colors.red, size: 100, ),. But it doesn't work. Can somebody help me. Thx
Welcome to Stackoverflow.
Try the following code. Your above code is also correct.
Try to check below line in your pubspec.yaml file
flutter:
uses-material-design: true
Refer Flutter Icons
Full Example:
import 'package:flutter/material.dart';
void main() {
runApp(
MyApp(),
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: Icon(
Icons.star,
color: Colors.red,
size: 100,
),
);
}
}
Result screen->
You can also test the code on Dartpad.

Show snack bar to handling missing URL receivers

I used the url_luncher package and it suggests handle the missing URL receiver in case of target platform can not handle the URL.
So I create a function to handle of onTap of CardTile widget and dial the phone number and if the target platform can not handle the request it shows a snake bar to inform the user in UI.
But I have two problems 1) if using an anonymous function I get a runtime error and my code would be wordly and long
Unhandled Exception: No ScaffoldMessenger widget found.
MyApp widgets require a ScaffoldMessenger widget ancestor.
The specific widget that could not find a ScaffoldMessenger ancestor was:
MyApp
The ancestors of this widget were:
[root]
Typically, the ScaffoldMessenger widget is introduced by the MaterialApp at the top of your application widget tree.
if use function name onTap of CardTile widget for example onTap : _urlLauncherFunction(context) I can not pass BuildContext context argument to the function and get a compile error
This expression has a type of 'void' so its value can't be used.
I could not figure out what did wrong so please guide and help me to solve this.
I paste the anonymous function version here
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:url_launcher/url_launcher.dart';
void main() {
runApp(MyApp());
}
final telLaunchErrorSnackBar = SnackBar(
content:
Text('Your device can not handle this url'));
final String _myPhoneNumber = '+9812345678';
//use xml scheme to trigger error otherwise it should be tel
final Uri _telUri = Uri(scheme: 'xml', path: _myPhoneNumber);
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: Column(
children: [
CircleAvatar(
backgroundImage: AssetImage('images/image.jpg'),
),
Card(
child: ListTile(
leading: Icon(
Icons.phone,
),
title: Text(
'00 123 45657',
),
onTap: () async {
String telUri = _telUri.toString();
await canLaunch(telUri)
? await launch(telUri)
: ScaffoldMessenger.of(context)
.showSnackBar(telLaunchErrorSnackBar);
},
),
),
],
),
),
),
);
}
}
When I code as this , flutter throw a error.
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
// home: MyHomePage(title: 'Flutter Demo Home Page'),
home: Scaffold(
body: SafeArea(
child: Container(
alignment: Alignment.center,
child: GestureDetector(
child: Container(
width: 100,
height: 100,
color: Colors.green,
),
onTap: (){
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('content')));
},
),
),
),
),
);
}
}
then I change
...
MaterialApp(
home:Scafford(...),
)
...
to
...
MaterialApp(
home:Home(),
)
...
class Home extends StatelessWidget {
#override
Widget build(BuildContext context){
return Scaffold(...);
}
}
It works.

Is there a way to have width of container bigger than the screen in Flutter?

I have a following container which is actually bigger than the screen. But it seems like flutter doesn't allow the container width to be bigger than the screen.
import 'package:flutter/material.dart';
import 'dart:math' as math;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Test(),
);
}
}
class Test extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
onTap: () {
print("Tapped");
},
child: Transform.rotate(
angle: math.pi / 4,
child: Container(
height: 200,
width: 700,
color: Colors.blue,
),
),
),
);
}
}
I tried to use Transform.scale instead but the GestureDetector doesn't work on the parts of container that is bigger than the screen.
import 'package:flutter/material.dart';
import 'dart:math' as math;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Test(),
);
}
}
class Test extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
onTap: () {
print("Tapped");
},
child: Transform.rotate(
angle: math.pi / 4,
child: Transform(
transform: Matrix4.diagonal3Values(4, 1, 1),
child: Container(
height: 200,
width: 300,
color: Colors.blue,
),
),
),
),
);
}
}
The container will be resized using a resize handle. I'm okay with container not having width greater than screen whilst it's not rotated but when it's rotated I want the container to have width based on resize handle which can be greater than screen. Is there any workaround for this? Any help would be greatly appreciated.
I found a way and that is to use Stack & Positioned:
Stack(
children: [
Positioned(top: 0,
left: 0,
height: 200,
width: 1000,
child: Container(height: 200, width: 1000, color: Colors.blue),
),
],
),
Adjust the height and width of Positioned to limit how much width and height container can have.
From what I know it's not possible to have a container bigger than the screen. You have to take into account that the idea is for the app to run on different sized screens, so I personally don't see the point in giving static values when you can use dynamic ones so it fits different devices' sizes.

Flutter custom layout, decide widget's size based on its child

The understanding constraints article is very useful in understanding how layout works. However, I'm having trouble creating a custom layout that works the way it is explained there.
The article says that size flows up, first we obtain the sizes of the children and then we can decide on our own size based on the sizes of the children.
It seems CustomSingleChildLayout is the way to create a custom layout with one child. In it, based on the article I mentioned above, I would like to get my child's size, and then decide on my own size based on that. However, this seems to be impossible. getSize() method is called with the constraints, therefore I'm supposed to decide on my widgets size based on the constraints that I receive from above. I am able to obtain the child's size in getPositionForChild(), but this called after I give my size in getSize(). It made sense to trigger a relayout at this point, but it seems I'm not allowed to do that from a function called by the layout system.
So, the question is, what's the best way to implement a custom layout, with the layout behavior of constraints flowing down and sizes flowing up, as explained in understanding constraints?
Edit: Here is some code to explain what I really want.
This is the look that I'm going for. Here, I'm manually supplying the width and height of the blue square. I don't want to do that. I want the child's size to determine the size of the square. I want the size to flow up from the text and the blue square should decide on an edge length of max(width, height).
https://codepen.io/gazialankus/pen/abdKyVR
import 'package:flutter/material.dart';
class AppRoot extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo', // Appears in app switcher
theme: ThemeData(
primaryColor: Colors.grey.shade300,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyPage(),
);
}
}
class MyPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
color: Colors.yellow,
child: SizedBox(
width: 180,
height: 180,
child: Container(
color: Colors.blue,
child: AspectRatio(
aspectRatio: 1,
child: Text(
"I want to be in a tight square.",
style: TextStyle(
backgroundColor: Colors.red
),
),
),
),
),
),
),
);
}
}
void main() {
runApp(AppRoot());
}
It was suggested that I could wrap it with Align. Here I tried, but Align grows up. Align's widthFactor and heightFactor make use of the child's size, but can't make it a square that way. Removing the blue Container has no effect:
https://codepen.io/gazialankus/pen/MWKXvpO
import 'package:flutter/material.dart';
class AppRoot extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo', // Appears in app switcher
theme: ThemeData(
primaryColor: Colors.grey.shade300,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyPage(),
);
}
}
class MyPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
color: Colors.yellow,
child: Align(
alignment: Alignment.center,
child: Container(
color: Colors.blue,
child: Text(
"I want to be in a square.",
style: TextStyle(
backgroundColor: Colors.red
),
),
),
),
),
),
);
}
}
void main() {
runApp(AppRoot());
}
Here I'm trying to use AspectRatio to make the square, but it does not care about the child's size and just grows:
https://codepen.io/gazialankus/pen/KKVevXv
import 'package:flutter/material.dart';
class AppRoot extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo', // Appears in app switcher
theme: ThemeData(
primaryColor: Colors.grey.shade300,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyPage(),
);
}
}
class MyPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
color: Colors.yellow,
child: Align(
alignment: Alignment.center,
child: Container(
color: Colors.blue,
child: AspectRatio(
aspectRatio: 1,
child: Text(
"I want to be in a tight square.",
style: TextStyle(
backgroundColor: Colors.red
),
),
),
),
),
),
),
);
}
}
void main() {
runApp(AppRoot());
}
And here I'm trying to do a custom layout, but I don't get to use the child's size to decide on my size. I have to decide on my size before receiving my child's. Trying to force a relayout once I learn my child's size throws an exception, which is at the end of the code. Codepen fails silently.
https://codepen.io/gazialankus/pen/LYGrjxM
import 'package:flutter/material.dart';
class AppRoot extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo', // Appears in app switcher
theme: ThemeData(
primaryColor: Colors.grey.shade300,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyPage(),
);
}
}
class MyPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
color: Colors.yellow,
child: CustomSingleChildLayout(
delegate: MyDelegate(relayout: ValueNotifier<int>(0)),
child: Text(
"I want to be in a square.",
style: TextStyle(
backgroundColor: Colors.red
),
),
),
),
),
);
}
}
class MyDelegate extends SingleChildLayoutDelegate {
ValueNotifier<int> relayout;
MyDelegate({ this.relayout }) : super(relayout: relayout);
#override
bool shouldRelayout(SingleChildLayoutDelegate oldDelegate) {
return desiredWidth == 100;
}
#override
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
print('getConstraintsForChild');
return super.getConstraintsForChild(constraints);
}
double desiredWidth = 300;
#override
Offset getPositionForChild(Size size, Size childSize) {
print('getPositionForChild');
print(size);
print(childSize);
if (size.width > childSize.width) {
desiredWidth = childSize.width;
relayout.value++;
// ^trying to force a relayout
// throws exception, output is given at the bottom in comments
print("RELAYOUT");
}
return super.getPositionForChild(size, childSize);
}
#override
Size getSize(BoxConstraints constraints) {
print('getSize');
return Size(desiredWidth, 100);
}
}
void main() {
runApp(AppRoot());
}
/*
Performing hot reload...
Syncing files to device LG H990...
I/flutter (19850): getSize
I/flutter (19850): getConstraintsForChild
I/flutter (19850): getPositionForChild
I/flutter (19850): Size(300.0, 100.0)
I/flutter (19850): Size(148.0, 16.0)
════════ Exception caught by foundation library ════════════════════════════════════════════════════
The following assertion was thrown while dispatching notifications for ValueNotifier<int>:
'package:flutter/src/rendering/object.dart': Failed assertion: line 1527 pos 12: '_debugCanPerformMutations': is not true.
Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
https://github.com/flutter/flutter/issues/new?template=BUG.md
When the exception was thrown, this was the stack:
#2 RenderObject.markNeedsLayout (package:flutter/src/rendering/object.dart:1527:12)
#3 RenderBox.markNeedsLayout (package:flutter/src/rendering/box.dart:2053:11)
#4 ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:207:21)
#5 ValueNotifier.value= (package:flutter/src/foundation/change_notifier.dart:274:5)
#6 MyDelegate.getPositionForChild (package:m_health/ui/app_root.dart:64:16)
...
The ValueNotifier<int> sending notification was: ValueNotifier<int>#ac2fb(1)
════════════════════════════════════════════════════════════════════════════════════════════════════
Reloaded 2 of 522 libraries in 1,390ms.
I/flutter (19850): RELAYOUT
*/
This should resolve your issue. We remove the constraints passed down by using the UnconstrainedBox. We only need to remove the vertical so that the AspectRatio uses the width constraint. Then we ask the sub-tree to be sized by its intrinsic size. This is, of course, now easy to overflow because it will never wrap and will always use its intrinsic width. However you can wrap the UnconstrainedBox in a FittedBox and it will never overflow and instead scale to fit a parent that might be smaller than it's intrinsic dimension. You might also want to try setting the axis parameter on the UnconstrainedBox to horizontal. Then the IntrinsicWidth will be constrained to the parent width.
import 'package:flutter/material.dart';
class AppRoot extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo', // Appears in app switcher
theme: ThemeData(
primaryColor: Colors.grey.shade300,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyPage(),
);
}
}
class MyPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
color: Colors.yellow,
child: UnconstrainedBox(
child: IntrinsicWidth(
child: Container(
color: Colors.blue,
child: AspectRatio(
aspectRatio: 1,
child: Text(
"I want to be in a tight square.",
style: TextStyle(backgroundColor: Colors.red),
),
),
),
),
),
),
),
);
}
}
void main() {
runApp(AppRoot());
}
Years Later...
The boxy library lets you build widgets where "size flows up". See simple example below which scales a widget while also causing it take more/less space in layout.
If you are allergic to 3rd party libraries and need this functionality, unfortunatly you are stuck with implementing a bunch of low level stuff that seems difficult. It's not anywhere in built in libraries.
import 'package:boxy/boxy.dart';
class Zoom extends StatelessWidget {
const Zoom({required this.child, required this.scale, Key? key})
: super(key: key);
final Widget child;
final double scale;
#override
Widget build(BuildContext context) {
return CustomBoxy(delegate: ZoomLayoutDelegate(scale), children: [
Transform.scale(scale: scale, alignment: Alignment.topLeft, child: child)
]);
}
}
class ZoomLayoutDelegate extends BoxyDelegate {
ZoomLayoutDelegate(this.scale);
double scale;
#override
Size layout() {
// Get Reference To Child
var child = getChild(0);
// Lay out the child with the incoming constraints
var invScale = 1 / scale;
var childConstraints = BoxConstraints(
maxHeight: constraints.maxHeight * invScale,
minHeight: constraints.minHeight * invScale,
maxWidth: constraints.maxWidth * invScale,
minWidth: constraints.minWidth * invScale);
var childSize = child.layout(childConstraints);
child.position(Offset.zero);
// Return the size of this widget which is based on
// the child's size
return Size(
childSize.width * scale, childSize.height * scale
);
}
}

Flag emoji causing differing widths in Flutter

Some flag emoji seem to have extra padding. See the image below:
You can see the Danish flag is taking double width, but the British flag has the correct width.
Here is the complete project code:
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
debugPaintSizeEnabled = true;
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('My App')),
body: BodyWidget(),
),
);
}
}
class BodyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
width: 100,
margin: const EdgeInsets.all(50),
child: Column(
children: <Widget>[
Text('🇩🇰', style: TextStyle(fontSize: 30),),
Text('🇬🇧', style: TextStyle(fontSize: 30),),
],
),
);
}
}
Is this a bug or am I doing something wrong? I want all of the flags to have the same width.
It is making alignment problems for me in a bigger project.
This appear to be a bug rather than a programming problem. Make sure you have upgraded to the latest version of Flutter. As of Flutter 1.12.13+hotfix.6 • channel beta I am no longer seeing this issue.
Related GitHub issues:
https://github.com/flutter/flutter/issues/43230
https://github.com/flutter/flutter/issues/41792