everyone how can i get like this icon's border in flutter
i need to set color only for left , bottom and top sides
i heard someone talk about customPainter but i don't nkow how to use plz help me:
enter image description here
this my code:
Container(
decoration:BoxDecoration(
shape: BoxShape.circle,
border: new Border(
left: BorderSide(
color: Theme.of(context).primaryColor,
width: 2,),
right: BorderSide(
color: Theme.of(context).primaryColor,
width: 2,),
bottom: BorderSide( color: Theme.of(context).primaryColor,
width: 2,),
top: BorderSide(color: Theme.of(context).primaryColor,
width: 2,),),
) ,
child:ClipOval(
child: Image.asset('images/imageout1.png',width: 85,),
))
As you said, you can use a CustomPainter. The key is the use of drawArc
Return this somewhere in your widget build method
CustomPaint(
size: Size.square(100),
painter: CirclePainter(),
)
Create CirclePainter
class CirclePainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
Paint innerLine = Paint()
..color = Colors.white
..style = PaintingStyle.stroke
..strokeWidth = 8.0;
Paint outerLine = Paint()
..color = Colors.orange
..style = PaintingStyle.stroke
..strokeWidth = 3.0;
canvas.drawArc(Rect.fromCircle(center: Offset(size.width / 2, size.height / 2), radius: size.width / 2),
0, 2 * pi, false, innerLine);
canvas.drawArc(
Rect.fromCircle(center: Offset(size.width / 2, size.height / 2), radius: (size.width + 12) / 2),
1.9 * pi,
1.2 * pi,
false,
outerLine);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
Result
Related
In Flutter I try to make a segmented ring (or radial gauge) around a number to indicate its value. Like here
The example of in the link is already a solution itself, however, I read syncfusion widgets are not free. (I am using it commercially)
Any alternatives or ideas how to set this into practice?
You can use CustomPainter to achieve the same,
class RingPainter extends CustomPainter {
const RingPainter({
required this.percentage,
this.startColor,
this.endColor,
this.width,
}) : assert(percentage >= 0 && percentage <= 100,
"Percentage must be in the range 0-100!");
final double percentage;
final Color? startColor;
final Color? endColor;
final double? width;
double get progress => percentage / 100;
#override
void paint(Canvas canvas, Size size) {
var angle = math.pi / 180 * 230;
canvas.rotateAroundCenter(size, angle);
canvas.drawRing(
size,
1,
startColor: Colors.black12,
endColor: Colors.black12,
width: width,
);
canvas.drawRing(
size,
progress,
startColor: startColor,
endColor: endColor,
width: width,
);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => false;
}
extension on Canvas {
rotateAroundCenter(Size size, double angleInRadians) {
final double r =
math.sqrt(size.width * size.width + size.height * size.height) / 2;
final alpha = math.atan(size.height / size.width);
final beta = alpha + angleInRadians;
final shiftY = r * math.sin(beta);
final shiftX = r * math.cos(beta);
final translateX = size.width / 2 - shiftX;
final translateY = size.height / 2 - shiftY;
translate(translateX, translateY);
rotate(angleInRadians);
}
drawRing(
Size size,
double value, {
Color? startColor,
Color? endColor,
double? width,
}) {
final rect = Rect.fromLTWH(-15, 0.0, size.width, size.height);
final gradient = SweepGradient(
startAngle: 3 * math.pi / 2,
endAngle: 7 * math.pi / 2,
tileMode: TileMode.repeated,
colors: [
startColor ?? Colors.pink,
endColor ?? Colors.blueAccent,
],
);
final paint = Paint()
..shader = gradient.createShader(rect)
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke
..strokeWidth = width ?? 24;
final center = Offset(size.width / 2, size.height / 2);
final radius =
math.min(size.width / 2, size.height / 2) - ((width ?? 24) / 2);
const startAngle = -math.pi / 2;
final sweepAngle = 2 * math.pi * value * 0.723;
drawArc(
Rect.fromCircle(center: center, radius: radius),
startAngle,
sweepAngle,
false,
paint,
);
}
}
Use it with CustomPaint widget,
CustomPaint(
painter: RingPainter(
percentage: 70,
width: 20,
),
)
In case, you want text inside ring,
Center(
child: SizedBox(
width: 200,
height: 200,
child: Stack(
fit: StackFit.expand,
children: [
const Center(
child: Text(
"70%",
style: TextStyle(
fontSize: 48,
fontWeight: FontWeight.w900,
color: Colors.purple,
),
),
),
CustomPaint(
painter: RingPainter(
percentage: 70,
width: 20,
),
),
],
),
),
)
I have a complex design, I don't know what to do with flutter, is there any help on how to implement this design?
Usually to create complex designs I prefer using Flutter Shape Maker.
All you need is to upload your svg picture and it will convert it to CustomPaint code in flutter. Perhaps this may help you.
I have tried to achieve a shape and the center painter here. Few things, I am able to achieve but for complete part, I think you need to use pie chart https://pub.dev/packages/syncfusion_flutter_charts specially Doughnut type.
Please check my sample as below:
This painter is used to prepare the pie.
class WheelPainter extends CustomPainter {
Path getWheelPath(double wheelSize, double fromRadius, double toRadius) {
return new Path()
..moveTo(wheelSize, wheelSize)
..arcTo(
Rect.fromCircle(
radius: wheelSize, center: Offset(wheelSize, wheelSize)),
fromRadius,
toRadius,
false)
..close();
}
Paint getColoredPaint(Color color) {
Paint paint = Paint();
paint.color = color;
return paint;
}
#override
void paint(Canvas canvas, Size size) {
double wheelSize = 150;
double nbElem = 6;
double radius = (2 * pi) / nbElem;
// canvas.drawPath(getWheelPath(wheelSize, 0, radius), getColoredPaint(Colors.red));
canvas.drawShadow(getWheelPath(wheelSize, radius * 0.5, radius * 2).shift(Offset(0, -10)), Colors.black, 10.0, true);
canvas.drawPath(getWheelPath(wheelSize, radius * 0.5, radius * 2),
getColoredPaint(Colors.purple));
// canvas.drawPath(getWheelPath(wheelSize, radius * 2, radius), getColoredPaint(Colors.blue));
canvas.drawShadow(getWheelPath(wheelSize, radius * 2.7, radius * 1.7).shift(Offset(0, -10)), Colors.black, 10.0, true);
canvas.drawPath(getWheelPath(wheelSize, radius * 2.7, radius * 1.7),
getColoredPaint(Colors.green));
// canvas.drawPath(getWheelPath(wheelSize, radius * 4, radius), getColoredPaint(Colors.yellow));
canvas.drawShadow(getWheelPath(wheelSize, radius * 4.6, radius * 1.7).shift(Offset(0, -10)), Colors.black, 10.0, true);
canvas.drawPath(getWheelPath(wheelSize, radius * 4.6, radius * 1.7),
getColoredPaint(Colors.orange));
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return oldDelegate != this;
}
}
Below is the sample to use it.
Stack(alignment: Alignment.center, children: [
CustomPaint(
size: Size(300, 300),
painter: WheelPainter(),
),
Container(
width: 150,
height: 150,
decoration:
BoxDecoration(shape: BoxShape.circle, color: Colors.white),
),
Container(
width: 110,
height: 110,
decoration:
BoxDecoration(shape: BoxShape.circle, color: Colors.white, boxShadow: [
BoxShadow(
color: Colors.grey,
blurRadius: 10.0,
blurStyle: BlurStyle.outer,
spreadRadius: 3.0,
offset: Offset(1.0,1.0)
)
]),
)
]),
This is how it will look like.
Hope it may help you.
You can take two container in Stack Widget
and implement customPaint
customPaint
You can try packges from pub.dev for this and you can customise as you need in app this designs.
syncfusion_flutter-chart
Try above package for your requirements
I want to get with custom painter something just like this. How I can draw it? For me not problem borders, gradients. I couldn't draw left part of my assets card. Please, help!
You can use shader on Paint to have gradient effect.
Paint paint = Paint()
..shader = const LinearGradient(
colors: [
Color.fromARGB(255, 141, 23, 15),
Colors.red,
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
).createShader(
Rect.fromLTRB(0, 0, size.width, size.height),
)
Run on dartPad
The shape class
class EatenShape extends CustomPainter {
final double gap = 4.0;
final double radius;
final Radius _border;
final Color canvasColor;
EatenShape({
this.radius = 40,
required this.canvasColor,
}) : _border = Radius.circular(radius);
#override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..shader = const LinearGradient(
colors: [
Color.fromARGB(255, 141, 23, 15),
Colors.red,
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
).createShader(
Rect.fromLTRB(0, 0, size.width, size.height),
)
..style = PaintingStyle.fill;
final _rect = Rect.fromLTRB(
0,
gap,
size.height - gap * 2,
size.height - gap,
);
///left Circle
Path fullPath = Path()
..addOval(_rect)
///eaten shape
..addRRect(
RRect.fromLTRBAndCorners(
size.height * .5,
0,
size.width,
size.height,
bottomLeft: _border,
topLeft: _border,
bottomRight: _border,
topRight: _border,
),
);
Path drawPath = Path()..addPath(fullPath, Offset.zero);
canvas.drawPath(drawPath, paint);
Paint holoPaint = Paint()
..style = PaintingStyle.stroke
..strokeWidth = gap
..color = canvasColor;
canvas.drawOval(_rect, holoPaint);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
I've tried with Path's fillType, not sure about the issue I've faced there. Another thing can be done just using Container with decoration without using CustomPaint.
You can use this paint as
SizedBox(
width: 300,
height: 70,
child: Stack(
children: [
Positioned.fill(
child: CustomPaint(
painter: EatenShape(
canvasColor: Theme.of(context).scaffoldBackgroundColor,
),
),
),
],
),
),
I want to design a widget of shape of a chat bubble where one corner is pinned and its height should adjust to the lines of the text? For now I'm using ClipRRect widget with some borderRadius. But I want one corner pinned. Any suggestions ?
UPDATE
I know this can be done using a stack but I'm looking for a better solution since I have to use it many times in a single view and using many stacks might affect the performs. ( correct me here if I'm wrong )
For someone who want this get done with library. You can add bubble: ^1.1.9+1 (Take latest) package from pub.dev and wrap your message with Bubble.
Bubble(
style: right ? styleMe : styleSomebody,
//Your message content child here...
)
Here right is boolean which tells the bubble is at right or left, Write your logic for that and add the style properties styleMe and styleSomebody inside your widget as shown below. Change style according to your theme.
double pixelRatio = MediaQuery.of(context).devicePixelRatio;
double px = 1 / pixelRatio;
BubbleStyle styleSomebody = BubbleStyle(
nip: BubbleNip.leftTop,
color: Colors.white,
elevation: 1 * px,
margin: BubbleEdges.only(top: 8.0, right: 50.0),
alignment: Alignment.topLeft,
);
BubbleStyle styleMe = BubbleStyle(
nip: BubbleNip.rightTop,
color: Colors.grey,
elevation: 1 * px,
margin: BubbleEdges.only(top: 8.0, left: 50.0),
alignment: Alignment.topRight,
);
Hi im also searching for a chat bubble shaped widget finally i made one.
I have made this in custom Painter and i'm not good at it.
import 'package:flutter/material.dart';
class ChatBubble extends CustomPainter {
final Color color;
final Alignment alignment;
ChatBubble({
#required this.color,
this.alignment,
});
var _radius = 10.0;
var _x = 10.0;
#override
void paint(Canvas canvas, Size size) {
if (alignment == Alignment.topRight) {
canvas.drawRRect(
RRect.fromLTRBAndCorners(
0,
0,
size.width - 8,
size.height,
bottomLeft: Radius.circular(_radius),
topRight: Radius.circular(_radius),
topLeft: Radius.circular(_radius),
),
Paint()
..color = this.color
..style = PaintingStyle.fill);
var path = new Path();
path.moveTo(size.width - _x, size.height - 20);
path.lineTo(size.width - _x, size.height);
path.lineTo(size.width, size.height);
canvas.clipPath(path);
canvas.drawRRect(
RRect.fromLTRBAndCorners(
size.width - _x,
0.0,
size.width,
size.height,
topRight: Radius.circular(_radius),
),
Paint()
..color = this.color
..style = PaintingStyle.fill);
} else {
canvas.drawRRect(
RRect.fromLTRBAndCorners(
_x,
0,
size.width,
size.height,
bottomRight: Radius.circular(_radius),
topRight: Radius.circular(_radius),
topLeft: Radius.circular(_radius),
),
Paint()
..color = this.color
..style = PaintingStyle.fill);
var path = new Path();
path.moveTo(0, size.height);
path.lineTo(_x, size.height);
path.lineTo(_x, size.height-20);
canvas.clipPath(path);
canvas.drawRRect(
RRect.fromLTRBAndCorners(
0,
0.0,
_x,
size.height,
topRight: Radius.circular(_radius),
),
Paint()
..color = this.color
..style = PaintingStyle.fill);
}
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
copy and paste the above code and paste in your project
Align(
alignment: alignment, //Change this to Alignment.topRight or Alignment.topLeft
child: CustomPaint(
painter: ChatBubble(color: Colors.blue, alignment: alignment),
child: Container(
margin: EdgeInsets.all(10),
child: Stack(
children: <Widget>[
TextView("Hello World"),
],
),
),
),
)
paste this code where you have to show chatBubble Widget.
And i have also upload this code in bitbucket ChatBubble Widget Please be free if you have anything to contribute.
Sorry I am not able to show you the code for it but I can present an idea that might work if you implement it correctly. Suppose the Widget you made with ClipRect is called MyChatBubbleRect. Now, make another widget that draws a triangle using CustomPainter, let's call it MyChatBubbleTriangle, of course fill it with same color as the chat bubble but you can use a different color initially for debugging. Now that we have two widgets we can stack 'em together on top of each other and using Positioned widget over the MyChatBubbleTriangle. Something like this:
Stack(
children : [
MyChatBubbleRect(), // Maybe decrease the width a bit
Positioned(
top: 0,
right: 0,
child: MyChatBubbleTriangle()
)
]
)
This is just an idea I think you can pursue. Sorry couldn't provide the proper source code.
Chat Body
DecoratedBox(
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(8.0),
),
child: Text("your message goes here"),
);
Make a custom Triangle
class ChatBubbleTriangle extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
var paint = Paint()..color = Colors.blue;
var path = Path();
path.lineTo(-10, 0);
path.lineTo(0, 10);
path.lineTo(10, 0);
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
Use both of them within a stack wrapping ChatBubbleTriangle with Positioned() widget
I am building a list of boxes layouts in my app using flutter. I want dotted border around the box. I have used card widget to create the boxes. But, how can I get dotted border around the boxes?
EDIT
I have added this as a package in pub.
Now, all you need to do is
DottedBorder(
color: Colors.black,
gap: 3,
strokeWidth: 1,
child: FlutterLogo(size: 148),
)
Working Solution [Outdated]
Like tomerpacific said in this answer, Flutter does not have a default implementation for dashed border at the moment.
I worked for some time yesterday and was able to come up with a solution using CustomPainter. Hope this helps someone.
Add the DashedRect to your container, like so
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Container(
height: 400,
width: 300,
color: Colors.black12,
child: DashedRect(color: Colors.red, strokeWidth: 2.0, gap: 3.0,),
),
),
);
}
}
DashedRect.dart
import 'package:flutter/material.dart';
import 'dart:math' as math;
class DashedRect extends StatelessWidget {
final Color color;
final double strokeWidth;
final double gap;
DashedRect(
{this.color = Colors.black, this.strokeWidth = 1.0, this.gap = 5.0});
#override
Widget build(BuildContext context) {
return Container(
child: Padding(
padding: EdgeInsets.all(strokeWidth / 2),
child: CustomPaint(
painter:
DashRectPainter(color: color, strokeWidth: strokeWidth, gap: gap),
),
),
);
}
}
class DashRectPainter extends CustomPainter {
double strokeWidth;
Color color;
double gap;
DashRectPainter(
{this.strokeWidth = 5.0, this.color = Colors.red, this.gap = 5.0});
#override
void paint(Canvas canvas, Size size) {
Paint dashedPaint = Paint()
..color = color
..strokeWidth = strokeWidth
..style = PaintingStyle.stroke;
double x = size.width;
double y = size.height;
Path _topPath = getDashedPath(
a: math.Point(0, 0),
b: math.Point(x, 0),
gap: gap,
);
Path _rightPath = getDashedPath(
a: math.Point(x, 0),
b: math.Point(x, y),
gap: gap,
);
Path _bottomPath = getDashedPath(
a: math.Point(0, y),
b: math.Point(x, y),
gap: gap,
);
Path _leftPath = getDashedPath(
a: math.Point(0, 0),
b: math.Point(0.001, y),
gap: gap,
);
canvas.drawPath(_topPath, dashedPaint);
canvas.drawPath(_rightPath, dashedPaint);
canvas.drawPath(_bottomPath, dashedPaint);
canvas.drawPath(_leftPath, dashedPaint);
}
Path getDashedPath({
#required math.Point<double> a,
#required math.Point<double> b,
#required gap,
}) {
Size size = Size(b.x - a.x, b.y - a.y);
Path path = Path();
path.moveTo(a.x, a.y);
bool shouldDraw = true;
math.Point currentPoint = math.Point(a.x, a.y);
num radians = math.atan(size.height / size.width);
num dx = math.cos(radians) * gap < 0
? math.cos(radians) * gap * -1
: math.cos(radians) * gap;
num dy = math.sin(radians) * gap < 0
? math.sin(radians) * gap * -1
: math.sin(radians) * gap;
while (currentPoint.x <= b.x && currentPoint.y <= b.y) {
shouldDraw
? path.lineTo(currentPoint.x, currentPoint.y)
: path.moveTo(currentPoint.x, currentPoint.y);
shouldDraw = !shouldDraw;
currentPoint = math.Point(
currentPoint.x + dx,
currentPoint.y + dy,
);
}
return path;
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
I do not expect this to fit in with all use cases and there is a lot of room for customization and improvement. Comment if you find any bugs.
You can use dotted_border Flutter package
return DottedBorder(
borderType: BorderType.RRect,
radius: Radius.circular(20),
dashPattern: [10, 10],
color: Colors.grey,
strokeWidth: 2,
child: Card(
color: Colors.amber,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
child: Center(child: Text("hi")),
)
There is an one plugin for draw dotted border around widgets
https://pub.dev/packages/dotted_border
Using this plugin you can draw dotted or dashed border
//1. Install the plugin by add dependencies in pubspace.yaml
dotted_border: ^1.0.6
Add below code for show border
DottedBorder(
color: Colors.black,
strokeWidth: 1,
child: FlutterLogo(size: 148),
)
BorderStyle.none can be useful if you wanna apply some animation or remove\add border function onTap(like a lighting border) event or similar.