Image comparator side by side shower in flutter [duplicate] - flutter

This question already has answers here:
How to make Before-After image slider view in Flutter
(2 answers)
Closed 9 months ago.
I want to make to make one page in flutter, that take two images and give the possibility to compare them, having one slider that make one image grow in weight.
But i had problem fixing the image size from the changing container, so the question is: How i can fix the size to take all the weight but the container change his weight without change the image visualization?
After the code i add one snapshot of the working code, but like you can see that they are the same image, and i have the slider in the middle the image should be the "same". At this moment the image is modify based in the container size.
class ImageComparePage extends StatefulWidget {
late ImageOfDimension imageOne;
late ImageOfDimension imageTwo;
ImageComparePage({required this.imageOne, required this.imageTwo});
#override
_ImageComparePageState createState() => _ImageComparePageState();
}
class _ImageComparePageState extends State<ImageComparePage> {
double opacityValue = 0.5;
#override
void initState() {}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
FlutterI18n.translate(context, "image_compare.title"),
),
),
body: Column(
children: [
Slider(
value: opacityValue,
min: 0,
max: 1,
onChanged: (rating) {
setState(() {
opacityValue = rating;
print(opacityValue);
});
},
),
Expanded(
child: Stack(
fit: StackFit.passthrough,
children: [
imageTwoToCompareWithOpacity(),
imageOneToCompare(),
],
),
)
],
),
);
}
Widget imageOneToCompare() {
return Container(
width: MediaQuery.of(context).size.width * opacityValue,
foregroundDecoration: BoxDecoration(
image: DecorationImage(
image: FileImage(File(widget.imageOne.path)), fit: BoxFit.cover),
),
);
}
Widget imageTwoToCompareWithOpacity() {
return Container(
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
image: DecorationImage(
// colorFilter: new ColorFilter.mode(
// Colors.black.withOpacity(opacityValue), BlendMode.dstATop),
image: FileImage(File(widget.imageTwo.path)),
fit: BoxFit.cover),
),
);
}
}

Related

Centered layout with Stack and AnimatedSwitcher widget

I am struggling to set up the correct layout for my composite widgets.
It is the Stack widget containing two images each wrapped in the corresponding widget which are applying some visual effects on the images.
The images are supposed to change every couple of seconds and then I am using the AnimatedSwitcher to animate the fading transition between them.
This is how it looks now:
The result I want to achieve should look like this:
Here is the source code of the corresponding widget:
import 'dart:ui';
import 'package:demo_flutter_fading_images/themes/style.dart';
import 'package:flutter/material.dart';
class ImagesStack extends StatefulWidget {
final String imagePath;
const ImagesStack({required Key key, required this.imagePath}) : super(key: key);
#override
State<ImagesStack> createState() => _ImagesStackState();
}
class _ImagesStackState extends State<ImagesStack> {
#override
Widget build(BuildContext context) {
return Center(
child: Stack(children: <Widget>[
ImageFiltered(
imageFilter: ImageFilter.blur(
sigmaX: 6,
sigmaY: 6,
),
child: Container(
// constraints: const BoxConstraints.expand(),
constraints: BoxConstraints.tight(const Size(360, 500)),
decoration: BoxDecoration(
image: DecorationImage(
alignment: Alignment.center,
image: AssetImage(widget.imagePath),
fit: BoxFit.fill,
),
),
),
),
Container(
margin: const EdgeInsets.fromLTRB(8, 4, 8, 4),
decoration: frontImageBoxDecoration,
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image.asset(
widget.imagePath,
fit: BoxFit.fill,
),
),
),
]),
);
}
}
And the full source code of demo project:
github - demo project
I tried it quickly on dartpad.
https://dartpad.dev/?id=3c24c716a9844b706662cb495675f56d
You can refer to the code to follow the structure and make changes. I have left some comments to help understand the code.
Try resizing the window after running the app in dart to see how the image gets positioned for different sizes.

Drawing Widgets at specific pixel locations for different screen sizes

