How to make a image fit in 1/3rd of screen in flutter - flutter

I want to create a layout like this where the users will select and image and it'll take them to another screen like below and the selected image will take about one-third portion of the screen. The rest 2/3rd will be used as a canvas as you can see.
Unfortunately this is what I've got till now:
Here's the entire code:
import 'package:flutter/material.dart';
import 'package:flutter_app/src/components/Canvas.dart';
import 'package:flutter_app/src/components/DrawingArea.dart';
class DetailsPage extends StatelessWidget {
List<DrawingArea> points = [];
final String imagePath;
final String title;
final int index;
DetailsPage(
{#required this.imagePath, #required this.title, #required this.index});
// Display the selected image
Widget displayImage(String imagePath) {
return Container(
child: Expanded(
child: Hero(
tag: 'logo$index',
child: Container(
margin: EdgeInsets.only(top: 20, right: 50),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(30),
bottomRight: Radius.circular(30)),
image: DecorationImage(
image: AssetImage(imagePath),
fit: BoxFit.cover,
),
),
),
),
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("This will be the canvas"),
),
body: Container(
child: Column(
children: <Widget>[
displayImage(imagePath),
],
),
),
);
}
}

You have to set height of container which you can set by using MediaQuery as shown below:
Past this function in your code
Widget displayImage(String imagePath) {
return Container(
height: MediaQuery.of(context).size.height / 3,
child: Expanded(
child: Hero(
tag: 'logo$index',
child: Container(
margin: EdgeInsets.only(top: 20, right: 50),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(30),
bottomRight: Radius.circular(30)),
image: DecorationImage(
image: AssetImage(imagePath),
fit: BoxFit.cover,
),
),
),
),
),
);
}

You can use Flexible: https://api.flutter.dev/flutter/widgets/Flexible-class.html
https://youtu.be/CI7x0mAZiY0
Column(children: [
Flexible(
flex: 1
child: Container(color: Colors.blue),
Flexible(
flex: 2
child: Container(color: Colors.green),
),
]);

Not sure if I got you right. Is this what you're trying to get?
Column(
children: [
Expanded(
flex: 1,
child: Image.asset(
'your_image_asset',
fit: BoxFit.cover,
),
),
Expanded(
flex: 2,
child: Placeholder(),
),
],
)

Related

Center Image In Container's child column flutter

I want to align image in center in column and increase size of image.
My desired look
This is what I got by using code
Here is my code:
class BigRoundedContainer extends StatelessWidget {
final String image, text;
const BigRoundedContainer({Key? key, required this.image, required this.text}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
width: 145.w,
height: 145.h,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(Dimensions.radius40),
color: Colors.white,
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.black.withOpacity(0.5),
blurRadius: Dimensions.radius10,
offset: const Offset(0.0, 10),
)
],
),
child: Padding(
padding: EdgeInsets.only(bottom: Dimensions.height10),
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Expanded(
child: Image.asset(
image,
color: AppColors.fIconsAndTextColor,
),
),
SmallText(text: text, size: Dimensions.height20),
]),
),
);
}
}
This is how im using BigRoundedContainer
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
BigRoundedContainer(
image: "assets/images/agency.png",
text: LanguageStringKeys.instance.agency.tr,
),
BigRoundedContainer(
image: "assets/images/freelancer.png",
text: LanguageStringKeys.instance.freelancer.tr,
),
),
],
While you are using Expanded, you can skip size params on Image. Include fit: BoxFit.cover
Expanded(
child: Image.asset(
image,
fit: BoxFit.cover,
),
),
try this:
Expanded(
child: Align(
alignment: Alignment.bottomCenter,
child: Image.asset(
image,
color: AppColors.fIconsAndTextColor,
),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: SmallText(text: text, size: Dimensions.height20),,
)
you can play with SmallText's padding to get your desire space.
Give padding all in parent container then give image width height and margin between the text

Absolute positioning on the screen, and overlay of image of to the top portion of app

Absolute positioning on scaffold/screen.
1 - The white container in the 1st photo - how to align this as an absolute position on the bottom of the screen / how is it done as the best method?
2 - The container has to be overlaid on the top of the image.
Tried to give absolute positioning using stack on the screen/scaffold, didn't work.
Use the following code:
class SampleWidget extends StatefulWidget {
const SampleWidget({super.key});
#override
State<SampleWidget> createState() => _SampleWidgetState();
}
class _SampleWidgetState extends State<SampleWidget> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: const BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(
'https://images.fineartamerica.com/images/artworkimages/mediumlarge/1/mountains-valleys-and-clouds-vertical-panorama-rick-deacon.jpg'))),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const SizedBox(
height: 400,
),
Expanded(
child: Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 20.0),
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20.0),
topRight: Radius.circular(20.0),
),
),
child: const Center(
child: Text(
"The new adventure begin here",
style: TextStyle(fontSize: 22),
)),
),
),
],
),
),
);
}
}
Output:

Vote progress bar in Flutter

