flutter cropping around Card with getOuterPath and ShapeBorder - flutter

In flutter i'm trying to cropping around Cart, this action can be done easily? i can't find any documentation or hacking ideas
when we create this widget with CustomPainter we can't set shadow, is any body can help us to solve this issue?
thanks in advance

it could be like that:
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
brightness: Brightness.light,
primarySwatch: Colors.blue,
scaffoldBackgroundColor: Colors.white,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Card(
shape: DurmaShape(
borderRadius: Radius.circular(20),
holeSize: 40,
offset: Offset(30, -30),
side: BorderSide(
color: Colors.black.withOpacity(0.5),
width: 1.0,
),
),
elevation: 7,
child: Container(
height: 200,
width: 280,
),
),
],
),
),
);
}
}
class DurmaShape extends ShapeBorder {
DurmaShape({
#required this.borderRadius,
#required this.holeSize,
this.offset = Offset.zero,
this.side = BorderSide.none,
});
final Radius borderRadius;
final Offset offset;
final BorderSide side;
#override
EdgeInsetsGeometry get dimensions => EdgeInsets.zero;
#override
void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) {
if (side != BorderSide.none) {
canvas.drawPath(
_getPath(rect),
side.toPaint(),
);
}
}
Path _getPath(Rect rect) {
return Path.combine(
PathOperation.difference,
Path()
..addRRect(RRect.fromRectAndRadius(rect, borderRadius))
..close(),
Path()
..addOval(Rect.fromCircle(
center: Offset(0, rect.height) + offset,
radius: holeSize,
))
..close(),
);
}
#override
Path getInnerPath(Rect rect, {TextDirection textDirection}) => null;
final double holeSize;
#override
ui.Path getOuterPath(ui.Rect rect, {ui.TextDirection textDirection}) =>
_getPath(rect);
#override
ShapeBorder scale(double t) => this;
}

Related

flutter container with curve border

I want this type container with curve border, please check attach images
best solution of answer
I am Using ShapeBorder with paint.
class CustomShape extends ShapeBorder {
#override
EdgeInsetsGeometry get dimensions => EdgeInsets.zero;
#override
Path getInnerPath(Rect rect, {TextDirection? textDirection}) {
return getInnerPath(rect);
}
#override
Path getOuterPath(Rect rect, {TextDirection? textDirection}) {
final double curveX = rect.width / 10;
Path rectPath = Path()
..addRRect(RRect.fromRectAndRadius(rect, const Radius.circular(24)));
Path curvePath = Path()
..moveTo(rect.center.dx - curveX, rect.top)
..quadraticBezierTo(
rect.center.dx,
rect.center.dy - curveX, //middle curve control
rect.center.dx + curveX,
rect.top,
);
return Path.combine(PathOperation.xor, rectPath, curvePath);
}
#override
void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) {
canvas.drawPath(
getOuterPath(rect),
Paint()
..color = Colors.red
..style = PaintingStyle.stroke);
}
#override
ShapeBorder scale(double t) => this;
}
And use
child: Container(
height: 200,
width: 500,
decoration: ShapeDecoration(
shape: CustomShape(),
),
),
Use quadraticBezierTo value to control the curve
I am pretty sure you will find something that will work here:
Flutter draw container with a curve in the center
Hope it helps.
Here is your Clip Code... and also use Shape Maker to design such layout and you will get clip code
Your Clip Container with border
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const MyStatefulWidget(),
),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({super.key});
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
#override
Widget build(BuildContext context) {
return Center(
child: CustomPaint(
painter: BorderPainter(),
child: Container(
height: 200,
width: 400,
child: Center(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Pakistan'),
Spacer(),
Text('VS'),
Spacer(),
Text('India'),
],
),
)
)
),
),
);
}
}
Clipping Code of Container
class BorderPainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..style = PaintingStyle.stroke
..strokeWidth = 2
..color = Colors.pink;
Path path0 = Path();
path0.moveTo(size.width*0.4995083,size.height*0.2401000);
path0.quadraticBezierTo(size.width*0.5840167,size.height*0.2406000,size.width*0.6666667,size.height*0.1420143);
path0.lineTo(size.width*0.9996583,size.height*0.1441000);
path0.lineTo(size.width,size.height);
path0.lineTo(0,size.height);
path0.lineTo(0,size.height*0.1422571);
path0.lineTo(size.width*0.3358333,size.height*0.1442857);
path0.quadraticBezierTo(size.width*0.4136083,size.height*0.2398857,size.width*0.4995083,size.height*0.2401000);
path0.close();
canvas.drawPath(path0, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}

