I'd like to achieve following effect in Flutter with built in Flutter widgets without using PNG image with transparency.
I was trying to experiment with backgroundBlendingMode but without success.
I can also think of using custom painter to draw circle and inner cross, but ideally I would like to use any Icon or any other Widget to cut the background.
I also stumbled upon something called CustomClipper. Is it the way to go?
Let's say that we have following widget:
return Stack(
children: <Widget>[
SizedBox(
height: 44,
width: 44,
child: Image.network(
'https://images.pexels.com/photos/1295138/pexels-photo-1295138.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260',
fit: BoxFit.cover,
),
),
Positioned(
left: 0,
right: 0,
bottom: 0,
top: 0,
child: Icon(
Icons.close,
color: Colors.black,
),
),
],
);
Sample image can be taken from pexels.
Ok, so I found the answer on SO in this question.
It appears that the proper keyword is cutout.
So my solution is really simple and looks like follows:
ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Cutout(
color: Colors.white,
child: Icon(
Icons.close,
color: Colors.white,
),
),
),
And the clipper using ShaderMask:
class Cutout extends StatelessWidget {
const Cutout({
Key key,
#required this.color,
#required this.child,
}) : super(key: key);
final Color color;
final Widget child;
#override
Widget build(BuildContext context) {
return ShaderMask(
blendMode: BlendMode.srcOut,
shaderCallback: (bounds) =>
LinearGradient(colors: [color], stops: [0.0]).createShader(bounds),
child: child,
);
}
}
Related
I have a special clipper form (picture)
and I want to create a shadow around it. For that, I tried it with this:
Material(
elevation: 10,
child: ClipPath(
clipper: RoundedDiagonalPathClipper(),
child: Transform.scale(
scaleX: 1,
scaleY: -1,
child: Container(
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(
25.0,
),
),
color: Colors.white,
),
...... more code, not important for this ....
But then it creates a normal container around the special form. I found the option "clip Behaviour, but I don't know if this is my solution. Can you help me? Or is there a other way of creating a shadow around this box?
A simple way is creating a Shadow and shifting your clipper by offset.
Create a ClipShadowPath class like this.
import 'package:flutter/material.dart';
#immutable
class ClipShadowPath extends StatelessWidget {
final Shadow shadow;
final CustomClipper<Path> clipper;
final Widget child;
ClipShadowPath({
#required this.shadow,
#required this.clipper,
#required this.child,
});
#override
Widget build(BuildContext context) {
return CustomPaint(
key: UniqueKey(),
painter: _ClipShadowShadowPainter(
clipper: this.clipper,
shadow: this.shadow,
),
child: ClipPath(child: child, clipper: this.clipper),
);
}
}
class _ClipShadowShadowPainter extends CustomPainter {
final Shadow shadow;
final CustomClipper<Path> clipper;
_ClipShadowShadowPainter({#required this.shadow, #required this.clipper});
#override
void paint(Canvas canvas, Size size) {
var paint = shadow.toPaint();
var clipPath = clipper.getClip(size).shift(shadow.offset);
canvas.drawPath(clipPath, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
Here is usage:
Widget buildBodyWidget(BuildContext context) {
return ClipShadowPath(
////*** Your Custom clip path *****
clipper: RoundedDiagonalPathClipper(),
/// Blur property of Shadow class
shadow: Shadow(
blurRadius: 5
),
child: Transform.scale(
scaleX: 1,
scaleY: -1,
child: Container(
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(
25.0,
),
),
color: Colors.white,
),
);
}
I am trying to create a custom floating bottom navigation bar and i create a widget and added a margin to create a floating effect but it adds a white background.
I need to create it without the white background.
Here is my code;
Scaffold(
bottomNavigationBar: AnimatedBottomBar(
currentIcon: viewModel.currentIndex,
onTap: (int index) => viewModel.updateIndex(index),
icons: viewModel.icons,
),
body: viewModel.pages[viewModel.currentIndex],
);
Then the animated bottom bar
import 'package:flutter/material.dart';
import 'package:woneserve_updated_mobile_app/app/theming/colors.dart';
import 'package:woneserve_updated_mobile_app/models/icon_model.dart';
class AnimatedBottomBar extends StatelessWidget {
final int currentIcon;
final List<IconModel> icons;
final ValueChanged<int>? onTap;
const AnimatedBottomBar({
Key? key,
required this.currentIcon,
required this.onTap,
required this.icons,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
color: Colors.transparent,
child: Container(
margin: const EdgeInsets.all(40),
padding: const EdgeInsets.all(15),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 2,
blurRadius: 5,
offset: const Offset(0, 2), // changes position of shadow
),
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: icons
.map(
(icon) => GestureDetector(
onTap: () => onTap?.call(icon.id),
child: AnimatedSize(
duration: const Duration(milliseconds: 900),
child: Icon(
icon.icon,
size: currentIcon == icon.id ? 26 : 23,
color: currentIcon == icon.id ? primaryColor : Colors.black,
),
),
),
)
.toList(),
),
),
);
}
}
How can i create the same effect without the white background? Any help would be appreciated.
You might need to add extendBody: true in Scaffold.
my friend
for solve this problem you have 3 way.
use extendBody: true in your Scaffold.
use theme in MaterialApp Widget.(see below)
ThemeData(
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
backgroundColor: Colors.transparent,
),
),
use floatingActionButton instead of bottomNavigationBar in Scaffold.(see below)
Scaffold(
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: AnimatedBottomBar(...),
...
)
Try remove first Container in build method. If not work, remove margin and padding in second Container.
I need to make glass card view widget in the flutter (like image).
Its mode without using the package. But if there is no solution, if there is a package for it, thank you for introducing that package as well.
Try to used glassmorphism package also refer glassmorphism_ui
You can use GLASS package.
This package is Null safety and also supports ANDROID IOS LINUX MACOS WEB WINDOWS platform.
class GlassMorphismExample extends StatelessWidget {
const GlassMorphismExample({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.amber,
body: Center(
child: GlassMorphism(
child: Container(
alignment: Alignment.center,
width: MediaQuery.of(context).size.width * 0.8,
height: MediaQuery.of(context).size.height * 0.8,
child: const Text(
"Glass Morphism",
style: TextStyle(fontSize: 35),
),
),
end: 0.5,
start: 0.3,
),
),
);
}
}
class GlassMorphism extends StatelessWidget {
final Widget child;
final double start;
final double end;
const GlassMorphism({
Key? key,
required this.child,
required this.start,
required this.end,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return ClipRRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 3, sigmaY: 3),
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.white.withOpacity(start),
Colors.white.withOpacity(end),
],
begin: AlignmentDirectional.topStart,
end: AlignmentDirectional.bottomEnd,
),
borderRadius: const BorderRadius.all(Radius.circular(10)),
border: Border.all(
width: 1.5,
color: Colors.white.withOpacity(0.2),
),
),
child: child,
),
),
);
}
}
Result
thanks to all. I wrote my own package for answer of my question.
https://pub.dev/packages/flutter_glass
I made my own widget with blur, bottom widget is looking correct, but top isn't. On top widget, text is behind blur, but why?
I need same result like second widget. (Text front of blur)
Second widget is looking correct.
Please look screenshot at first.
How to fix it? Thanks for any help.
class MyHomePage extends StatelessWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// incorrect
MyCard(
imageLink:
'https://catherineasquithgallery.com/uploads/posts/2021-02/1612198837_120-p-fioletovii-fon-mainkraft-160.png',
text: 'AR-scene',
),
SizedBox(
height: 70,
),
//correct
MyCard(
imageLink:
'https://www.digiseller.ru/preview/1019450/p1_3193057_f7ad4eea.jpg',
text: 'Photos',
),
],
),
);
}
}
// my custom widget
class MyCard extends StatelessWidget {
final imageLink;
final text;
const MyCard({Key? key, required this.imageLink, required this.text})
: super(key: key);
#override
Widget build(BuildContext context) {
return Container(
width: 270,
height: 320,
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 4, sigmaY: 3),
child: Center(
child: Text(
text,
style: TextStyle(fontSize: 25, color: Colors.white),
textAlign: TextAlign.center,
),
)),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(7),
image: DecorationImage(
fit: BoxFit.cover, image: NetworkImage(imageLink))),
);
}
}
Wrap your BackdropFilter with ClipRect, else it covers the covering the full screen.
return Container(
key: ValueKey(text),
width: 270,
height: 320,
child: ClipRect( //<- here
child: BackdropFilter(
More on BackdropFilter-class
Using backdrop filter applies that particular filter to the whole screen. You can use ClipRRect to make it adopt the size of child widget (Container in this case).
// my custom widget
class MyCard extends StatelessWidget {
final imageLink;
final text;
const MyCard({Key? key, required this.imageLink, required this.text})
: super(key: key);
#override
Widget build(BuildContext context) {
return ClipRRect(
child: Container(
width: 270,
height: 320,
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 4, sigmaY: 3),
child: Center(
child: Text(
text,
style: TextStyle(fontSize: 25, color: Colors.white),
textAlign: TextAlign.center,
),
)),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(7),
image: DecorationImage(
fit: BoxFit.cover, image: NetworkImage(imageLink))),
),
);
}
}
A better solution is to use ImageFiltered instead of BackdropFilter widget.
ImageFiltered blurs its child, for example, a single picture.
BackdropFilter blurs everything "behind" it, but does not blur its own child. It's useful in situations like a pop-up dialog, where you want to blur the whole screen, except the dialog itself.
I am trying to add swiper dots below as shown in the figure
while in the code I tried parallax effect on image and text, now I am trying to add dots below, swiper dots will help to understand which page we are in.
here is the present code:
import 'package:ecommerce_int2/models/product.dart';
import 'package:flutter/material.dart';
import 'package:transformer_page_view/transformer_page_view.dart';
import 'package:flutter/cupertino.dart';
class ParallaxMain extends StatefulWidget {
ParallaxMain({Key key, this.title}) : super(key: key);
final String title;
#override
_ParallaxMainState createState() => new _ParallaxMainState();
}
class ParallaxSlide extends StatelessWidget {
final List<Product> product;
ParallaxSlide({Key key, this.product}) : super(key: key);
#override
Widget build(BuildContext context) {
return new TransformerPageView(
loop: true,
viewportFraction: 0.8,
transformer: new PageTransformerBuilder(
builder: (Widget child, TransformInfo info) {
return new Padding(
padding: new EdgeInsets.all(10.0),
child: new Material(
elevation: 4.0,
textStyle: new TextStyle(color: Colors.white),
borderRadius: new BorderRadius.circular(10.0),
child: new Stack(
fit: StackFit.expand,
children: <Widget>[
new ParallaxImage.asset(
//images[info.index],
product[info.index].image[0],
position: info.position,
),
new DecoratedBox(
decoration: new BoxDecoration(
gradient: new LinearGradient(
begin: FractionalOffset.bottomCenter,
end: FractionalOffset.topCenter,
colors: [
const Color(0xFF000000),
const Color(0x33FFC0CB),
],
),
),
),
new Positioned(
child: new Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new ParallaxContainer(
child: new Text(
product[info.index].name,
style: new TextStyle(fontSize: 15.0),
),
position: info.position,
translationFactor: 300.0,
),
new SizedBox(
height: 8.0,
),
new ParallaxContainer(
child: new Text("₹ "+product[info.index].price.toString(),
style: new TextStyle(fontSize: 18.0)),
position: info.position,
translationFactor: 200.0,
),
],
),
left: 10.0,
right: 10.0,
bottom: 10.0,
)
],
),
),
);
}),
itemCount: product.length,
);
}
}
class _ParallaxMainState extends State<ParallaxMain> {
#override
Widget build(BuildContext context) {
return new SizedBox(
height: 400,
child: new ParallaxSlide()
);
}
}
Is there any way to add swiper dots to this code?
Try this:
move your TransformerPageView inside a stack and add a DotIndicator
Stack(children:[
TransformerPageView(controller: _controller),
DotsIndicator(controller: _controller)
])
Make sure you add the same _controller for both of them. Then position the dot indicator as you like.
PageController: A controller for PageView.
A page controller lets you manipulate which page is visible in a PageView.
You can read the complete information in the link provided.
Hints taken from here.
Personally, I use smooth_page_indicator because it provides awesome transition effects. Just follow the docs and it's so easy to implement.
Yes we can do it by using carousel_slider
Please check the example of Image carousel slider with a custom indicator.