How do I create a voting progress bar in Flutter that starts from both end, where green extends from left side in green color if people voted YES and red extends from right side in green color if people voted NO . I have tried to find in Pub dev and can't find something like this. Would like to know how to create one as most of the tutorial I found, the progress bar only extends from one side instead of both sides. Something like this to clarify what I want to do
Maybe like this :
Widget _voteWidget(int yesVote, int noVote) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: 20,
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(30)),
),
child: Row(
children: [
Flexible(
flex: yesVote,
child: Container(
decoration: const BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.only(topLeft: Radius.circular(30), bottomLeft: Radius.circular(30)),
),
),
),
Flexible(
flex: noVote,
child: Container(
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.only(topRight: Radius.circular(30), bottomRight: Radius.circular(30)),
),
),
),
],
),
),
SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('${yesVote.toString()} Yes'),
Text('${noVote.toString()} Yes'),
],
)
],
),
);
}
use linearprogress indicator , if you want to add any decoration, just wrap with your custom widget
class MyWidget extends StatelessWidget {
int yes = 8736;
int no = 520;
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(20),
child: LinearProgressIndicator(
minHeight: 20,
color: Colors.green,
backgroundColor: Colors.red,
value: (yes / (yes + no)),
));
}
}
result:

How to make a container take up the height of the parent widget?

I have a card layout which looks like the following:
The code for it it as follows:
Card(
color: tap ? Colors.green : Colors.white,
margin: EdgeInsets.symmetric(horizontal: 5.0, vertical: 3.0),
child: Container(
child: Row(
children: [
**Container(
height: !widget.menuItem.image.endsWith('/')? 70.0 : 0.0,
width: !widget.menuItem.image.endsWith('/')? 70.0 : 0.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(topLeft: Radius.circular(5.0), topRight: Radius.circular(5.0)),
image: DecorationImage(
image: NetworkImage(widget.menuItem.image),
fit: BoxFit.cover
),
),**
),
SizedBox(
width: 8.0,
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
Text(
howManyThere() > 0 ? "${howManyThere()} x " : '',
style: addBTNHighlight,
),
Expanded(
child: Text(
widget.menuItem.item_name,
overflow: TextOverflow.ellipsis,
style: tap ? TitleWhite18Bold : Title18bold,
),
),
],
),
Container(
child: Text(
widget.menuItem.description,
//overflow: TextOverflow.ellipsis,
style: tap ? SubTitleWhite13 : SubTitle13,
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Text(
"£" + num.parse(widget.menuItem.price).toStringAsFixed(2),
style: tap ? priceHighlightSelected : priceHighlight,
),
),
],
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 30.0, vertical: 6.0),
decoration: BoxDecoration(),
child: Text("ADD", style: tap ? priceHighlightWhite : addBTNHighlight)),
],
),
],
),
),
)
As you can see that I am almost there with my desired layout but with one small issue which can be seen in first and last item. Because of the given width and height of the image container, it leaves a gap on top and bottom.
What I would like to happen is that the width to stay the same but the height to be flexible and adjust with the height of the card itself. Is it possible?
When I remove the height attribute of the container with the image, I get a blank space of the image
UPDATE: I tried LayoutBuilder as well but without any Luck, it throws 'Incorrect use of ParentWidget' Exception. The code I used is as follows:
Row(
children: [
widget.menuItem.image.endsWith('/')
? Container()
: **LayoutBuilder(
builder: (context, constraints){
return Container(
width: 70.0,
height: constraints.minHeight,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5.0)),
image: DecorationImage(
image: NetworkImage(widget.menuItem.image),
fit: BoxFit.cover
),
),
);
}**
),
Try this :
Column(
children: [
Expanded(
child: Container(
width: !widget.menuItem.image.endsWith('/')? 70.0 : 0.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(topLeft: Radius.circular(5.0), topRight: Radius.circular(5.0)),
image: DecorationImage(
image: NetworkImage(widget.menuItem.image),
fit: BoxFit.cover
),
),
),
),
],
),
The problem here is your description text which overflow your desired max height. You can try to constraint your Container with a height: 70.0 or you can add to your Text widget the property maxLines: 1.
LayoutBuilder only give you constraints that parent pass to child, which is something like 100 < width < 200, 300 < height < infinity. At this point the height of all texts on the right are not determined yet, so it is impossible to determined the height of image base on that.
One way to do this is to assign key to each list item, get item heights after everything is layout, the rebuild with those fixed height. This will become a two pass process and is less efficient.
The official solution to this is IntrinsicHeight, which conceptually do the same thing, but in a more optimized way.
Here is a minimum example:
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: App(),
),
);
}
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: 10,
itemBuilder: (context, index) {
return Card(
clipBehavior: Clip.antiAliasWithSaveLayer,
// This is where magic happened
child: IntrinsicHeight(
child: Row(
children: [
Container(
width: 100,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage('https://cataas.com/cat'),
fit: BoxFit.cover,
),
),
),
Expanded(
child: Text(
// just put some random text with dynamic height
'Text\n' * (Random().nextInt(4) + 4),
),
),
],
),
),
);
},
),
);
}
}
Remove height constraints, then
Try replacing fit: BoxFit.cover with BoxFit.fitHeight or BoxFit.fill.
In order to fill the image with card height you can give container required height and wrap the Image widget in AspectRatio widget with ratio 1. This will always helps image widget to fill parent card height. Have a look in below code.
Parent Widget
Container(
margin: EdgeInsets.only(bottom: 12),
height: 100,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
AspectRatio(
aspectRatio: 1,
child: _pictureWidget(widget.menuItem.image),
),
/// Replace `Container` with the needed widget
Expanded(child: Container()),
],
),
)
_pictureWidget
Widget _picture(String url) {
return _pictureWidget(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(5.0), topRight: Radius.circular(5.0)),
child: Image.network(
url != null ? url : "",
fit: BoxFit.cover,
loadingBuilder: (BuildContext context, Widget child,
ImageChunkEvent loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes
: null,
),
);
},
),
);
}