CustomPainter together with Paint()..blendMode gives weird blinking effect while scrolling

After launching the application, the green circle is not visible. In order for the circle to appear, you need to scroll up. Then if you scroll down, the circle starts blinking as long as the scrolloffset is within about 20 pixels. If the scrolloffset is larger than 20 pixels, the circle disappears and appears only when the scrolloffset is 0.
If wrap the widget in RepaintBoundary, then the circle appears on any scroll and then does not disappear.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class DemoPainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
canvas.save();
final path = Path()..addOval(Rect.fromCircle(center: Offset.zero, radius: 50));
final paint = Paint()..color = Colors.green;
paint.blendMode = BlendMode.dstOver;
canvas.drawPath(path, paint);
canvas.restore();
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
class TestWidget extends StatelessWidget {
const TestWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return SizedBox(
height: 80,
child: Center(
child: CustomPaint(
painter: DemoPainter(),
child: Text(
"Child widget",
style: TextStyle(color: Colors.blue[200], fontWeight: FontWeight.bold, fontSize: 20),
),
),
));
}
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(primarySwatch: Colors.blue),
home: Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
const TestWidget(),
const TestWidget(),
const TestWidget(),
const TestWidget(),
const RepaintBoundary(child: TestWidget()),
Container(
height: 2000,
color: Colors.red,
)
],
),
),
),
);
}
}
The link to Dartpad, but i can't reproduce the effect on the web platform.
What could be the reason for such effect and how to get rid of it?

How to make a custom bubble shape in flutter?