I'm trying to build a simple Flutter application that displays a full-screen background image and enables the user to drag certain widgets (i.e. a basic circle) from pre-defined start positions (given in pixels) to pre-defined target positions (also given in pixels). The following screenshot from the TouchSurgery app shows a very similar setup to what I'm trying to achieve (green circle = start position, white circle = target position):
My biggest concern at this point are different screen sizes. Let's assume we have an iPhone SE (second generation) with a resolution of 750 x 1334. I can create the following background image with the desired resolution and randomly determine the desired start position to be at coordinates (430, 949) (for simplicity we can disregard the target position):
With the following widget, I can render a circular Container on top of the starting point:
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
var dpr = MediaQuery.of(context).devicePixelRatio;
return Scaffold(
body: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/iPhoneSE.png"),
fit: BoxFit.fill,
),
),
),
Positioned(
left: 430 / dpr,
top: 949 / dpr,
child: Container(
width: 77.0 / dpr,
height: 77.0 / dpr,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.red,
),
),
),
],
),
);
}
}
The resulting image looks like this:
Things start to get tricky when I add an AppBar or a BottomNavigationBar to my application. Both Widgets have a default height of 56 pixels. Given a devicePixelRatio of 2 on the iPhone SE, I need to crop the size of my background image to 750 x 1110 for the overlay to still be accurate (1334 - 2 * 56 (AppBar) - 2 * 56 (BottomNavigationBar)).
Things get even more complicated for other devices such as the iPhone XR, where also the size of the safe area has to be considered. And for Android, there's even more different screen resolutions available.
My question now is the following: instead of creating differently sized background images for 20-30+ different screen sizes - is there a more efficient way in Flutter to draw widgets such as a circular Container at very specific screen locations that works independently of the actual screen size?
You need to get the size of the image container BEFORE positioning your Positioned Widget.
Because as you said, the screen size could change, independently of the image size (e.g. The screen is taller but has a bigger SafeArea, or has an appBar and BottomAppBar. The image could be the same size even if the screen size increased...)
Since your Positioned widget and your image Container are in the same build method, you have to use a LayoutBuilder widget to track the size of your image Container before moving on to building your Positioned widget.
Here's how:
(I've included 2 fully working examples so that you can see that the red circle keeps the same relative position to the background image, even when the image size changes. Your corrected code is the first example).
Example 1
/*
I used these calculated ratios based on your code.
Feel free to use any other way to get these ratios.
The method will be the same.
- The image takes all the available width and height
- The positioned element is postioned :
58.9% from the left of the image container
72% from the top of the image container
- The inner container's:
width is 7.129629629% of the Image Container's width,
height is 4.292084726% of the Image Container's height,
*/
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) { //This is key
return Scaffold(
body: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/iPhoneSE.png"),
fit: BoxFit.fill,
),
),
),
Positioned(
left: 0.589 * constraints.maxWidth,
top: 0.72 * constraints.maxHeight,
child: Container(
width: 0.07129629629 * constraints.maxWidth,
height: 04292084726 * constraints.maxHeight,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.red,
),
),
),
],
),
);
});
}
}
Example 1 image:
Example 2 (with an AppBar and BottomAppBar)
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Title of app"),
),
body: LayoutBuilder(builder: (context, constraints) {
return Column(
children: <Widget>[
Flexible(
fit: FlexFit.loose,
child: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/iPhoneSE.png"),
fit: BoxFit.fill,
),
),
),
Positioned(
left: 0.589 * constraints.maxWidth,
top: 0.72 * constraints.maxHeight,
child: Container(
width: 0.07129629629 * constraints.maxWidth,
height: 0.04292084726 * constraints.maxHeight,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.red,
),
),
),
],
),
),
],
);
}),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(
Icons.home,
),
title: Text("Home")),
BottomNavigationBarItem(
icon: Icon(Icons.account_circle), title: Text("Profile")),
],
),
);
}
}
Example 2 image:
How about using a Transform.scale widget on your stack and just resizing the whole thing to fit inside whatever constraints the device has?
Something like this:
Transform.scale(
alignment: Alignment.topLeft,
scale: scaleVar,
child: Stack(
children: <Widget>[
Positioned(
top: 0,
left: 0,
child: Image(
image: AssetImage("assets/iPhoneSE.png"),
alignment: Alignment.topLeft,
),
),
Positioned(
left: 430,
top: 949,
child: Container(
width: 77.0,
height: 77.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.red,
),
),
),
],
),
)

How can i fix local asset error in flutter?