Designing a Flutter button with image and text

If I just throw together an image and some text in a rounded-corner rectangle, the user will not know that they can "click here". But I don't have to bake my own solution. InkWell covers this scenario, complete with a nice shadow.
I am positioning
a custom clickable icon using the
InkWell
class, itself requiring to be inside an
Ink
instance.
import 'package:flutter/material.dart';
const boat_url = ('https://upload.wikimedia.org/wikipedia/commons/thumb/0/05/'
'Segelboot_Bodensee_Mainau_%28Foto_Hilarmont%29.JPG/'
'182px-Segelboot_Bodensee_Mainau_%28Foto_Hilarmont%29.JPG');
void main() {
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Image',
home: Scaffold(
backgroundColor: Colors.grey,
body: MyImage(),
)));
}
class MyImage extends StatelessWidget {
MyImage({Key key,});
#override
Widget build(BuildContext context) {
Size sz = MediaQuery.of(context).size * 0.4;
double border = 4;
return Stack(children: [
Positioned(
top: 100,
left: 100,
width: sz.width,
height: sz.height,
child: Material(
child: Ink(
decoration: BoxDecoration(
boxShadow: <BoxShadow>[
new BoxShadow(
color: Colors.red,
blurRadius: 10.0,
offset: new Offset(30.0, 20.0),
),
],
border: Border.all(
color: Colors.blue,
width: border,
),
borderRadius: BorderRadius.circular(40),
),
child: InkWell(
onTap: (){/*..*/},
child: Column(
children: [
Container(
height: 4 * (sz.height - 2 * border) / 5,
alignment: Alignment.center,
child: Image.network(boat_url),
),
Container(
height: (sz.height - 2 * border) / 5,
child: FittedBox(
clipBehavior: Clip.antiAlias,
alignment: Alignment.centerLeft,
fit: BoxFit.fitHeight,
child: Text('A long descriptive sentence')),
)
],
)),
),
)),
]);
}
}
1- I'm not actually using Colors.white, and the Scaffold itself has
backgroundColor: Colors.grey. Where is the white background coming from?
2- When we talk of a "shadow", I'm expecting the shadow to be behind
the ink/inkwell object. Why does the shadow appear in front?
Related: 1
That white color is from the Material widget, to remove that you can use type param.
Material(
type: MaterialType.transparency,
child: Container(),
);
Here is code to achieve the custom button
Video link
Scaffold(
backgroundColor: Colors.blueGrey,
body: SafeArea(
child: Container(
decoration: BoxDecoration(
color: Colors.green.shade200,
border: Border.all(color: Colors.green),
borderRadius: BorderRadius.circular(5),
boxShadow: [
BoxShadow(
blurRadius: 5,
spreadRadius: 2,
color: Colors.black26,
)
]),
margin: const EdgeInsets.all(20),
child: Material(
type: MaterialType.transparency,
child: InkWell(
onTap: () {},
splashColor: Colors.black26,
child: IntrinsicHeight(
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(mainAxisSize: MainAxisSize.min, children: [
Image.asset(
'assets/images/marked_tyre_base.png',
fit: BoxFit.cover,
width: 80,
height: 80,
),
const SizedBox(
height: 10,
),
Text(
'Tyre 1',
style: TextStyle(color: Colors.white),
)
]),
),
),
),
),
),
),
);
Screenshot:
Create a class, ImageTextButton:
class ImageTextButton extends StatelessWidget {
final VoidCallback onPressed;
final ImageProvider image;
final double imageHeight;
final double radius;
final Widget text;
ImageTextButton({
#required this.onPressed,
#required this.image,
this.imageHeight = 200,
this.radius = 28,
#required this.text,
});
#override
Widget build(BuildContext context) {
return Card(
elevation: 8,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(radius)),
clipBehavior: Clip.hardEdge,
child: InkWell(
onTap: onPressed,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Ink.image(
image: image,
height: imageHeight,
fit: BoxFit.cover,
),
SizedBox(height: 6),
text,
SizedBox(height: 6),
],
),
),
);
}
}
Usage:
ImageTextButton(
onPressed: () {},
image: AssetImage('chocolate_image'),
text: Text('Chocolate'),
)