I am trying to create a custom tooltip with the triangle shape on either side. I have created a bubble but how to add the triangle in there without using any library?
class SdToolTip extends StatelessWidget {
final Widget child;
final String message;
const SdToolTip({
required this.message,
required this.child,
});
#override
Widget build(BuildContext context) {
return Center(
child: Tooltip(
child: child,
message: message,
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.blueAccent.withOpacity(0.6),
borderRadius: BorderRadius.circular(22)),
textStyle: const TextStyle(
fontSize: 15, fontStyle: FontStyle.italic, color: Colors.white),
),
);
}
}
You can do it by CustomPainter without any library.
Example 1:
Create Custom Painter Class,
class customStyleArrow extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
final Paint paint = Paint()
..color = Colors.white
..strokeWidth = 1
..style = PaintingStyle.fill;
final double triangleH = 10;
final double triangleW = 25.0;
final double width = size.width;
final double height = size.height;
final Path trianglePath = Path()
..moveTo(width / 2 - triangleW / 2, height)
..lineTo(width / 2, triangleH + height)
..lineTo(width / 2 + triangleW / 2, height)
..lineTo(width / 2 - triangleW / 2, height);
canvas.drawPath(trianglePath, paint);
final BorderRadius borderRadius = BorderRadius.circular(15);
final Rect rect = Rect.fromLTRB(0, 0, width, height);
final RRect outer = borderRadius.toRRect(rect);
canvas.drawRRect(outer, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => false;
}
Wrap your text widget with CustomPaint,
return CustomPaint(
painter: customStyleArrow(),
child: Container(
padding: EdgeInsets.only(left: 15, right: 15, bottom: 20, top: 20),
child: Text("This is the custom painter for arrow down curve",
style: TextStyle(
color: Colors.black,
)),
),
);
Example 2:
Check below example code for tooltip shapedecoration
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Customize Tooltip'),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
const MyHomePage({
Key? key,
required this.title,
}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Tooltip(
child: const IconButton(
icon: Icon(Icons.info, size: 30.0),
onPressed: null,
),
message: 'Hover Icon for Tooltip...',
padding: const EdgeInsets.all(20),
showDuration: const Duration(seconds: 10),
decoration: ShapeDecoration(
color: Colors.blue,
shape: ToolTipCustomShape(),
),
textStyle: const TextStyle(color: Colors.white),
preferBelow: false,
verticalOffset: 20,
),
),
);
}
}
class ToolTipCustomShape extends ShapeBorder {
final bool usePadding;
ToolTipCustomShape({this.usePadding = true});
#override
EdgeInsetsGeometry get dimensions =>
EdgeInsets.only(bottom: usePadding ? 20 : 0);
#override
Path getInnerPath(Rect rect, {TextDirection? textDirection}) => Path();
#override
Path getOuterPath(Rect rect, {TextDirection? textDirection}) {
rect =
Rect.fromPoints(rect.topLeft, rect.bottomRight - const Offset(0, 20));
return Path()
..addRRect(
RRect.fromRectAndRadius(rect, Radius.circular(rect.height / 3)))
..moveTo(rect.bottomCenter.dx - 10, rect.bottomCenter.dy)
..relativeLineTo(10, 20)
..relativeLineTo(10, -20)
..close();
}
#override
void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) {}
#override
ShapeBorder scale(double t) => this;
}
Wrap your widget with CustomPaint refer to this article https://medium.com/flutter-community/a-deep-dive-into-custompaint-in-flutter-47ab44e3f216 and documentation for more info, should do the trick.
Try this package https://pub.dev/packages/shape_of_view_null_safe
ShapeOfView(
shape: BubbleShape(
position: BubblePosition.Bottom,
arrowPositionPercent: 0.5,
borderRadius: 20,
arrowHeight: 10,
arrowWidth: 10
),
//Your Data goes here
child: ...,
)

Flutter ClipRect and Align : how to compute the Alignment values

I want to display part of an image (a rectangle of 128 * 128 inside this image which is 512 * 512) in a rectangle in Flutter app.
Like this:
I want to select a specific zone in the source image, here from x=115, y=12 with width=128,height=128.
So here's my Flutter code to do this:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
var myWidth = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
width: myWidth,
height: myWidth,
color: Colors.yellow,
child: FittedBox(
fit: BoxFit.fill,
child: ClipRect(
child: Align(
alignment: Alignment(2.0*115.0 / 512.0 - 1, 2.0*12.0 / 512.0 -1.0),
widthFactor: 0.25,
heightFactor: 0.25,
child: Image.network(
"https://homepages.cae.wisc.edu/~ece533/images/baboon.png"),
),
),
)));
}
}
I suppose that the widthFactor and heightFactor represent the percentage of the original image I want to display - so here, because I want to display 128 pixels, it's 25% of the original width/height.
However, I just can't figure out out to calculate the values for the alignment.
First I tried for x :
alignment: Alignment(2.0*115.0 / 512.0 - 1, 2.0*12.0 / 512.0 -1.0),
Which almost gives the desired result, but not quite, see below:
I tried many other combinations to calculate the Alignment values and read all I could find with the help of Google... Is this even possible to accomplish this with a ClipRect and an Align?
Any help is welcome ;-)
NOTE : I don't want to crop the original image (and hence produce a new image), I want to keep it as downloaded to avoid having N copies of the same bitmap in memory. What I want is a specific view on the image - something that is absolutely trivial to do with OpenGL/DirectX and UV coordinates for example, but not so with Flutter.
Based on pskink comment, provided a working solution in the original post.
import 'package:flutter/material.dart';
import 'package:network_to_file_image/image_for_canvas.dart';
import 'package:network_to_file_image/network_to_file_image.dart';
import 'dart:ui' as ui;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
var myWidth = MediaQuery.of(context).size.width;
User user = User(
filename: null,
url: "https://homepages.cae.wisc.edu/~ece533/images/baboon.png",
);
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
width: myWidth,
height: myWidth,
color: Colors.yellow,
child: CustomPaint(
painter: ImagePainter(user, loadCallback: (_, __, ___) {
setState(() {});
})),
));
}
}
class ImagePainter extends CustomPainter {
final User user;
final LoadCallback<User> loadCallback;
ImagePainter(
this.user, {
required this.loadCallback,
});
#override
void paint(Canvas canvas, Size size) {
canvas.save();
canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height),
Paint()..color = Colors.lightGreenAccent);
canvas.restore();
var imageForCanvas = _imageForCanvas();
ui.Image? image = imageForCanvas.image(user);
if (image != null) {
canvas.save();
canvas.drawImageRect(
image,
Rect.fromLTWH(
12,
12,
256,
256,
),
Rect.fromLTWH(
0,
0,
size.width,
size.height,
),
Paint()..imageFilter = ui.ImageFilter.blur(sigmaX: .5, sigmaY: .5),
);
canvas.restore();
}
}
ImageForCanvas<User> _imageForCanvas() => ImageForCanvas<User>(
imageProviderSupplier: (User user) => NetworkToFileImage(
file: null,
url: user.url,
),
keySupplier: (User user) => user.url!,
loadCallback: loadCallback,
);
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
class User {
final String? filename;
final String? url;
User({
this.filename,
this.url,
});
}