Can someone tell me why the picture cannot be displayed?
#
When I take a picture from the Internet with "NetworkImage" it works. Is there a local solution too?
#
I tried a lot around but even the posts here in the forum can not help me.
# To add assets to your application, add an assets section, like this:
assets:
- images/mio.jpg
-
import 'package:flutter/material.dart';
void main() {
runApp(Main());
}
class Main extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
width: 250,
height: 250,
color: Colors.grey,
child: Stack(
children: <Widget>[
Container(
width: 200,
height: 300,
color: Colors.green,
),
Positioned(
top: 0,
right: 0,
child: Container(
width: 200,
height: 300,
child: Image(
fit: BoxFit.contain,
image: AssetImage(
'images/mio.jpg',
),
),
),
),
],
),
),
),
);
}
}
I get this error message
I'm not sure why you are getting this error but you should try
Asset.Image(
'images/mio.jpg',
fit: BoxFit.contain,
),
instead of
Image(
fit: BoxFit.contain,
image: AssetImage(
'images/mio.jpg',
),
),
another suggestion would be to not declare all your images in your pubspec.yaml, because there is a chance of human mistype error, you should just declare the root folder of your images, in your case
assets:
- images/
Here's three solution
First make sure that there's only one tap before assets and two taps before the image path
Second change these lines of code
Image(
fit: BoxFit.contain,
image: AssetImage(
'images/mio.jpg',
),
and write this instead that works for me
Image.asset(
'images/mio.jpg',
fit: BoxFit.cover,
),
Third use flutter clean than flutter run

How can I make a Card height extend based on content?

I am creating a Card which has a header and a grid view of photos. Below is the code:
_getImageWidget(Post post, AppConfig config) {
if (post.photoPaths != null && post.photoPaths.length > 0) {
var url = config.imagePathDomain + post.photoPaths[0];
try {
return Expanded(
child: GridView.count(
crossAxisCount: 3,
shrinkWrap: false,
children: post.photoPaths.map<Widget>((String path) {
return CachedNetworkImage(
imageUrl: url,
);
}).toList()));
} catch (err) {
return Container();
}
}
return Container();
}
#override
Widget build(BuildContext context) {
var config = AppConfig.of(context);
return BlocBuilder<UserInfoBloc, UserInfo>(builder: (_, userInfo) {
return Container(
width: MediaQuery.of(context).size.width,
child: Card(
child: Column(children: <Widget>[
Row(
children: <Widget>[
IconButton(
iconSize: 30,
icon: roundImage(post.userPicture, Icon(Icons.person)),
onPressed: () {},
),
Text('#${userInfo.username}')
],
),
this._getImageWidget(post, config),
])));
});
}
The header in the Card is a Row includes a IconButton and Text.
The body of the Card is a gridview which includes a few photo.
Below is the screenshot when I run the code. You can see that the photo is shown only a half. And I can scroll vertically on the grid view. The number of photos is dynamic which means there could be many rows of photos in the GridView. How can I make the Card extend based on its children?
By simply setting your CachedNetwork image to use a fit: BoxFit.cover that will resize to fill the content while preserving ratio (this means you may lose some of its details) or fit: BoxFit.contain that will try to be as big as possible while containing the entire source (image) within the bounds.
If that doesn't help as well (as I'm not seeing the entire tree so I'm not sure about the ancestors of your Card) you can also replace the return of your BlocBuilder's child to be a FittedBox instead of a Container and apply the same logic for the fit property, but for the whole card instead.
Try using a fixed size container and using the BoxFit property on the container.
Something like this :
new Container(
width: 80.0,
height: 80.0,
decoration: new BoxDecoration(
shape: BoxShape.rectangle,
image: new DecorationImage(
fit: BoxFit.fill,
image: CachedNetworkImageProvider(url),
),
),
),
Edit : Try to remove itemExtent from ListView.builder

How can I make a fadein "decoration image" effect in Flutter

I want to build a widget that displays an image as a background behind some content. I know I can do this with a DecorationImage the problem is that I want the image to fade in as it might not be available right away.
So I want it to look like this after the image has faded in.
class DecorationExample extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fitWidth,
image: NetworkImage(
'https://images.pexels.com/photos/414612/pexels-photo-414612.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500'),
),
),
child: Column(
// Center the content dead center.
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
//Expand the column to take up the availble width
Container(width: double.infinity),
Text('Can be'),
Text('any'),
Text('size'),
Text('Depending on the number of rows')
],
),
);
}
}
My first instinct is to use a stack. The problem is that I need the stack to constrain itself to the height of the column which may vary depending on the content.
import 'package:flutter/material.dart';
import 'package:transparent_image/transparent_image.dart';
class StackedImageTest extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Container(
width: double.infinity,
child: _fadeInImage(),
),
_content(),
],
);
}
_content() => Column(
// Center the content dead center.
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
//Expand the column to take up the availble width
Container(width: double.infinity),
Text('Can be'),
Text('any'),
Text('height'),
Text('Depending on the number of rows')
],
);
_fadeInImage() => FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
fit: BoxFit.fitWidth,
image: 'https://images.pexels.com/photos/414612/pexels-photo-414612.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500',
);
}
To run the example include this dependency in your pubspec.yaml file:
transparent_image: ^1.0.0
So basically how can I achieve the same effect as with a decoration image(DecorationExample) but make it so that the image fades nicely into view(like in the StackedImageTest widget)?
Pretty simple as it turns out😅
Wrapping the first layer in the stack with a Positioned.fill() seems to do the trick
class FadeInDecorationContainer extends StatelessWidget {
final Widget child;
final String imgUrl;
const FadeInDecorationContainer({Key key, this.child, this.imgUrl}) : super(key: key);
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Positioned.fill(child: _fadeInImage()),
child,
],
);
}
_fadeInImage() => FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
fit: BoxFit.fitWidth,
image: imgUrl,
);
}
To run the example include this dependency in your pubspec.yaml file:
transparent_image: ^1.0.0