Created
November 24, 2022 22:05
-
-
Save CristhianLara1996/2e174e6a58c6f46c5e84a937baa6b3e7 to your computer and use it in GitHub Desktop.
Convert Widget To Bytes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Future<void> _assignWidgetToMarker( | |
double size, | |
Model item, | |
double iconSizeMarker, | |
State state, | |
) async { | |
return WidgetToByte( | |
size: size, | |
markerWidget: ContainerWithShadow( | |
child: SvgPicture.asset( | |
'assets/icons/map/marker.svg', | |
height: size, | |
color: item.status == 'enabled' | |
? Colors.red | |
: Colors.blue, | |
), | |
widget: SvgPicture.asset( | |
item.status == 'enabled' | |
? iconPending | |
: iconCompleted, | |
height: iconSizeMarker, | |
width: iconSizeMarker, | |
), | |
height: size, | |
width: size, | |
text: '1', | |
), | |
callback: (Uint8List image) { | |
_markers.add( | |
Marker( | |
consumeTapEvents: true, | |
markerId: MarkerId(item.uuid), | |
position: LatLng(item.latitude, item.longitude), | |
onTap: () async { | |
await moveCamera(LatLng(item.latitude, item.longitude))! | |
.then((value) { | |
setState(() { | |
infoWindowShown = true; | |
}); | |
}); | |
}, | |
icon: BitmapDescriptor.fromBytes(image), | |
anchor: const Offset(0.5, 0.5), | |
), | |
); | |
setState(() {}); | |
}, | |
).generate(context); | |
} | |
/////////////////////// | |
class WidgetToByte { | |
final Function(Uint8List) callback; | |
final Widget markerWidget; | |
final double size; | |
WidgetToByte({ | |
required this.markerWidget, | |
required this.callback, | |
required this.size, | |
}); | |
void generate(BuildContext context) { | |
WidgetsBinding.instance | |
.addPostFrameCallback((_) => afterFirstLayout(context)); | |
} | |
void afterFirstLayout(BuildContext context) { | |
addOverlay(context); | |
} | |
void addOverlay(BuildContext context) { | |
OverlayState? overlayState = Overlay.of(context); | |
OverlayEntry entry = OverlayEntry( | |
builder: (context) { | |
return _MarkerHelper( | |
size: size, | |
markerWidgets: markerWidget, | |
callback: (Uint8List bitmapList) { | |
callback.call(bitmapList); | |
}, | |
); | |
}, | |
maintainState: true, | |
); | |
overlayState?.insert(entry); | |
} | |
} | |
/// Maps are embeding GoogleMap library for Andorid/iOS into flutter. | |
/// | |
/// These native libraries accept BitmapDescriptor for marker, which means that for custom markers | |
/// you need to draw view to bitmap and then send that to BitmapDescriptor. | |
/// | |
/// Because of that Flutter also cannot accept Widget for marker, but you need draw it to bitmap and | |
/// that's what this widget does: | |
/// | |
/// 1) It draws marker widget to tree | |
/// 2) After painted access the repaint boundary with global key and converts it to uInt8List | |
/// 3) Returns set of Uint8List (bitmaps) through callback | |
class _MarkerHelper extends StatefulWidget { | |
final Widget markerWidgets; | |
final Function(Uint8List) callback; | |
final double size; | |
const _MarkerHelper({ | |
required this.markerWidgets, | |
required this.callback, | |
required this.size, | |
Key? key, | |
}) : super(key: key); | |
@override | |
_MarkerHelperState createState() => _MarkerHelperState(); | |
} | |
class _MarkerHelperState extends State<_MarkerHelper> with AfterLayoutMixin { | |
GlobalKey globalKeys = GlobalKey(); | |
@override | |
void afterFirstLayout(BuildContext context) { | |
_getBitmaps(context, widget.size).then((list) { | |
widget.callback(list); | |
}); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Transform.translate( | |
offset: Offset(MediaQuery.of(context).size.width, 0), | |
child: Material( | |
type: MaterialType.transparency, | |
child: Stack( | |
children: <Widget>[ | |
SizedBox( | |
height: widget.size, | |
width: widget.size, | |
child: RepaintBoundary( | |
key: globalKeys, | |
child: widget.markerWidgets, | |
), | |
), | |
], | |
), | |
), | |
); | |
} | |
Future<Uint8List> _getBitmaps(BuildContext context, double size) async { | |
var futures = await _getUint8List(globalKeys, size); | |
return futures; | |
} | |
Future<Uint8List> _getUint8List(GlobalKey markerKey, double size) async { | |
return Future.delayed(const Duration(milliseconds: 20), () async { | |
RenderRepaintBoundary boundary = | |
markerKey.currentContext?.findRenderObject() as RenderRepaintBoundary; | |
boundary.layout( | |
BoxConstraints( | |
maxWidth: size, | |
maxHeight: size, | |
minWidth: size, | |
minHeight: size, | |
), | |
parentUsesSize: true, | |
); | |
var image = await boundary.toImage(pixelRatio: 0.55); | |
ByteData? byteData = | |
await image.toByteData(format: ui.ImageByteFormat.png); | |
return byteData!.buffer.asUint8List(); | |
}); | |
} | |
} | |
/// AfterLayoutMixin | |
mixin AfterLayoutMixin<T extends StatefulWidget> on State<T> { | |
@override | |
void initState() { | |
super.initState(); | |
WidgetsBinding.instance | |
.addPostFrameCallback((_) => afterFirstLayout(context)); | |
} | |
void afterFirstLayout(BuildContext context); | |
} | |
///////////////////////////// | |
class ContainerWithShadow extends StatelessWidget { | |
const ContainerWithShadow({ | |
required this.child, | |
Key? key, | |
this.height = 20, | |
this.width = 20, | |
this.text = '', | |
this.widget, | |
this.withShadow = false, | |
}) : super(key: key); | |
final double height; | |
final double width; | |
final String text; | |
final Widget? widget; | |
final Widget child; | |
final bool withShadow; | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
margin: const EdgeInsets.all(10), | |
child: Stack( | |
children: [ | |
Container( | |
decoration: BoxDecoration( | |
boxShadow: [ | |
if (withShadow) | |
const BoxShadow( | |
blurRadius: 2, | |
spreadRadius: -4, | |
color: TulColors.disabledColor, | |
offset: Offset(0, -1), | |
), | |
], | |
), | |
child: child, | |
), | |
Positioned( | |
top: height / 4, | |
right: -10, | |
child: Container( | |
alignment: Alignment.topCenter, | |
height: height, | |
width: width, | |
child: TulText.fontSizeCustom( | |
label: text, | |
fontWeight: FontWeight.bold, | |
fontSize: 45, | |
), | |
), | |
), | |
if (widget != null) | |
Positioned( | |
top: 0, | |
right: -5, | |
child: widget!, | |
), | |
], | |
), | |
); | |
} | |
} | |
class Triangle extends CustomPainter { | |
final Color? color; | |
Triangle({this.color}); | |
@override | |
void paint(Canvas canvas, Size size) { | |
var paint = Paint() | |
..color = color! | |
..strokeWidth = 10 | |
..style = PaintingStyle.fill; | |
var path = Path(); | |
path.moveTo(0.0, 0.0); | |
path.lineTo(size.width / 2, size.height); | |
path.lineTo(size.width, 0.0); | |
path.close(); | |
canvas.drawPath(path, paint); | |
} | |
@override | |
bool shouldRepaint(Triangle oldDelegate) => false; | |
@override | |
bool shouldRebuildSemantics(Triangle oldDelegate) => false; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment