v1.0.1+2flutter_drawing_board
एक फ्लटर ड्रॉइंग बोर्ड पैकेज, मूल ड्रॉइंग टूल, कैनवास संचालन और छवि डेटा प्राप्त करने की सुविधा प्रदान करता है।
एक नया ड्रॉइंग बोर्ड के लिए फ्लटर पैकेज
यह अंग्रेज़ी मूल स्नैपशॉट है। नवीनतम सामग्री GitHub पर देखें।
A powerful and highly customizable Flutter package for creating interactive drawing boards with advanced features.
Breaking Changes: After version
0.3.0, text functionality has been removed. For text features, please use
Version 0.9.9+ Behavior Changes:
SimpleLine()now uses Bezier curve smoothing by default (useBezierCurve: true), providing smoother lines. To use the old behavior, setuseBezierCurve: false.- JSON import maintains backward compatibility with
useBezierCurve: falseas default.
Try it online: Demo
import 'package:flutter_drawing_board/flutter_drawing_board.dart';
class MyDrawingPage extends StatefulWidget {
@override
State<MyDrawingPage> createState() => _MyDrawingPageState();
}
class _MyDrawingPageState extends State<MyDrawingPage> {
final DrawingController _drawingController = DrawingController();
@override
void dispose() {
_drawingController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
// Drawing Board
Expanded(
child: DrawingBoard(
controller: _drawingController,
background: Container(color: Colors.white),
),
),
// Action Bar (slider, undo, redo, rotate, clear)
DrawingBar(
controller: _drawingController,
tools: [
DefaultActionItem.slider(),
DefaultActionItem.undo(),
DefaultActionItem.redo(),
DefaultActionItem.turn(),
DefaultActionItem.clear(),
],
),
// Tool Bar (pen, brush, shapes, eraser)
DrawingBar(
controller: _drawingController,
tools: [
DefaultToolItem.pen(),
DefaultToolItem.brush(),
DefaultToolItem.rectangle(),
DefaultToolItem.circle(),
DefaultToolItem.straightLine(),
DefaultToolItem.eraser(),
],
),
],
),
);
}
}
The package provides several built-in drawing content types:
Draws smooth free-form lines with optional Bezier curve smoothing.
_drawingController.setPaintContent = SimpleLine(
useBezierCurve: true, // Enable Bezier smoothing (default: true since v0.9.9)
minPointDistance: 2.0, // Filter points closer than this distance (default: 2.0)
);
Note: Since v0.9.9,
useBezierCurvedefaults totruefor smoother lines. Set tofalsefor the old straight-line behavior.
Draws brush strokes with pressure-like width variation and advanced smoothing.
_drawingController.setPaintContent = SmoothLine(
brushPrecision: 0.8, // Line smoothness factor (smaller = smoother, default: 0.8)
useBezierCurve: true, // Enable Bezier curves (default: true)
minPointDistance: 2.0, // Filter redundant points (default: 2.0)
smoothLevel: 1, // 0: fast, 1: balanced, 2: ultra-smooth (default: 1)
);
Smooth Levels:
0: Fast - No additional smoothing1: Balanced - Basic smoothing (recommended)2: Ultra-smooth - Catmull-Rom spline interpolation for silky smooth curves_drawingController.setPaintContent = StraightLine();
_drawingController.setPaintContent = Rectangle();
_drawingController.setPaintContent = Circle(
isEllipse: false, // false: circle, true: ellipse (default: false)
startFromCenter: true, // true: start from center, false: diagonal (default: true)
);
_drawingController.setPaintContent = Eraser();
final DrawingController _drawingController = DrawingController(
config: DrawConfig(
contentType: SimpleLine,
strokeWidth: 4.0,
color: Colors.black,
),
maxHistorySteps: 100, // Limit undo/redo history (default: 100)
);
_drawingController.setStyle(
color: Colors.blue,
strokeWidth: 6.0,
strokeCap: StrokeCap.round,
strokeJoin: StrokeJoin.round,
blendMode: BlendMode.srcOver,
isAntiAlias: true,
);
// Undo last action
_drawingController.undo();
// Redo last undone action
_drawingController.redo();
// Rotate canvas 90° clockwise
_drawingController.turn();
// Clear entire canvas
_drawingController.clear();
// Check operation availability
bool canUndo = _drawingController.canUndo();
bool canRedo = _drawingController.canRedo();
bool canClear = _drawingController.canClear();
// Add single content
_drawingController.addContent(StraightLine.fromJson(jsonData));
// Add multiple contents
_drawingController.addContents([
SimpleLine.fromJson(line1Json),
Rectangle.fromJson(rect1Json),
]);
Export as Image:
// Get complete image (with background)
Future<void> _exportImage() async {
final ByteData? data = await _drawingController.getImageData(
format: ui.ImageByteFormat.png,
);
if (data != null) {
final Uint8List bytes = data.buffer.asUint8List();
// Save or display the image
}
}
// Get surface image (drawing only, faster)
Future<void> _exportSurface() async {
final ByteData? data = await _drawingController.getSurfaceImageData();
// Use the image data
}
Export as JSON:
void _exportJson() {
final List<Map<String, dynamic>> jsonList = _drawingController.getJsonList();
final String jsonString = const JsonEncoder.withIndent(' ').convert(jsonList);
// Save or share the JSON
}
Import from JSON:
void _importJson(List<Map<String, dynamic>> jsonData) {
final contents = jsonData.map((json) {
final type = json['type'] as String;
switch (type) {
case 'SimpleLine':
return SimpleLine.fromJson(json);
case 'StraightLine':
return StraightLine.fromJson(json);
case 'Rectangle':
return Rectangle.fromJson(json);
case 'Circle':
return Circle.fromJson(json);
case 'Eraser':
return Eraser.fromJson(json);
default:
return null;
}
}).whereType<PaintContent>().toList();
_drawingController.addContents(contents);
}
DrawingBoard(
controller: _drawingController,
background: Container(color: Colors.white),
// Interaction callbacks
onPointerDown: (PointerDownEvent event) { /* ... */ },
onPointerMove: (PointerMoveEvent event) { /* ... */ },
onPointerUp: (PointerUpEvent event) { /* ... */ },
// Canvas interaction
boardPanEnabled: true, // Enable panning (default: true)
boardScaleEnabled: true, // Enable zooming (default: true)
minScale: 0.2, // Minimum zoom scale (default: 0.2)
maxScale: 20, // Maximum zoom scale (default: 20)
panAxis: PanAxis.free, // Pan direction constraint (default: free)
// Advanced features
enablePalmRejection: false, // Enable palm rejection for tablets (default: false)
// Layout
alignment: Alignment.topCenter,
clipBehavior: Clip.antiAlias,
boardClipBehavior: Clip.hardEdge,
// Transformation controller for external manipulation
transformationController: _transformationController,
)
The DrawingBar widget provides a flexible toolbar layout with automatic controller passing.
// Horizontal toolbar (default)
DrawingBar(
controller: _drawingController,
style: HorizontalToolsBarStyle(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 8.0,
),
tools: [ /* tool widgets */ ],
)
// Vertical toolbar
DrawingBar(
controller: _drawingController,
style: VerticalToolsBarStyle(
mainAxisAlignment: MainAxisAlignment.start,
spacing: 8.0,
),
tools: [ /* tool widgets */ ],
)
// Wrap toolbar (auto-wrapping)
DrawingBar(
controller: _drawingController,
style: WrapToolsBarStyle(
spacing: 8.0,
runSpacing: 8.0,
),
tools: [ /* tool widgets */ ],
)
Pre-built tool buttons for switching drawing content:
DefaultToolItem.pen() // SimpleLine tool
DefaultToolItem.brush() // SmoothLine tool
DefaultToolItem.straightLine() // StraightLine tool
DefaultToolItem.rectangle() // Rectangle tool
DefaultToolItem.circle() // Circle tool
DefaultToolItem.eraser() // Eraser tool
Custom tool item:
DefaultToolItem(
icon: Icons.star,
content: MyCustomContent,
onTap: (controller) {
// Custom action
},
color: Colors.grey,
activeColor: Colors.blue,
iconSize: 24,
)
Pre-built action buttons:
DefaultActionItem.slider() // Stroke width slider
DefaultActionItem.undo() // Undo button
DefaultActionItem.redo() // Redo button
DefaultActionItem.turn() // Rotate 90° button
DefaultActionItem.clear() // Clear canvas button
Custom action item:
DefaultActionItem(
childBuilder: (context, controller) {
return Icon(Icons.save);
},
onTap: (controller) async {
// Save drawing
await _saveDrawing(controller);
},
)
Prevents accidental palm touches on tablets by detecting large touch areas and rapid successive touches.
DrawingBoard(
controller: _drawingController,
background: Container(color: Colors.white),
enablePalmRejection: true, // Enable palm rejection
)
How it works:
Control memory usage by limiting undo/redo history:
final DrawingController _drawingController = DrawingController(
maxHistorySteps: 50, // Limit to 50 steps (default: 100)
);
// Set color with custom opacity
_drawingController.setStyle(
color: Colors.red.withValues(alpha: 0.5),
);
Extend PaintContent to create your own drawing tools:
class Triangle extends PaintContent {
Triangle();
Triangle.data({
required this.startPoint,
required this.A,
required this.B,
required this.C,
required Paint paint,
}) : super.paint(paint);
factory Triangle.fromJson(Map<String, dynamic> data) {
return Triangle.data(
startPoint: jsonToOffset(data['startPoint'] as Map<String, dynamic>),
A: jsonToOffset(data['A'] as Map<String, dynamic>),
B: jsonToOffset(data['B'] as Map<String, dynamic>),
C: jsonToOffset(data['C'] as Map<String, dynamic>),
paint: jsonToPaint(data['paint'] as Map<String, dynamic>),
);
}
Offset startPoint = Offset.zero;
Offset A = Offset.zero;
Offset B = Offset.zero;
Offset C = Offset.zero;
@override
void startDraw(Offset startPoint) => this.startPoint = startPoint;
@override
void drawing(Offset nowPoint) {
A = Offset(
startPoint.dx + (nowPoint.dx - startPoint.dx) / 2,
startPoint.dy,
);
B = Offset(startPoint.dx, nowPoint.dy);
C = nowPoint;
}
@override
void draw(Canvas canvas, Size size, bool deeper) {
final Path path = Path()
..moveTo(A.dx, A.dy)
..lineTo(B.dx, B.dy)
..lineTo(C.dx, C.dy)
..close();
canvas.drawPath(path, paint);
}
@override
Triangle copy() => Triangle();
@override
Map<String, dynamic> toContentJson() {
return <String, dynamic>{
'startPoint': startPoint.toJson(),
'A': A.toJson(),
'B': B.toJson(),
'C': C.toJson(),
'paint': paint.toJson(),
};
}
}
Add to toolbar:
DrawingBar(
controller: _drawingController,
tools: [
...DefaultToolItem.values, // All default tools
DefaultToolItem(
icon: Icons.change_history,
content: Triangle,
activeColor: Colors.purple,
),
],
)
Preview:
The package includes several performance optimizations (introduced in v0.9.9+):
minPointDistance, reducing data by 30-50%[
{
"type": "StraightLine",
"startPoint": {"dx": 114.56, "dy": 117.50},
"endPoint": {"dx": 252.93, "dy": 254.91},
"paint": {
"blendMode": 3,
"color": 4294198070,
"filterQuality": 3,
"invertColors": false,
"isAntiAlias": false,
"strokeCap": 1,
"strokeJoin": 1,
"strokeWidth": 4.0,
"style": 1
}
},
{
"type": "SimpleLine",
"points": [
{"dx": 100.0, "dy": 100.0},
{"dx": 150.0, "dy": 120.0},
{"dx": 200.0, "dy": 110.0}
],
"useBezierCurve": true,
"minPointDistance": 2.0,
"paint": { /* ... */ }
}
]
| Method | Description |
|---|---|
setStyle({...}) |
Update paint style (color, width, etc.) |
setPaintContent(PaintContent) |
Switch drawing tool |
undo() |
Undo last action |
redo() |
Redo last undone action |
turn() |
Rotate canvas 90° |
clear() |
Clear canvas |
addContent(PaintContent) |
Add single content |
addContents(List<PaintContent>) |
Add multiple contents |
getImageData() |
Export as image (with background) |
getSurfaceImageData() |
Export surface image (faster) |
getJsonList() |
Export as JSON |
| Type | Description | Parameters |
|---|---|---|
SimpleLine |
Free-form line | useBezierCurve, minPointDistance |
SmoothLine |
Brush stroke | brushPrecision, smoothLevel, useBezierCurve, minPointDistance |
StraightLine |
Straight line | - |
Rectangle |
Rectangle | - |
Circle |
Circle/Ellipse | isEllipse, startFromCenter |
Eraser |
Eraser | - |
Check out the example folder for complete examples including:
Contributions are welcome! Here's how you can help:
Please ensure your code follows the existing style and includes tests where applicable.
This project is licensed under the MIT License - see the LICENSE file for details.
See CHANGELOG.md for version history.
निर्भरता सूची 2 आइटम
{"sdk":"flutter"}{"sdk":"flutter"}उपयोग के अनुसार छाँटें, गतिविधि की तुलना करें और अपनाने से पहले मूल प्रोजेक्ट की आवश्यकताएँ जाँचें।
“A repository is the most basic element of GitHub.”
GitHub Docs — About repositories ↗