Flutter How to create box container with arrow on top? - flutter

Hi how do i create box container with arrow on top without using any pub packages.
Like below.

You can customize ShapeBorder similar to this post. Then instead of using rect.bottomCenter for Path(), change it to rect.TopCenter to place the drawn Rect at the top.
Path()dart
..addRRect(RRect.fromRectAndRadius(rect, Radius.circular(rect.height / 2)))
..moveTo(rect.topCenter.dx - 10, rect.topCenter.dy)
..relativeLineTo(10, 20)
..relativeLineTo(20, -20)
..close();

For my case, I customized a shapeborder for flutter tooltip.
class TooltipShippingFeeBorder extends ShapeBorder{
#override
EdgeInsetsGeometry get dimensions => const EdgeInsets.only(top:20);
#override
Path getInnerPath(Rect rect, {TextDirection? textDirection}) {
return Path()
..fillType = PathFillType.evenOdd
..addPath(getOuterPath(rect), Offset.zero);
}
#override
Path getOuterPath(Rect rect, {TextDirection? textDirection}) {
rect = Rect.fromPoints(rect.topLeft, rect.bottomRight - Offset(0, 20));
return Path()
..addRRect(RRect.fromRectAndRadius(rect, const Radius.circular(6)))
..moveTo(rect.topCenter.dx - 10, rect.topCenter.dy)
..relativeLineTo(10, -20)
..relativeLineTo(20, 20)
..close();
}
#override
void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) {
}
#override
ShapeBorder scale(double t) => this;
}
And use it on tooltip like this:
Tooltip(
triggerMode: TooltipTriggerMode.tap,
padding: const EdgeInsets.only(bottom: 16, left: 10, right: 10),
decoration: ShapeDecoration(
shape: TooltipShippingFeeBorder(),
color: WalletTheme.primaryColor),
message: '$shippingFeeMessage\n',
child: const Icon(
Icons.info_outline,
size: 16,
color: WalletTheme.grey2,
),
)
So in your case, you also create the same border and use ShapreDecoration for Container.
ShapeDecoration(
shape: TooltipShippingFeeBorder(),
color: WalletTheme.primaryColor)

Related

How to make a button with rounded edges in flutter?

Making a rounded corner button is so simple, but I want to make a button that its edges are also rounded.
maybe I should use CustomPaint?
SquircleBorder might help you:
Container(
width: 56.0,
height: 56.0,
child: Material(
color: Colors.blueGrey[400],
shape: SquircleBorder(
side: BorderSide(color: Colors.grey, width: 3.0),
),
child: Icon(Icons.settings),
),
),
class SquircleBorder extends ShapeBorder {
final BorderSide side;
final double superRadius;
const SquircleBorder({
this.side: BorderSide.none,
this.superRadius: 5.0,
})
: assert(side != null),
assert(superRadius != null);
#override
EdgeInsetsGeometry get dimensions => EdgeInsets.all(side.width);
#override
ShapeBorder scale(double t) {
return new SquircleBorder(
side: side.scale(t),
superRadius: superRadius * t,
);
}
#override
Path getInnerPath(Rect rect, {TextDirection textDirection}) {
return _squirclePath(rect.deflate(side.width), superRadius);
}
#override
Path getOuterPath(Rect rect, {TextDirection textDirection}) {
return _squirclePath(rect, superRadius);
}
static Path _squirclePath(Rect rect, double superRadius) {
final c = rect.center;
final dx = c.dx * (1.0 / superRadius);
final dy = c.dy * (1.0 / superRadius);
return new Path()
..moveTo(c.dx, 0.0)
..relativeCubicTo(c.dx - dx, 0.0, c.dx, dy, c.dx, c.dy)
..relativeCubicTo(0.0, c.dy - dy, -dx, c.dy, -c.dx, c.dy)
..relativeCubicTo(-(c.dx - dx), 0.0, -c.dx, -dy, -c.dx, -c.dy)
..relativeCubicTo(0.0, -(c.dy - dy), dx, -c.dy, c.dx, -c.dy)
..close();
}
#override
void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) {
switch (side.style) {
case BorderStyle.none:
break;
case BorderStyle.solid:
var path = getOuterPath(rect.deflate(side.width / 2.0), textDirection: textDirection);
canvas.drawPath(path, side.toPaint());
}
}
}
Use a ContinuousRectangleBorder shape:
ElevatedButton(
style: ElevatedButton.styleFrom(
shape: ContinuousRectangleBorder(
side: BorderSide.none,
borderRadius: BorderRadius.all(Radius.circular(18)),
),
),
onPressed: () {},
child: Text('Click'),
);
That shape is called a Squircle. See: https://en.wikipedia.org/wiki/Squircle