How to make Custom thumb of seekbar with flutter?

I'm trying to make seekbar like below image, but unable to made.
I followed Seekbar Package plugin.
Using flutter_xlider plugin makes this a breeze.
Here is a small example from their docs:
FlutterSlider(
...
handler: FlutterSliderHandler(
decoration: BoxDecoration(),
child: Material(
type: MaterialType.canvas,
color: Colors.orange,
elevation: 3,
child: Container(
padding: EdgeInsets.all(5),
child: Icon(Icons.adjust, size: 25,)),
),
),
)
Their slider is very well documented, check it out.
if you are trying to create a custom Thumb design,
then you can extend your choice of Existing thumb class and override the drawing to get the shape you want.
check out this code in dart pad it will help you get started.
Update:
Here is the source code for the same in case the link goes offline:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Custom Slider Thumb Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: SliderTheme(
child: RangeSlider(
min: 0,
max: 100,
divisions: 10,
onChanged: (RangeValues value) {
if (value.end - value.start <= 10) return;
print('current progress: $value');
},
values: RangeValues(0, 100),
),
data: SliderThemeData(
// change size here to customize the thumb
rangeThumbShape: SliderThumbShape(thumbSize: 15.0),
),
),
),
);
}
}
class SliderThumbShape extends RangeSliderThumbShape {
final double thumbSize;
const SliderThumbShape({this.thumbSize = 10.0});
#override
Size getPreferredSize(bool isEnabled, bool isDiscrete) {
return Size.fromWidth(thumbSize);
}
#override
void paint(
PaintingContext context,
Offset center, {
Animation<double> activationAnimation,
#required Animation<double> enableAnimation,
bool isDiscrete,
bool isEnabled,
bool isOnTop,
TextDirection textDirection,
SliderThemeData sliderTheme,
Thumb thumb,
}) {
assert(context != null);
assert(center != null);
assert(enableAnimation != null);
assert(sliderTheme != null);
assert(sliderTheme.disabledThumbColor != null);
assert(sliderTheme.thumbColor != null);
final Canvas canvas = context.canvas;
final ColorTween colorTween = ColorTween(
begin: sliderTheme.disabledThumbColor,
end: sliderTheme.thumbColor,
);
canvas.drawRect(
Rect.fromCenter(center: center, height: thumbSize/2, width: thumbSize),
Paint()..color = colorTween.evaluate(enableAnimation),
);
}
}