I'm getting different results of the same screen when run on different phone sizes:
The second phone screen is my desired outcome. Using expanded initially helped me solve an issue with the first phone screen (where there was an extra space below the green bar). Later I realized that I was getting overflow on the second phone screen. Thus, I solved the overflow by using SingleChildScrollView. However that somehow cause the first phone screen to have the issue of the extra space again.
Code:
final quizBottomContentText = Container(
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.only(left:30.0, right:30.0, top: 30.0, bottom: 30),
child: Text(
questions[questionNum].title,
style: TextStyle(fontSize: 18.0),
)
);
final quizOptions = Container(
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.only(bottom: 20.0),
child: Center(
child: Column(
children: questions[questionNum].options.map<Widget>(
(option) => SimpleRoundButton(
backgroundColor: Color.fromRGBO(58, 66, 86, 1.0),
buttonText: Text(option,
style: TextStyle(
color: Colors.white
),
),
textColor: Colors.white,
onPressed: (){},
),
).toList(),
)
)
);
final countdown = CountdownWidget(
width: MediaQuery.of(context).size.width,
duration: 20,
triviaState: triviaState,
);
final quizBottomContent = Expanded(
child: SingleChildScrollView(
child: Container(
width: MediaQuery.of(context).size.width,
child: Column(
children: <Widget>[quizBottomContentText, quizOptions, countdown],
),
)
)
);
Because you're app is not responsive. See, you're passing size in a hard coded way
eg: padding: EdgeInsets.only(bottom: 20.0)
What this means? Mean that in your emulator, you'll get a result, maybe is what you expect, but in another device, maybe in a iPhone Xs Max, the result is diferent, so, what can you do?
You'll have two options here, the first, use the MediaQuery component. I'll show you how and why I use the way I use for a better understanding.
In Flutter, we have the MediaQuery component with a lot of propierty, one of them, is this: MediaQuery.of(context).size.width (Which gets your device's full width size). Everything fine till here, right? If you print this in diferent devices, you'll get diferente results, which means that a Padding with 20 from left/right will be different in both devices.
I made a calculation to kinda ''hack'' this and make it responsive, get this:
MediaQuery.of(context).size.width and divide by 400. Why 400? Me and a friend discovered this and when we divided, we've got a value almost next to 1 in very different devices, so, if you get the result (eg 1.5) and multiplies by 20, you'll make your app kinda of responsive. It's a way, the second way it's to use the LayoutBuilder which need a context and a constraints as parameters.
With constraints, you can manipulate to show differents model designs in differents devices, like, buildConventionalDesig for devices with width less than 400, an example, or buildBiggerDesign for a bigger phone, like iPhone Xs Max.
There's an article that you could be your reference to help you, check it:
Build Response UIs in Flutter. It doesn't cover this trick with MediaQuery, but maybe you can get a new insight.
Hope this have helped.
Related
This is my Flutter project.
Apparently ListView has a built-in mechanism to render children only if (ListView thinks) it needs to be rendered.
ListView(
children: List.generate(
1000,
(index) => SizedOverflowBox(
alignment: Alignment.bottomLeft,
size: const Size(double.infinity, 50),
child: Container(
width: 100,
height: 1000,
color: const Color.fromARGB(15, 255, 0, 0),
margin: EdgeInsets.only(left: 20 * (index % 20)),
child: Text(index.toString()),
alignment: Alignment.bottomLeft,
)),
))
In this example, although all child widgets are built (ListView.builder would delay it on demand), children below the bottom edge of screen are not rendered, even if they're actually contacting the screen area due to its overflow configuration to the negative y direction (See the image below: you can find the red boxes for i > 11 are not rendered at all).
I couldn't find which part of flutter library source code handles this kind of "necessity" check.
Q1: Where is it?
Q2: How can I force ListView to render children that it thinks needn't be rendered?
Things like cacheExtent and KeepAlive are partially related to this problem, but not the direct answer as far as I know.
I have tried using Expanded and Flexible and none of it is working.I am not able to understand why.Also is this the best way to increase the size of image, because I want that my images looks size looks same across all devices.
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
width: size.width * 0.4,
height: size.width * 0.6,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('images/brushOne.jpg'),
fit: BoxFit.fill)),
),
Padding(
padding: const EdgeInsets.only(top: 40.0),
child: Text(
'Thank you for letting me do what I love, your support is contagious If I could put all 10,000 of you in a room and give you all a hug I WOULD. Your support makes my heart grow and glow. Thank you for helping me create a business and a family.I love you all 🌈',
),
),
],
)
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
width: MediaQuery.of(context).size.width * 0.4,
height: MediaQuery.of(context).size.width * 0.6,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images.jpg'),
fit: BoxFit.fill)),
),
Container(
child: Container(
padding: EdgeInsets.only(top: 40),
child: Text(
'Thank you for letting me do what I love, your support is contagious If I could put all 10,000 of you in a room and give you all a hug I WOULD. Your support makes my heart grow and glow. Thank you for helping me create a business and a family.I love you all 🌈',
),
width: MediaQuery.of(context).size.width * 0.6,
),
),
],
)
You set the first container to 40%.
width: MediaQuery.of(context).size.width * 0.4
If you set the width of the second container to 60%,
width: MediaQuery.of(context).size.width * 0.6
the problem will be solved. You can use sizedbox() to leave space between two containers if you want.
Wrap the padding widget fixed the problem:
The difference is the constraints passed to Text.
With Expanded, the constraints is fixed size:
Without Expanded, the constraints is infinity:
I suggest you to use ,
SizedBox(
width: 100,
child: Text(
"Thank you for letting me do what I love, your support is contagious If I could put all 10,000 of you in a room and give you all a hug I WOULD. Your support makes my heart grow and glow. Thank you for helping me create a business and a family.I love you all 🌈",
maxLines: 5,
overflow: TextOverflow.ellipsis,
),
),
Expanded should work as demoed in this quick mock-up here.
Like Engin has mentioned MediaQuery is your best bet for scaling contents to a device's screen, but if you're applying MediaQuery to both sections of the Row, you'll have to update both sizes each time you choose to resize one element. This is accruing unnecessary technical debt that will compound if you ever choose to add additional elements to the Row in the future. Expanded on the other hand will take up the remaining space without the need to manually calculate sizes each time you make a change to UI elements.
I need to customize the App bar like below, with rounded style and it floats on top of all other widgets:
Its similar to Google Map app. What would be the best way to achieve this customization?
Thanks for any advice or guides to approach this...
You can use Stack widget to display a widget on top of another widget (page content in your example). So use Stack to place search / app bar on top of main app content and customize as your needs.
You can check this youtube video to learn more about Stack widget.
Here's sample code, you can place inside Scaffold.
Stack(
children: <Widget>[
// this will be filled entire screen
Positioned.fill(child: Image.network('https://i.imgur.com/SJGDZUp.png')),
// this will be placed top of the screen with 15 points distance
Positioned(
top: 15,
left: 15,
right: 15,
// using SafeArea to avoid device frames (for example notch in iPhones)
child: SafeArea(
child: Container(
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
color: Colors.black,
),
child: Text('Search...', style: TextStyle(color: Colors.white)),
),
),
),
],
),
DISCLAIMER: I haven't tested the code, so, it may contain syntax issues or typos
I have a custom build widget for grid view, in which i am either sending Icon or image to display along with Text (label). Now when i send icon i can display the test below icon, but when i am trying image i am not sure if the below approach is correct to display text or not, i am trying to put EdgeInsets in the container. I think it might fail due to pixel overload, but in my emulator, it seems to be fine.. Is there any better option for this scenario or the approach I am following is ok?
if (image != null) ...[
Container(
margin: EdgeInsets.only(top:150.0),
),
] else ...[
child ?? Container(),
],
Text('$label',
style: TextStyle(
color: AppColors.lightBlue,
fontSize: 20,
),),
If I am getting your problem well, then the solution is to use Alignment Class Flutter, in the Container. What this will do, is it allows the child of the Container to be aligned the way we want to align it. Since your requirement is to align the text at the bottom center, hence we would use the Alignment property, Alignment.bottomCenter.
Please Note: This will tell you how to align the content which will not be disturbed as per the device size, with a background image
SOLUTION 1 [EFFICIENT]
Container(
height: MediaQuery.of(context).size.height * 0.3, // ignore this, cos I am giving height to the container
width: MediaQuery.of(context).size.width * 0.5, // ignore this, cos I am giving width to the container
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage('https://i.pinimg.com/originals/0c/96/b1/0c96b19dc89ffdaa7ff737cfc04a095f.png')
)
),
alignment: Alignment.bottomCenter, // This aligns the child of the container
child: Padding(
padding: EdgeInsets.only(bottom: 10.0), //some spacing to the child from bottom
child: Text('Hello', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))
)
)
The output would look like this now:
You can check this piece of code in any of the device, and it will show up just fine.
SOLUTION 2 [NOT RECOMMENDED]
Now, if you really want the margin, there is a cleaner way to do it, and that is using MediaQuery, as you can see in the above code also for giving out height and width.
Now, the question arises, what MediaQuery is, you can find it here, or in a simpler statement, it takes care of the size of the device. Now, whenever, we are concerned about the size of the device with the content alignment, we can use MediaQuery, and what it does, is it will adjust the margin/height/width/padding etc according to the Device size, and will look the same everywhere
How we can do that, I will just use your code only, and since you want the text to come at the bottom with the use of margin. Here, how you can do that
Container(
height: MediaQuery.of(context).size.height * 0.3,
width: MediaQuery.of(context).size.width * 0.5,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage('https://i.pinimg.com/originals/0c/96/b1/0c96b19dc89ffdaa7ff737cfc04a095f.png')
)
),
child: Container(
margin: EdgeInsets.only(top: MediaQuery.of(context).size.height * 0.25),
child: Text('Hello', textAlign: TextAlign.center, style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))
)
)
OUTPUT
MediaQuery.of(context).size.height = device height, and when we multiply, it does the math according to the device, and align the content. Similarly for MediaQuery.of(context).size.width= device width
I would suggest SOLUTION 1 only, since it is clean, and would not let you do a lot in nested child. I hope that clears your doubt. Let me know. Thanks :)
Good Evening,
I have been searching for many hours and can not find a solution.
I have set a full screen image and with a Stack I have Positioned several GestureDetectors.
I have succeeded to be able to press on a GestureDetector and call a Function.
The problem is that when the screen size changes, either to a new or older phone then the Image responds and covers the full screen but the Positioned() of course stay at the same place, thus the Image mappings are not correct any more.
Is there a way to make the Positioned be responsive? or Maybe a total different way achieving the desired outcome?
Please help me :)
class Overview extends StatelessWidget {
#override
Widget build(BuildContext context) {
double sh = MediaQuery.of(context).size.height;
double sw = MediaQuery.of(context).size.width;
return Scaffold(
drawer: AppDrawer(),
body: Stack(
children: <Widget>[
Container(
height: sh,
width: sw,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/ang7.png'),
fit: BoxFit.cover)),
),
Positioned(
left: 10,
top: 50,
child: IconButton(
icon: Icon(Icons.menu),
iconSize: 30,
color: Colors.white,
onPressed: () => Scaffold.of(context).openDrawer(),
),
Positioned(
left: left,
top: top,
child: GestureDetector(
// child: Icon(Icons.add_circle),
onTap: () => Navigator.push(context, MaterialPageRoute(
builder: (context) {
return Amenities(
tText[page][0],
tText[page][1],
tText[page][2],
);
},
)),
child: Container(
height: 35,
width: 50,
color: Colors.blue,
),
));
),
Posting my comment as an answer just in case it works and there are no better answers provided. Please up vote and mark as answered if it does. :-)
You could try experimenting with MediaQuery.of to determine the size of the device (height and width) and then use those values to scale the Positioned widgets position parameters up or down from your 'baseline' sizes. In theory that should (may) match how the background image has been scaled. Would probably need to scale the size of the Positioned widgets as well.
Update regarding your comment:
Not really. What I mean is that you would need to run MediaQuery.of on the device that you are happy with the UI layout, and record that device's width and height. You then use this width and height in your app and compare these 'baseline' values with what values you get when you run the app on other devices.
So:
Divide other-device-width by baseline-device-width to get your width scaling factor.
Divide other-device-height by baseline-device-height to get your height scaling factor.
Then use these scaling factors to 'scale' the Positioned widgets width (positioned-widget-width multiplied by width-scaling-factor) and height (positioned-widget-height multiplied by height-scaling-factor) and position on the screen (you would have to play around with the positioning values).
Sounds messy but it is just a bit of simple math.
Like I say, might not work or might not be the most elegant solution. There are so many different devices out there you will never really be able to completely test this. Might need to rethink you UI. Maybe some other people have ideas around that.