Custom Shape for Container

Idea is to make a custom shaped container by giving it ShapeDecoration().
I used this thread as a reference.
Eventialy I achieved the shape I wanted, but once I wrap this custom shaped container with margin\padding\SizedBoxes around it - it's content is being pushed out of the bounds of the container. Check out screenshots.
Normaly it should be smth like this:
but with paddings between elements.
So the problem is that my customized container behavers realy wierd once it has any margin\padding arround it.
return Padding(
padding: const EdgeInsets.symmetric(vertical: 40),
child: Container(
padding: const EdgeInsets.all(8),
height: 88,
alignment: Alignment.center,
decoration: ShapeDecoration(
shape: UnitListItemBorderShape(
color: _isCurrent ? theme.listItemBorderColor : theme.listItemBackgroundColor,
),
color: theme.listItemBackgroundColor,
),
child: Stack(
children: [
//custom container's ineer content
] ,
),
);
UnitListItemBorderShape class:
class UnitListItemBorderShape extends ShapeBorder {
const UnitListItemBorderShape({color}) : _color = color;
final Color _color;
#override
EdgeInsetsGeometry get dimensions => const EdgeInsets.all(0);
#override
Path getInnerPath(Rect rect, {TextDirection textDirection}) => null;
#override
Path getOuterPath(Rect rect, {TextDirection textDirection}) => UnitListItemShape.getShape(
rect.width,
rect.height,
const Radius.circular(16),
const Radius.circular(20),
);
#override
void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) {
final Paint borderPaint = Paint()
..color = _color
..style = PaintingStyle.stroke
..strokeWidth = 2;
canvas.drawPath(getOuterPath(rect), borderPaint);
}
#override
ShapeBorder scale(double t) => null;
}
UnitListItemShape class:
class UnitListItemShape {
static Path getShape(double width, double height, Radius borderRadius, Radius circleRadius) {
final double rightOffset = circleRadius.x;
final Rect rect = Rect.fromCenter(center: Offset(width - rightOffset - 4, height / 2), width: 48, height: 48);
return Path()
..moveTo(borderRadius.x, 0)
..lineTo(width - borderRadius.x - rightOffset, 0)
..arcToPoint(Offset(width - rightOffset, borderRadius.x), radius: borderRadius)
..lineTo(width - rightOffset, (height / 2) - rightOffset - 4)
// ..addRect(rect)
..arcTo(rect, -70 * math.pi / 180, 150 * math.pi / 180, false)
..lineTo(width - rightOffset, height - borderRadius.x)
..arcToPoint(Offset(width - borderRadius.x - rightOffset, height), radius: borderRadius)
..lineTo(borderRadius.x, height)
..arcToPoint(Offset(0, height - borderRadius.x), radius: borderRadius)
..lineTo(0, borderRadius.x)
..arcToPoint(Offset(borderRadius.x, 0), radius: borderRadius)
..fillType = PathFillType.evenOdd
..close();
}
}

Align Text in custom created Shape : Flutter

