I need make container with angle for chat messaging application.
enter image description here
return Container(
margin: EdgeInsets.only(left: 30, top: 100, right: 30, bottom: 50),
height: double.infinity,
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(10),
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10)
),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset: Offset(0, 3), // changes position of shadow
),
],
),
Please help, how make it?
Here you can go, make a widget and call that widget for use.
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
Positioned(
top: 20,
left: 20,
child: Container(
height: 50,
width: 300,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(10),
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10)),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset: Offset(0, 3), // changes position of shadow
),
],
),
),
),
Positioned(
top: 70,
left: 300,
child: CustomPaint(painter: triangle()),
)
],
));
}
The custom paint, you can call the below widget.
class triangle 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;
}
}
Now just edit the path as you like to do.
Changed my answer and adapted from Flutter - ClipPath
Container(
margin:
EdgeInsets.only(left: 30, top: 100, right: 30, bottom: 50),
height: 100,
width: double.infinity,
decoration: ShapeDecoration(
color: Colors.white,
shape: MessageBorder(),
shadows: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset: Offset(0, 3), // changes position of shadow
),
],
),
),
class MessageBorder extends ShapeBorder {
final bool usePadding;
MessageBorder({this.usePadding = true});
#override
EdgeInsetsGeometry get dimensions =>
EdgeInsets.only(bottom: usePadding ? 20 : 0);
#override
Path getInnerPath(Rect rect, {TextDirection textDirection}) => null;
#override
Path getOuterPath(Rect rect, {TextDirection textDirection}) {
rect = Rect.fromPoints(rect.topLeft, rect.bottomRight - Offset(0, 20));
return Path()
..addRRect(RRect.fromLTRBAndCorners(
rect.left, rect.top, rect.right, rect.bottom,
topLeft: Radius.circular(10),
topRight: Radius.circular(10),
bottomRight: Radius.circular(10)))
..moveTo(30, rect.bottomCenter.dy)
..relativeLineTo(0, 20)
..relativeLineTo(20, -20)
..close();
}
#override
void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) {}
#override
ShapeBorder scale(double t) => this;
}
Related
I'm new to flutter and I'm currently learning about making tabBar. I wanted to achieve something like the image below, where on my current active tab there will be an arrow indented towards the other inactive tab. How can I achieve this ? Should I use stack ? And I also need this to be responsive on different screen.
Here's my current code:
Stack(
alignment: AlignmentDirectional.topCenter,
children: [
TabBar(
controller: collabTabController,
labelColor: Colors.white,
labelStyle: weight500Style,
unselectedLabelColor: defaultProfileColor,
unselectedLabelStyle: weight500Style,
indicator: ShapeDecoration(
shape: RoundedRectangleBorder(
borderRadius:
selectedTabIndex == 0
? const BorderRadius.only(
bottomLeft: Radius.circular(15),
topLeft: Radius.circular(15),
)
: const BorderRadius.only(
bottomRight: Radius.circular(15),
topRight: Radius.circular(15),
)
),
color: selectedTabIndex == 0 ? personalCardTag : Colors.orange,
),
tabs: [
Tab(text:'text 1'.tr()),
Tab(text:'text 2'.tr()),
],
),
RotatedBox(
quarterTurns: 1,
child: ClipPath(
clipper: Triangle(),
child: Container(
color: formBackgroundColor,
width: 40,
height: 20,
),
),
),
],
),
Try this :
class TabBarPage extends StatefulWidget {
const TabBarPage({super.key});
#override
State<TabBarPage> createState() => _TabBarPageState();
}
class _TabBarPageState extends State<TabBarPage>
with SingleTickerProviderStateMixin {
int selectedTabIndex = 0;
TabController? collabTabController;
#override
void initState() {
super.initState();
collabTabController = TabController(length: 2, vsync: this);
}
#override
Widget build(BuildContext context) {
double ScreenWidth = MediaQuery.of(context).size.width;
return Scaffold(
body: SafeArea(
child: Stack(
alignment: AlignmentDirectional.topCenter,
children: [
TabBar(
controller: collabTabController,
labelColor: Colors.white,
unselectedLabelColor: Colors.blue,
onTap: (value) {
selectedTabIndex = value;
setState(() {});
},
indicator: ShapeDecoration(
shape: RoundedRectangleBorder(
borderRadius: selectedTabIndex == 0
? const BorderRadius.only(
bottomLeft: Radius.circular(15),
topLeft: Radius.circular(15),
)
: const BorderRadius.only(
bottomRight: Radius.circular(15),
topRight: Radius.circular(15),
)),
color: selectedTabIndex == 0 ? Colors.amber : Colors.orange,
),
tabs: [
Tab(text: 'text 1'),
Tab(text: 'text 2'),
],
),
selectedTabIndex == 0
? Positioned(
left: ScreenWidth * 0.5,
child: RotatedBox(
quarterTurns: selectedTabIndex == 0 ? 0 : 2,
child: ClipPath(
clipper: Triangle(),
child: Container(
height: 48,
width: 40,
color: selectedTabIndex == 0
? Colors.amber
: Colors.orange,
),
),
),
)
: Positioned(
right: ScreenWidth * 0.5,
child: RotatedBox(
quarterTurns: 2,
child: ClipPath(
clipper: Triangle(),
child: Container(
height: 48,
width: 40,
color: Colors.orange,
),
),
),
),
],
),
),
);
}
}
class Triangle extends CustomClipper<Path> {
#override
Path getClip(Size size) {
var path = Path()
..lineTo(size.width * 0.8, size.height * 0.4)
..cubicTo(size.width * 0.8, size.height * 0.4, size.width,
size.height * 0.5, size.width * 0.8, size.height * 0.6)
..lineTo(0, size.height)
..close();
return path;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
I currently have this code where I am trying to apply a specific type of corner to a container.
Eg.
class TestCode extends StatelessWidget {
const TestCode({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
width: 358,
height: 177,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(topLeft: Radius.circular(30)),
color: Color(0x6b000000),
shape: BoxShape.rectangle,
),
),
),
);
}
}
What I want to do is not to have rounded corners but cut off corners in a container.
You can use CustomPainter, first crate this class:
class CustomDraw extends CustomPainter {
late Paint painter;
CustomDraw(BuildContext buildContext, Color color) {
painter = Paint()
..color = color
..style = PaintingStyle.fill;
}
#override
void paint(Canvas canvas, Size size) {
var path = Path();
path.moveTo(0, size.height * 0.2);
path.lineTo(size.height * 0.2, 0);
path.lineTo(size.width, 0);
path.lineTo(size.width, size.height * 0.8);
path.lineTo(size.width - size.height * 0.2, size.height);
path.lineTo(0, size.height);
path.close();
canvas.drawPath(path, painter);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
then use it like this:
Container(
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(),
child: CustomPaint(
size: Size(300, 100),
painter: CustomDraw(context, Colors.red),
),
),
here is the easiest way:
Material(
clipBehavior: Clip.antiAlias,
shape: const BeveledRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20.0),
bottomRight: Radius.circular(20.0))),
child: Container(
height: 100,
width: 100,
decoration: const BoxDecoration(
color: Colors.grey,
),
),
),
Output:
Please I'm trying to draw a ring using custom paint in flutter, is there any idea on how to implement it?
As I tried to implement it like this but it's not accepted as I need the shadow to be more professional:
Stack(
alignment: Alignment.center,
children: [
Container(
height: 180,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
blurRadius: 2,
spreadRadius: 1,
offset: Offset(0, 2)),
],
),
),
Container(
height: 150,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
blurRadius: 2,
spreadRadius: 1,
offset: Offset(0, 2)),
],
),
),
],
),
Yes it could be done easily using Custom Paint.
class MyHome extends StatelessWidget{
#override
Widget build(BuildContext context){
return Scaffold(
body: Center(
child: Container(
height:200,
width:200,
child:CustomPaint(
painter:RingPainter(),
),
),
),
);
}
}
class RingPainter extends CustomPainter{
#override
void paint(Canvas canvas, Size size) {
double height=size.height;
double width=size.width;
//Paint to draw ring shape
Paint paint=Paint()..color=Colors.green..strokeWidth=16.0
..style=PaintingStyle.stroke..strokeCap=StrokeCap.round;
//defining Center of Box
Offset center=Offset(width/2,height/2);
//defining radius
double radius=min(width/2,height/2);
canvas.drawCircle(center,radius,paint);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}
How can I draw semicircle like this?
Code:
class DrawHalfCircleClipper extends CustomClipper<Path> {
#override
Path getClip(Size size) {
final Path path = new Path();
...
return path;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) {
return true;
}
Create a StatelessWidget say MyArc which accepts a diameter.
import 'dart:math' as math;
class MyArc extends StatelessWidget {
final double diameter;
const MyArc({super.key, this.diameter = 200});
#override
Widget build(BuildContext context) {
return CustomPaint(
painter: MyPainter(),
size: Size(diameter, diameter),
);
}
}
// This is the Painter class
class MyPainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()..color = Colors.blue;
canvas.drawArc(
Rect.fromCenter(
center: Offset(size.height / 2, size.width / 2),
height: size.height,
width: size.width,
),
math.pi,
math.pi,
false,
paint,
);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => false;
}
Usage:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: MyArc(diameter: 300),
);
}
Container(
decoration: const BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(100),
bottomRight: Radius.circular(100),
),
With this code you can make a half circle.
create a class that extends from CustomClipper and use the arcToPoint method to draw the circle and use the ClipPath widget, here is the code to implement that
ClipPath(
clipper: CustomClip(),
child: Container(
width: 200,
height: 100,
color: Colors.blue,
),
),
class CustomClip extends CustomClipper<Path> {
#override
Path getClip(Size size) {
double radius = 100;
Path path = Path();
path
..moveTo(size.width / 2, 0)
..arcToPoint(Offset(size.width, size.height),
radius: Radius.circular(radius))
..lineTo(0, size.height)
..arcToPoint(
Offset(size.width / 2, 0),
radius: Radius.circular(radius),
)
..close();
return path;
}
#override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) {
return true;
}
}
with a simple implementation( not the best)
you can draw 2 container both have same width and height inside a row
and provide a BoxDectoration for each container => BorderRadius
as the following code,
this is not the best implementation , it just works
Row(children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(topRight: Radius.circular(200),),
color: Colors.blue[300],
),
width: 200,
height: 200,
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(topLeft: Radius.circular(200),),
color: Colors.blue[300],
),
width: 200,
height: 200,
)
],
),
UPDATE: You only need a Container, EASY PEASY:
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(100),
topLeft: Radius.circular(100)),
color: Colors.red,
shape: BoxShape.rectangle,
),
height: 35,
width: 35,
),
Here is a simple code using Stack. You can easily generate a semicircle using a rectangle and a circle. Reshape the containers with BoxDecoration(shape:)
Stack(
children: [
Align(
alignment: Alignment.center,
child: Container(
height: 35,
width: 35,
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
),
),
Align(
alignment: Alignment.centerLeft,
child: Container(
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.rectangle,
),
height: 35,
width: 35,
),
),
],
),
This will work, you can change the dimensions, but make sure the height is half the borderRadius and the width is equal to the borderRadius.
Container(
height: 50,
width:100,
decoration: const BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(100),
bottomRight: Radius.circular(100),
))),
I wonder if there is a better solution for making a curved bar like the following image.
Here is my flutter code:
import 'package:flutter_web/material.dart';
class CurvedBar extends StatelessWidget {
const CurvedBar({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(height: 50,
color: Colors.orange,
child: Column(
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(20.0),
bottomRight: Radius.circular(20.0)),
child: Container(
height: 20.0,
width: double.infinity,
color: Colors.white,
),
),
Container(
color: Colors.white,
child: Row(
children: <Widget>[
Flexible(
flex: 1,
child: ClipRRect(
borderRadius:
BorderRadius.only(topRight: Radius.circular(20.0)),
child: Container(
height: 20.0,
color: Colors.orange,
),
)),
Flexible(
flex: 1,
child: ClipRRect(
borderRadius:
BorderRadius.only(topLeft: Radius.circular(20.0)),
child: Container(
height: 20.0,
color: Colors.orange,
),
))
],
))
],
));
}
}
make a custom ShapeBorder class like this one (the key method is _getPath that returns your shape's Path):
class CustomShapeBorder extends ShapeBorder {
const CustomShapeBorder();
#override
Path getInnerPath(Rect rect, {TextDirection textDirection}) => _getPath(rect);
#override
Path getOuterPath(Rect rect, {TextDirection textDirection}) => _getPath(rect);
_getPath(Rect rect) {
final r = rect.height / 2;
final radius = Radius.circular(r);
final offset = Rect.fromCircle(center: Offset.zero, radius: r);
return Path()
..moveTo(rect.topLeft.dx, rect.topLeft.dy)
..relativeArcToPoint(offset.bottomRight, clockwise: false, radius: radius)
..lineTo(rect.center.dx - r, rect.center.dy)
..relativeArcToPoint(offset.bottomRight, clockwise: true, radius: radius)
..relativeArcToPoint(offset.topRight, clockwise: true, radius: radius)
..lineTo(rect.centerRight.dx - r, rect.centerRight.dy)
..relativeArcToPoint(offset.topRight, clockwise: false, radius: radius)
..addRect(rect);
}
#override
EdgeInsetsGeometry get dimensions {
return EdgeInsets.all(0);
}
#override
ShapeBorder scale(double t) {
return CustomShapeBorder();
}
#override
void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) {
}
}
now you can use it like:
Container(
margin: EdgeInsets.only(top: 80),
height: 50,
width: double.infinity,
decoration: ShapeDecoration(
shape: CustomShapeBorder(),
//color: Colors.orange,
gradient:
LinearGradient(colors: [Colors.blue, Colors.orange]),
shadows: [
BoxShadow(
color: Colors.black, offset: Offset(3, -3), blurRadius: 3),
],
),
),
Result: