When applying ImageFilter.blur to an image, the edges of the image are unchanged.
How can I extend the blur to the edges?
import 'dart:ui';
import 'package:flutter/material.dart';
class ExamplePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage("https://i.pinimg.com/236x/93/ca/59/93ca599d74b60b4e9b30cd9472f842b7--patterns-in-nature-beautiful-patterns.jpg"),
fit: BoxFit.cover,
),
),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20),
child: Container(
decoration: BoxDecoration(color: Colors.white.withOpacity(0.0)),
),
),
);
}
}
This may not be what you want to hear, or it might be =D. The issue you're seeing is that Skia's software renderer has a problem with blurs. You won't see the same issue on the Android simulator unless you specifically turn on software rendering, nor on actual devices as they use hardware rendering.
This is on my iPhone:
If you really need blur to work properly in the simulator I'd recommend either adding a +1 to this issue or making a new issue in the flutter repo with the image above (as in the issue I linked to it seemed they were seeing inconsistency rather than exactly what you've observed, although I'd imagine the fix would fix what you're seeing as well).
A solution that wouldn't require that bug to be fixed for the simulator is possible I think.... You could theoretically use an overflow to make the blur go outside of the edge of the screen by at least the size of the blur, have the image then offset by the same amount as the overflow, and flip copies of the same image outside of the screen bounds so that the colouring on the blur is right.... but that seems a bit overkill =D.
The fix will be available soon in the stable version of Flutter SDK, until that if you need it, switch to the master channel by running this in terminal and rebuild your app:
flutter channel master
source: Backdrop filter is inconsistent on software rendering
If you replace you above mentioned code with
return Container(
decoration: BoxDecoration(
image: DecorationImage(
image: CachedNetworkImageProvider("https://i.pinimg.com/236x/93/ca/59/93ca599d74b60b4e9b30cd9472f842b7--patterns-in-nature-beautiful-patterns.jpg"),
fit: BoxFit.cover,
),
),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
child: Container(
decoration: BoxDecoration(color: Colors.white.withOpacity(0.0)),
),
),
);
Then it look like this and edges issue resolved
Related
Can a ContinuousRectangleBorder (AKA Squircle, Superellipse) shape be used as a template for masking another widget?
Context
I'm trying to mask a widget using ClipRRect but the customization options it offers only include traditional border radius which doesn't quite generate the same shape as a container decorated with ContinuousRectangleBorder
Example:
In this approach, the ClipRRect destroys completely the original shape of the ContinuousRectangleBorder if its radius is too big, if it is too small it won't clip both the filter and the container appropiately. I tried with elliptical radiuses but still it does not look as expected
ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(40)),
child: BackdropFilter(
// Filter
filter: ImageFilter.blur(
sigmaX: 20,
sigmaY: 20,
),
// Container with ContinuousRectangleBorder
child: Container(
constraints: BoxConstraints(maxWidth: 600),
decoration: ShapeDecoration(
color: Colors.blue,
shape: ContinuousRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(80)),
),
),
child: Padding(
padding: const EdgeInsets.all(30.0),
child: Text("Hola World"),
),
),
),
);
What I've Tried
I tried using an Stack with two layers:
Stack
|- Layer 1: BackdropFilter inside a traditional ClipRRect hoping to simulate the shape of the ContinuousRectangleBorder behind the real ContinuousRectangleBorder without affecting the real geometry of it.
|- Layer 2: ContinuousRectangleBorder decoration to the final Container.
The problem with this approach is that I could not find a way for the widget within the Layer 1 to occupy the entire width and height of its brother in Layer 2
Hypothesis
Stack: I think this is the closest I've been to solve this case, but it is not the best solution since it simulates the result. (And I'm still stuck where I can't make the Layer 1 container to fill all the space available in the stack.
I read about about the ClipPath widget but it takes a Path as an argument and I have not been able to convert the ShapeDecoration to that type and use it as a mask.
It may be another way to create the ContinuousRectangleBorder look in order to use it as a mask and a container? I found it is also called squircle / superellipse but the packages and solutions to recreate it use a ShapeDecoration just as ContinuousRectangleBorder does.
Maybe an alternative way to make a mask that takes the ContinuousRectangleBorder as an argument and wraps its child?
Open discussion
I'm aware the last 2 hypothesis are a bit far from the original question but I'm open to make things in other ways.
Thank you all for your help.
Thanks to #pskink advice, the correct way to achieve this is by using a ClipPath and passing the ContinuousRectangleBorder as a shape of a ShapeBorderClipper
Example:
ClipPath(
clipper: ShapeBorderClipper(
shape: ContinuousRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(80),
),
),
),
child: Text("Hola World"),
);
So I was trying to create a welcome page when I got this problem. At first, everything was fine, but when I insert an image using DecorationImage, it looks like my image has an error in the color gradient. The real image look like this:
But when i run my app, i get this:
I use PageView.Builder in Scaffold to show my images. My code look like this:
return Scaffold(
body: PageView.builder(
scrollDirection: Axis.vertical,
itemCount: img.length,
itemBuilder: (_,index){
return Container(
width: double.maxFinite,
height: double.maxFinite,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
"assets/image/"+img[index]
),
fit: BoxFit.cover
)
),
I put all my image names in a list and use the index to call each images.
The goldfish looks pretty much the same but the gradient at the bottom is disturbed. At first, I thought it was because I was using a low spec virtual device, but then I tried with a different virtual device and still got the same result. Why this happened? Does anyone know where I went wrong?
Edit: i try to add FilterQuality
return Container(
width: double.maxFinite,
height: double.maxFinite,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
"assets/image/"+img[index]
),
fit: BoxFit.cover,
filterQuality:FilterQuality.high
)
),
But nothing happen. Did I put it wrong?
i tried using real device and it works, but i don't know why
I have a background image as shown, it needs to overlap the edges as shown in the UI render and I'm not sure how best to go about it. I've tried cropping it and using BoxFit.fill but this just leads to a change in aspect ratio which I don't really want, especially on different sized screens. I'm thinking maybe having it overlap on the left and right by a fixed amount and then the size changes to accommodate that depending on the screen size but not really sure how to code that. I've played around with expanded widgets inside columns and all sorts like that but to no avail.
If you made the image a bit wider, you can use BoxFit.fitHeight instead. Here's a sample fitting a landscape image to a portrait view.
https://codepen.io/digitaljoni/pen/rNeMzdG
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fitHeight,
image: NetworkImage(
'https://images.unsplash.com/photo-1542362567-b07e54358753?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2100&q=80',
),
),
),
),
);
}
}
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/btn-img.png'),
fit: BoxFit.cover,
),
),
...
),
The bug is that the image of the container widget is misplaced (a little bottom relative to Container's position). Does anyone have experienced same problem?
Update
when I use another image with larger height, it works fine (My current image height is 302px)
Update2
The problem seems to be with color filter, when I disable color filter it works fine.
I have an svg as a child in a container. I'm using this package . The svg is curved at one side but it loses this curvature when rendered.
Padding(
padding: const EdgeInsets.only(left: 30,right: 30,bottom: 10),
child: ClipRRect(
child: Container(
alignment: Alignment.centerRight,
child: SvgPicture.asset('assets/img/mask_purple_energizer.svg',height: 200,width: 1000,),
color: Theme.of(context).cardColor),
borderRadius: BorderRadius.circular(15),
),
),
Here is the gist of the svg file:
https://gist.github.com/horgag1/66ef8ab683f26b9c19a318769a2cf3e9
I don't think clip rects are supported by the SVG plugin you're using, or at least not how they are in your SVG. The right-side corners aren't being cropped properly either, but you can't tell that because the ClipRRect takes care of it.
If the SVG editor you're using supports it, you may be able to apply the clip to each shape instead of having it separate. Otherwise, your options are to either raise a bug or add clipping to the plugin, or to use a ClipPath widget and manually define the clipping path (or copy it out of the svg).