I have created one Custom shape in Flutter. The issue I am facing is, I have used ShapeBorder and assigned it Card. I want to align my text inside the drawn widget but currently it's also considering oursider view as a part of a widget.
Here is the code I have used:
Align(
child: Container(
height: 250,
width: 300,
child: Card(
clipBehavior: Clip.hardEdge,
shape: Shape1(factor: 0.8),
child: Container(
padding: EdgeInsets.only(left: 16.0),
child: Align(
alignment: Alignment.bottomLeft,
child: Text(
'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book',
// style: textStyleNotoSansRegular(),
),
),
),
),
),
widthFactor: 0.8,
),
Shape Class:
class Shape1 extends ShapeBorder {
final double factor;
Shape1({this.factor});
#override
EdgeInsetsGeometry get dimensions => EdgeInsets.zero;
#override
Path getInnerPath(Rect rect, {TextDirection textDirection}) => null;
#override
Path getOuterPath(Rect rect, {TextDirection textDirection}) {
return Path()
..moveTo(rect.bottomLeft.dx, rect.bottomLeft.dy)
..relativeLineTo(rect.width * factor, 0)
..lineTo(rect.topRight.dx, rect.topRight.dy)
..relativeLineTo(rect.width * -factor, 0)
..close();
}
#override
void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) {
var path = Path()
..moveTo(rect.bottomLeft.dx, rect.bottomLeft.dy)
..relativeLineTo(rect.width * factor, 0)
..lineTo(rect.topRight.dx, rect.topRight.dy)
..relativeLineTo(rect.width * -factor, 0)
..close();
var boxPainter = Paint();
boxPainter.strokeWidth = 5;
boxPainter.color = Colors.yellow;
boxPainter.style = PaintingStyle.stroke;
canvas.drawPath(path, boxPainter);
}
#override
ShapeBorder scale(double t) => null;
}
Current Result:
Expected Result:

Unable to set gradient color to my custom shape border in flutter app

I have created a custom shape using CustomBorder class, and I want to set a gradient color to my custom shape. Please see the below code that I have tried.
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomLeft,
end: Alignment.topRight,
colors: [Colors.orangeAccent, Colors.orange]
)
),
child: Material(
color: Colors.deepOrangeAccent,
shape: CustomShapeBorder(),
child: IconButton(
icon: FaIcon(FontAwesomeIcons.instagram),
iconSize: 30.0,
padding: const EdgeInsets.only(top: 60.0, left: 30.0),
color: Colors.white,
),
),
)
My CustomShapeBorder() class :
class CustomShapeBorder extends ShapeBorder {
final double distanceFromWall = 12;
final double controlPointDistanceFromWall = 5;
#override
// TODO: implement dimensions
EdgeInsetsGeometry get dimensions => null;
#override
Path getInnerPath(Rect rect, {TextDirection textDirection}) {
// TODO: implement getInnerPath
return null;
}
#override
Path getOuterPath(Rect rect, {TextDirection textDirection}) {
// TODO: implement getOuterPath
return getClip(Size(260.0,180.0));
}
#override
void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) {
// TODO: implement paint
}
#override
ShapeBorder scale(double t) {
// TODO: implement scale
return null;
}
Path getClip(Size size) {
Path clippedPath = new Path();
clippedPath.lineTo(0, size.height);
clippedPath.quadraticBezierTo(30, size.height + 10, size.width * 0.20, size.height - 50);
clippedPath.quadraticBezierTo(70, size.height - 120, size.width * 0.40, size.height * 0.35);
clippedPath.quadraticBezierTo(180, (size.height - (size.height* 0.6)), size.width - 40 , 32 );
clippedPath.quadraticBezierTo(250, 0, size.width, 0);
clippedPath.lineTo(size.width, 0);
clippedPath.close();
return clippedPath;
}
}
Output:(Just refer to the upper custom shape, forget the bottom one)
If I remove the color: Colors.deepOrangeAccent from child: Material then the output is :
BoxDecoration is optimized for rectangular widgets. Since the widget here that you'd like to apply gradient is similar to a blob. It's best to use ShapeDecoration instead. Also, Material should be used as a parent Widget and not a child of a Widget.
Container(
decoration: ShapeDecoration(...),
child: IconButton(...),
)

