Why doesn't flutter properly blur the whole background image? - flutter

I'm trying to apply an ImageFilter on to my image but it only blurs part of it and fades off like this:
The Actual Image
Partly Blurred Image
As you can see, most of it is properly blurred but you can make out the bottom part.
How I'm blurring it:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
ConstrainedBox(
constraints: const BoxConstraints.expand(),
child: Image(image: AssetImage(config.wallpaper), fit: BoxFit.cover),
),
Container(
child: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: config.blur['sigmaX'] ?? 50,
sigmaY: config.blur['sigmaY'] ?? 50),
child: Container(
color: Colors.transparent,
height: 1080,
width: 1920,
),
),
),
)
],
));
}
}

Maybe you can try stacking a translucent container above the image?
Something like this :
Stack(
Image(/*your image*/),
Container(color: Colors.grey.withOpacity(0.6)),
),
You can adjust the color and opacity according to your need. You won't exactly be blurring the image but it will do a good work of hiding that image.

Related

How to have Label text with graphics over image(product image of e commerce app) in flutter?

I am trying to get a text label with graphics over the image. Labels like new arrival, best seller, limited, on sale just like on the pic attached.
enter image description here
Here's what i think the skeletal layout would be :
return Stack(
children: [
Card(
color: Colors.black54,
child: Image.asset('assets/xyz.png'),
),
Align(
//for bottomRight
alignment: Alignment.bottomRight,
child: Image.asset(
'assets/fireimg.png',
), //can be an SVG converted to png
),
Align(
//for topLeft
alignment: Alignment.topLeft,
child: Image.asset(
'assets/label.png',
), //can be an SVG converted to png
),
],
);
Feel free to give the Padding of your choice.
it has so much code to write , so i will give some examples to achieve that output
in this image ,i mentioned 0 and one .
for all 1
solution 1
you can use image like this way
Stack(
children: [
Container(
width: 200,
height: 200,
color: Colors.amber,// added only for view this example
child:Image() // add Product image here
),
Positioned(
top: 20, //change according to your use case position
left: 0,// change according to your use case position
child: Container(
color: Colors.black, // added only for view this example
decoration: BoxDecoration(image: ),// add label image here
width: 100,
height: 50,
child: Row(
children: [Text('hi')],
),
))
],
)
solution 2
you can use custom paint for label layout
not that
in both solution you have to use stack and position widgets , you can control position according to your use case
for all 0
you can use RotationTransition widgets to achieve this
not that
you have to use stack and position widgets , you can control position according to your use case
for the vertical Text
use this example
String exText = "meta";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('hi'),
),
body: Container(
width: 200,
height: 200,
color: Colors.amber,
child: Column(
children: exText.characters
.map((e) => Container(
child: Text('$e'),
))
.toList()),
),
out put will be

How to rotate a larger-than-screen image without the overflow being clipped off in Flutter?

I have this image that I would like to display full screen and rotate in the background:
Here it is filling the screen correctly:
The problem is, when it rotates, the sides have been clipped off:
I've tried every type of box fit. I've tried sizing the container width to double.infinity. I've tried wrapping the image in a SingleChildScrollView. I've tried putting overflow: Overflow.visible on the stack. All day trying things, but nothing seems to be working.
The image needs to continuously fill the screen while rotating. How can I code it so that the edges aren't clipped off?
Here's my code:
class FirstScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Stack(
children: <Widget>[
SpinPerfect(
infinite: true,
duration: Duration(seconds: 10),
child: Image.asset(
'assets/images/star-burst.png',
fit: BoxFit.none,
),
),
Container(
child: Center(
child: Text('This is Screen 1'),
),
),
],
),
),
);
}
}
Note: I am currently rotating it using SpinPerfect from the animate_do package, but the same clipping problem happens when using Transform.rotate.
Thanks in advance for any direction!
Here is a solution that works very well:
Use SpinPerfect from the animate_do package (https://pub.dev/packages/animate_do) in combination with the photo_view package (https://pub.dev/packages/photo_view).
SpinPerfect(
infinite: true,
spins: 1,
duration: Duration(seconds: 60),
child: PhotoView(
disableGestures: true,
backgroundDecoration: BoxDecoration(color: Colors.transparent),
initialScale: PhotoViewComputedScale.covered * 2.7,
imageProvider: AssetImage('assets/images/background.jpg'),
),
)
Thanks to the creator of the animate_do package for the idea. (Very cool dude!)

Flutter: How to make the below image widget functional in Stack

I try to achieve the feature: pinch to zoom in/out an image under another overlay image.
My approach is using photo_view to make the main photo zoomable and put the overlay image on top of the main photo by the "stack".
import 'package:photo_view/photo_view.dart';
class Body extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Stack(
children: <Widget>[
Container(
child: PhotoView(
initialScale: PhotoViewComputedScale.covered,
imageProvider: AssetImage("assets/mainphoto.jpg"),
),
),
),
Container(
child: Center(
child: AssetImage("assets/overlay.png”),
),
),
],
),
);
}
}
The result of the above code
But the overlay image completely disables the main photo, I cannot pinch to zoom in/out the main photo.
I think it’s because of Stack, I googled around it but still don’t have any proper solution.
If any suggestions, I am very appreciated.
Use IgnorePointer Widget
IgnorePointer(
child: Container(
child: Center(
child: Image.asset(
"assets/overlay.png",
),
),
),
)

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 the blur filter be stopped from sampling colors surrounding a blurred image?

I have a demo widget that looks like the following:
class BlurDemo extends StatelessWidget {
BlurDemo({Key key}) : super(key: key);
final String imageUrl =
'https://dogtime.com/assets/uploads/2018/10/puppies-cover-1280x720.jpg';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Blur Demo'),
),
backgroundColor: Colors.black,
body: Center(
child: SizedBox(
width: 250,
height: 250,
child: FittedBox(
fit: BoxFit.cover,
child: Stack(children: [
Image.network(imageUrl),
Positioned.fill(
child: ClipRRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 20.0, sigmaY: 20.0),
child: Container(color: Colors.black.withAlpha(0))),
))])))));}}
Current effect:
Desired effect (mockup):
If you look at the edges of the photo in the "current effect" image, you'll see a darkening effect. The blur filter is sampling the pixels around the image, even though those pixels are outside of the clip rect. In this demo, the image is cropped and there are more surrounding pixels that could be sampled from for the blur effect. Even if it wasn't cropped, it would be nice to clamp the effect to the contents of the cliprect and not let surrounding colors bleed in.
ethanblake4 was able to answer this question on GitHub: https://github.com/flutter/flutter/issues/61891.
The answer is to use an ImageFiltered instead of BackdropFilter.