Comments (4)
@anasmuhamad98 Did you resolve it? Why don't you do pull-request?
from bubble.
https://github.com/vi-k/bubble/issues/14
Thanks, shinriyo.
from bubble.
import 'dart:ui';
import 'dart:math';
import 'package:flutter/material.dart';
enum BubbleNip { no, leftTop, leftBottom, rightTop, rightBottom, left }
/// Class BubbleEdges is an analog of EdgeInsets, but default values are null.
class BubbleEdges {
const BubbleEdges.fromLTRB(this.left, this.top, this.right, this.bottom);
const BubbleEdges.all(double value)
: left = value,
top = value,
right = value,
bottom = value;
const BubbleEdges.only({
this.left, // = null
this.top, // = null
this.right, // = null
this.bottom, // = null
});
const BubbleEdges.symmetric({
double vertical, // = null
double horizontal, // = null
}) : left = horizontal,
top = vertical,
right = horizontal,
bottom = vertical;
final double left;
final double top;
final double right;
final double bottom;
static get zero => BubbleEdges.all(0);
EdgeInsets get edgeInsets => EdgeInsets.fromLTRB(left ?? 0, top ?? 0, right ?? 0, bottom ?? 0);
@OverRide
String toString() => 'BubbleEdges($left, $top, $right, $bottom)';
}
class BubbleStyle {
const BubbleStyle({
this.radius,
this.nip,
this.nipWidth,
this.nipHeight,
this.nipOffset,
this.nipRadius,
this.stick,
this.color,
this.elevation,
this.shadowColor,
this.padding,
this.margin,
this.alignment,
});
final Radius radius;
final BubbleNip nip;
final double nipHeight;
final double nipWidth;
final double nipOffset;
final double nipRadius;
final bool stick;
final Color color;
final double elevation;
final Color shadowColor;
final BubbleEdges padding;
final BubbleEdges margin;
final Alignment alignment;
}
class BubbleClipper extends CustomClipper {
BubbleClipper({
this.radius,
this.nip,
this.nipWidth,
this.nipHeight,
this.nipOffset,
this.nipRadius,
this.stick,
this.padding,
}) : assert(nipWidth > 0.0),
assert(nipHeight > 0.0),
assert(nipRadius >= 0.0),
assert(nipRadius <= nipWidth / 2.0 && nipRadius <= nipHeight / 2.0),
assert(nipOffset >= 0.0),
// assert(radius <= nipHeight + nipOffset),
assert(padding != null),
assert(padding.left != null),
assert(padding.top != null),
assert(padding.right != null),
assert(padding.bottom != null),
super() {
_startOffset = _endOffset = nipWidth;
var k = nipHeight / nipWidth;
var a = atan(k);
_nipCX = (nipRadius + sqrt(nipRadius * nipRadius * (1 + k * k))) / k;
var nipStickOffset = (_nipCX - nipRadius).floorToDouble();
_nipCX -= nipStickOffset;
_nipCY = nipRadius;
_nipPX = _nipCX - nipRadius * sin(a);
_nipPY = _nipCY + nipRadius * cos(a);
_startOffset -= nipStickOffset;
_endOffset -= nipStickOffset;
if (stick) _endOffset = 0.0;
}
final Radius radius;
final BubbleNip nip;
final double nipHeight;
final double nipWidth;
final double nipOffset;
final double nipRadius;
final bool stick;
final BubbleEdges padding;
double _startOffset; // Offsets of the bubble
double _endOffset;
double _nipCX; // The center of the circle
double _nipCY;
double _nipPX; // The point of contact of the nip with the circle
double _nipPY;
get edgeInsets {
return nip == BubbleNip.leftTop || nip == BubbleNip.leftBottom || nip == BubbleNip.left
? EdgeInsets.only(
left: _startOffset + padding.left,
top: padding.top,
right: _endOffset + padding.right,
bottom: padding.bottom)
: nip == BubbleNip.rightTop || nip == BubbleNip.rightBottom
? EdgeInsets.only(
left: _endOffset + padding.left,
top: padding.top,
right: _startOffset + padding.right,
bottom: padding.bottom)
: EdgeInsets.only(
left: _endOffset + padding.left,
top: padding.top,
right: _endOffset + padding.right,
bottom: padding.bottom);
}
@OverRide
Path getClip(Size size) {
var radiusX = radius.x;
var radiusY = radius.y;
var maxRadiusX = size.width / 2;
var maxRadiusY = size.height / 2;
if (radiusX > maxRadiusX) {
radiusY *= maxRadiusX / radiusX;
radiusX = maxRadiusX;
}
if (radiusY > maxRadiusY) {
radiusX *= maxRadiusY / radiusY;
radiusY = maxRadiusY;
}
var path = Path();
switch (nip) {
case BubbleNip.left:
path.addRRect(RRect.fromLTRBR(_startOffset, 0,
size.width - _endOffset, size.height, radius));
path.moveTo(_startOffset + radiusX, nipOffset);
path.lineTo(_startOffset + radiusX, nipOffset + nipHeight);
path.lineTo(_startOffset, nipOffset + nipHeight);
path.lineTo(0, nipOffset + (nipHeight / 2) );
path.lineTo(_startOffset, nipOffset);
path.close();
break;
path.close();
break;
case BubbleNip.leftTop:
path.addRRect(RRect.fromLTRBR(_startOffset, 0,
size.width - _endOffset, size.height, radius));
path.moveTo(_startOffset + radiusX, nipOffset);
path.lineTo(_startOffset + radiusX, nipOffset + nipHeight);
path.lineTo(_startOffset, nipOffset + nipHeight);
if (nipRadius == 0) {
path.lineTo(0, nipOffset);
} else {
path.lineTo(_nipPX, nipOffset + _nipPY);
path.arcToPoint(Offset(_nipCX, nipOffset), radius: Radius.circular(nipRadius));
}
path.close();
break;
case BubbleNip.leftBottom:
path.addRRect(RRect.fromLTRBR(_startOffset, 0, size.width - _endOffset, size.height, radius));
Path path2 = Path();
path2.moveTo(_startOffset + radiusX, size.height - nipOffset);
path2.lineTo(_startOffset + radiusX, size.height - nipOffset - nipHeight);
path2.lineTo(_startOffset, size.height - nipOffset - nipHeight);
if (nipRadius == 0) {
path2.lineTo(0, size.height - nipOffset);
} else {
path2.lineTo(_nipPX, size.height - nipOffset - _nipPY);
path2.arcToPoint(Offset(_nipCX, size.height - nipOffset),
radius: Radius.circular(nipRadius), clockwise: false);
}
path2.close();
path.addPath(path2, Offset(0, 0));
path.addPath(path2, Offset(0, 0)); // Magic!
break;
case BubbleNip.rightTop:
path.addRRect(RRect.fromLTRBR(_endOffset, 0, size.width - _startOffset, size.height, radius));
Path path2 = Path();
path2.moveTo(size.width - _startOffset - radiusX, nipOffset);
path2.lineTo(size.width - _startOffset - radiusX, nipOffset + nipHeight);
path2.lineTo(size.width - _startOffset, nipOffset + nipHeight);
if (nipRadius == 0) {
path2.lineTo(size.width, nipOffset);
} else {
path2.lineTo(size.width - _nipPX, nipOffset + _nipPY);
path2.arcToPoint(Offset(size.width - _nipCX, nipOffset),
radius: Radius.circular(nipRadius), clockwise: false);
}
path2.close();
path.addPath(path2, Offset(0, 0));
path.addPath(path2, Offset(0, 0)); // Magic!
break;
case BubbleNip.rightBottom:
path.addRRect(RRect.fromLTRBR(_endOffset, 0, size.width - _startOffset, size.height, radius));
path.moveTo(size.width - _startOffset - radiusX, size.height - nipOffset);
path.lineTo(size.width - _startOffset - radiusX, size.height - nipOffset - nipHeight);
path.lineTo(size.width - _startOffset, size.height - nipOffset - nipHeight);
if (nipRadius == 0) {
path.lineTo(size.width, size.height - nipOffset);
} else {
path.lineTo(size.width - _nipPX, size.height - nipOffset - _nipPY);
path.arcToPoint(Offset(size.width - _nipCX, size.height - nipOffset),
radius: Radius.circular(nipRadius));
}
path.close();
break;
case BubbleNip.no:
path.addRRect(RRect.fromLTRBR(_endOffset, 0, size.width - _endOffset, size.height, radius));
break;
}
return path;
}
@OverRide
bool shouldReclip(BubbleClipper oldClipper) => false;
}
class Bubble extends StatelessWidget {
Bubble({
this.child,
Radius radius,
BubbleNip nip,
double nipWidth,
double nipHeight,
double nipOffset,
double nipRadius,
bool stick,
Color color,
double elevation,
Color shadowColor,
BubbleEdges padding,
BubbleEdges margin,
Alignment alignment,
BubbleStyle style,
}) : color = color ?? style?.color ?? Colors.white,
elevation = elevation ?? style?.elevation ?? 1.0,
shadowColor = shadowColor ?? style?.shadowColor ?? Colors.black,
margin = BubbleEdges.only(
left: margin?.left ?? style?.margin?.left ?? 0.0,
top: margin?.top ?? style?.margin?.top ?? 0.0,
right: margin?.right ?? style?.margin?.right ?? 0.0,
bottom: margin?.bottom ?? style?.margin?.bottom ?? 0.0,
),
alignment = alignment ?? style?.alignment ?? null,
bubbleClipper = BubbleClipper(
radius: radius ?? style?.radius ?? Radius.circular(6.0),
nip: nip ?? style?.nip ?? BubbleNip.no,
nipWidth: nipWidth ?? style?.nipWidth ?? 8.0,
nipHeight: nipHeight ?? style?.nipHeight ?? 10.0,
nipOffset: nipOffset ?? style?.nipOffset ?? 0.0,
nipRadius: nipRadius ?? style?.nipRadius ?? 1.0,
stick: stick ?? style?.stick ?? false,
padding: BubbleEdges.only(
left: padding?.left ?? style?.padding?.left ?? 8.0,
top: padding?.top ?? style?.padding?.top ?? 6.0,
right: padding?.right ?? style?.padding?.right ?? 8.0,
bottom: padding?.bottom ?? style?.padding?.bottom ?? 6.0,
),
);
final Widget child;
final Color color;
final double elevation;
final Color shadowColor;
final BubbleEdges margin;
final Alignment alignment;
final BubbleClipper bubbleClipper;
Widget build(context) {
return Container(
alignment: alignment,
margin: margin?.edgeInsets,
child: PhysicalShape(
clipBehavior: Clip.antiAlias,
clipper: bubbleClipper,
child: Container(padding: bubbleClipper.edgeInsets, child: child),
color: color,
elevation: elevation,
shadowColor: shadowColor,
));
}
}
from bubble.
@vi-k you're welcome.
There are few plugins in the Flutter world.
Almost all people rely on the plugin.
from bubble.
Related Issues (20)
- Add one more text field for date inside bubble HOT 2
- flutter web crash HOT 1
- Move Nip Horizontally HOT 1
- Add custom key HOT 2
- Change to AlignmentGeometry instead of Alignment HOT 1
- The Bubble widget gave me bad performance HOT 4
- Add null safety HOT 2
- [Question] Speech to text support HOT 1
- Feature request: Date and/or Time HOT 2
- UnimplementedError on web when running example HOT 1
- Feature Request: BubbleNip.BelowLeft, BubbleNip.BelowRight, BubbleNip.AboveLeft, BubbleNip.AboveRight
- Clip behavior not work because of BubblePainter in v1.2.1
- bottom center bubble HOT 1
- Dynamic list of bubbles
- Alignment Nip HOT 1
- OverFlowed Bright problem HOT 1
- UnimplementedError on web with --web-renderer html HOT 1
- Dynamic width when text is more than 1 line. HOT 1
- Add reaction support
- Flutter Web - Mobile Browser Bubble viewing problem HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from bubble.