Text between 2 containers in flutter

I would like to show a text between 2 containers in flutter. The problem is that the containers adapt to the size of the text. I do not want that behavior. want something like this. (Am very new to flutter).
I want to make a music player. The text can not be split.
Edit: Accordingly to what you've asked, you want to create a custom player that updates its color based on the song current position.
For that, you can create a CustomPaint widget with a CustomPainter player that updates whenever the song state changes.
class MyPlayerBar extends CustomPainter {
MyPlayerBar({this.fullSongTimeInSeconds, this.currentSecond});
final int fullSongTimeInSeconds;
final int currentSecond;
#override
void paint(Canvas canvas, Size size) {
Paint paint = Paint();
double cursor = (currentSecond * size.width) / fullSongTimeInSeconds;
Radius cornerRadius = Radius.circular(3.0);
// Already played half color (your darker orange)
paint.color = Color.fromRGBO(206, 69, 0, 1.0);
// Painting already played half
canvas.drawRRect(
RRect.fromRectAndCorners(Rect.fromLTWH(0.0, 0.0, cursor, size.height),
topLeft: cornerRadius, bottomLeft: cornerRadius),
paint);
// Yet to play half color (your lighter orange)
paint.color = Color.fromRGBO(227, 113, 18, 1.0);
// Painting the remaining space
canvas.drawRRect(
RRect.fromRectAndCorners(Rect.fromLTWH(cursor, 0.0, size.width - cursor, size.height),
bottomRight: cornerRadius, topRight: cornerRadius),
paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
I've created a full example that simulates a 3 minute song (180 seconds) that will result in the following:
Full example code:
class MyPlayer extends StatefulWidget {
_MyPlayerState createState() => _MyPlayerState();
}
class _MyPlayerState extends State<MyPlayer> {
int _songCurrentPosition = 0;
int _fullSongInSeconds = 180; // 3 minutes song
#override
void initState() {
super.initState();
_songPlaying();
}
void _songPlaying() async {
if (_songCurrentPosition >= _fullSongInSeconds) return;
await Future.delayed(Duration(seconds: 1));
setState(() => _songCurrentPosition += 1);
_songPlaying();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('My player'),
),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: CustomPaint(
painter: MyPlayerBar(
currentSecond: _songCurrentPosition, // Your current song position in seconds
fullSongTimeInSeconds: _fullSongInSeconds,
),
child: Container(
alignment: Alignment.center,
height: 30.0,
width: double.infinity,
child: Text(
'Playing: 01 - Hey, this is my life',
style: TextStyle(color: Colors.white, fontWeight: FontWeight.w500),
),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(10.0),
),
),
),
),
),
);
}
}
class MyPlayerBar extends CustomPainter {
MyPlayerBar({this.fullSongTimeInSeconds, this.currentSecond});
final int fullSongTimeInSeconds;
final int currentSecond;
#override
void paint(Canvas canvas, Size size) {
Paint paint = Paint();
double cursor = (currentSecond * size.width) / fullSongTimeInSeconds;
Radius cornerRadius = Radius.circular(3.0);
// Already played half color (your darker orange)
paint.color = Color.fromRGBO(206, 69, 0, 1.0);
// Painting already played half
canvas.drawRRect(
RRect.fromRectAndCorners(Rect.fromLTWH(0.0, 0.0, cursor, size.height),
topLeft: cornerRadius, bottomLeft: cornerRadius),
paint);
// Yet to play half color (your lighter orange)
paint.color = Color.fromRGBO(227, 113, 18, 1.0);
// Painting the remaining space
canvas.drawRRect(
RRect.fromRectAndCorners(Rect.fromLTWH(cursor, 0.0, size.width - cursor, size.height),
bottomRight: cornerRadius, topRight: cornerRadius),
paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}