Created
July 22, 2024 03:24
-
-
Save amirharati/2cf44d20faba6ba5edfaed4101b7c888 to your computer and use it in GitHub Desktop.
an example of adding opacity to pro_image_editor
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
import 'package:flutter/material.dart'; | |
import 'package:pro_image_editor/pro_image_editor.dart'; | |
void main() { | |
runApp(const MyApp()); | |
} | |
class MyApp extends StatelessWidget { | |
const MyApp({Key? key}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
title: 'Drawing App', | |
theme: ThemeData( | |
primarySwatch: Colors.blue, | |
), | |
home: const DrawingPage(), | |
); | |
} | |
} | |
class DrawingPage extends StatelessWidget { | |
const DrawingPage({Key? key}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: const Text('Drawing App'), | |
), | |
body: Center( | |
child: ElevatedButton( | |
child: const Text('Start Drawing'), | |
onPressed: () { | |
Navigator.push( | |
context, | |
MaterialPageRoute( | |
builder: (context) => PaintingEditor.network( | |
'https://picsum.photos/800/600', | |
initConfigs: PaintEditorInitConfigs( | |
theme: Theme.of(context), | |
enableFakeHero: false, | |
convertToUint8List: true, | |
configs: ProImageEditorConfigs( | |
imageEditorTheme: ImageEditorTheme( | |
background: Colors.white, | |
paintingEditor: PaintingEditorTheme( | |
initialColor: Colors.red.withOpacity(0.2), | |
), | |
), | |
paintEditorConfigs: const PaintEditorConfigs( | |
hasOptionFreeStyle: true, | |
hasOptionArrow: true, | |
hasOptionLine: true, | |
hasOptionRect: true, | |
hasOptionCircle: true, | |
hasOptionDashLine: true, | |
canChangeLineWidth: true, | |
editorIsZoomable: true, | |
enabled: false, | |
), | |
imageGenerationConfigs: ImageGeneratioConfigs( | |
outputFormat: OutputFormat.jpg, | |
customPixelRatio: 1.0, | |
maxOutputSize: const Size(2000, 2000), | |
), | |
customWidgets: ImageEditorCustomWidgets( | |
paintEditor: CustomWidgetsPaintEditor( | |
appBar: (editorState, rebuildStream) { | |
final customState = | |
CustomPaintingEditorState(editorState); | |
return ReactiveCustomAppbar( | |
stream: rebuildStream, | |
builder: (_) => _buildCustomAppBar(customState), | |
); | |
}, | |
colorPicker: (editorState, rebuildStream, | |
currentColor, setColor) { | |
// Return null to remove the default color picker | |
return null; | |
}, | |
), | |
), | |
), | |
), | |
), | |
), | |
); | |
}, | |
), | |
), | |
); | |
} | |
PreferredSizeWidget _buildCustomAppBar( | |
CustomPaintingEditorState editorState) { | |
return AppBar( | |
automaticallyImplyLeading: false, | |
backgroundColor: | |
editorState.imageEditorTheme.paintingEditor.appBarBackgroundColor, | |
foregroundColor: | |
editorState.imageEditorTheme.paintingEditor.appBarForegroundColor, | |
leading: IconButton( | |
icon: Icon(editorState.icons.backButton), | |
onPressed: editorState.close, | |
), | |
actions: [ | |
if (editorState.paintEditorConfigs.canChangeLineWidth) | |
IconButton( | |
icon: Icon(editorState.icons.paintingEditor.lineWeight), | |
onPressed: editorState.openLineWeightBottomSheet, | |
), | |
if (editorState.paintEditorConfigs.canToggleFill) | |
IconButton( | |
icon: Icon(editorState.fillBackground | |
? editorState.icons.paintingEditor.fill | |
: editorState.icons.paintingEditor.noFill), | |
onPressed: editorState.toggleFill, | |
), | |
IconButton( | |
icon: Icon(editorState.icons.undoAction), | |
onPressed: editorState.canUndo ? editorState.undoAction : null, | |
), | |
IconButton( | |
icon: Icon(editorState.icons.redoAction), | |
onPressed: editorState.canRedo ? editorState.redoAction : null, | |
), | |
IconButton( | |
icon: const Icon(Icons.color_lens), | |
onPressed: () => _showColorOpacityBottomSheet(editorState), | |
), | |
IconButton( | |
icon: Icon(editorState.icons.applyChanges), | |
onPressed: editorState.done, | |
), | |
], | |
); | |
} | |
void _showColorOpacityBottomSheet(CustomPaintingEditorState editorState) { | |
showModalBottomSheet( | |
context: editorState.context, | |
isScrollControlled: true, | |
builder: (BuildContext context) { | |
return DraggableScrollableSheet( | |
initialChildSize: 0.9, | |
minChildSize: 0.5, | |
maxChildSize: 0.9, | |
expand: false, | |
builder: (_, controller) { | |
return ColorOpacityPicker( | |
editorState: editorState, | |
//scrollController: controller, | |
); | |
}, | |
); | |
}, | |
); | |
} | |
} | |
class CustomPaintingEditorState { | |
final PaintingEditorState _originalState; | |
double _opacity = 0.2; | |
Color _color = Colors.red; | |
CustomPaintingEditorState(this._originalState) { | |
_color = _originalState.activeColor; | |
_opacity = _originalState.activeColor.opacity; | |
} | |
ProImageEditorConfigs get configs => _originalState.configs; | |
ImageEditorTheme get imageEditorTheme => _originalState.imageEditorTheme; | |
PaintEditorConfigs get paintEditorConfigs => | |
_originalState.paintEditorConfigs; | |
ImageEditorIcons get icons => _originalState.icons; | |
bool get fillBackground => _originalState.fillBackground; | |
bool get canUndo => _originalState.canUndo; | |
bool get canRedo => _originalState.canRedo; | |
Color get activeColor => _color.withOpacity(_opacity); | |
BuildContext get context => _originalState.context; | |
void close() => _originalState.close(); | |
void openLineWeightBottomSheet() => | |
_originalState.openLineWeightBottomSheet(); | |
void toggleFill() => _originalState.toggleFill(); | |
void undoAction() => _originalState.undoAction(); | |
void redoAction() => _originalState.redoAction(); | |
void done() => _originalState.done(); | |
void colorChanged(Color color) { | |
_color = color; | |
_originalState.colorChanged(_color.withOpacity(_opacity)); | |
} | |
void setOpacity(double value) { | |
_opacity = value; | |
_originalState.colorChanged(_color.withOpacity(_opacity)); | |
} | |
} | |
class ColorOpacityPicker extends StatefulWidget { | |
final CustomPaintingEditorState editorState; | |
const ColorOpacityPicker({Key? key, required this.editorState}) | |
: super(key: key); | |
@override | |
_ColorOpacityPickerState createState() => _ColorOpacityPickerState(); | |
} | |
class _ColorOpacityPickerState extends State<ColorOpacityPicker> { | |
late Color pickerColor; | |
late double opacity; | |
final List<Color> colorOptions = [ | |
Colors.red, | |
Colors.pink, | |
Colors.purple, | |
Colors.deepPurple, | |
Colors.indigo, | |
Colors.blue, | |
Colors.lightBlue, | |
Colors.cyan, | |
Colors.teal, | |
Colors.green, | |
Colors.lightGreen, | |
Colors.lime, | |
Colors.yellow, | |
Colors.amber, | |
Colors.orange, | |
Colors.deepOrange, | |
]; | |
@override | |
void initState() { | |
super.initState(); | |
pickerColor = widget.editorState.activeColor; | |
opacity = widget.editorState.activeColor.opacity; | |
} | |
void changeColor(Color color) { | |
setState(() => pickerColor = color); | |
widget.editorState.colorChanged(pickerColor.withOpacity(opacity)); | |
} | |
void changeOpacity(double value) { | |
setState(() => opacity = value); | |
widget.editorState.setOpacity(opacity); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
padding: const EdgeInsets.all(16), | |
child: Column( | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
const Text( | |
'Select Color', | |
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), | |
), | |
const SizedBox(height: 16), | |
GridView.builder( | |
shrinkWrap: true, | |
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( | |
crossAxisCount: 4, | |
crossAxisSpacing: 10, | |
mainAxisSpacing: 10, | |
), | |
itemCount: colorOptions.length, | |
itemBuilder: (context, index) { | |
return GestureDetector( | |
onTap: () => changeColor(colorOptions[index]), | |
child: Container( | |
decoration: BoxDecoration( | |
color: colorOptions[index], | |
shape: BoxShape.circle, | |
border: Border.all( | |
color: pickerColor == colorOptions[index] | |
? Colors.white | |
: Colors.transparent, | |
width: 3, | |
), | |
), | |
), | |
); | |
}, | |
), | |
const SizedBox(height: 20), | |
Row( | |
children: [ | |
const Icon(Icons.opacity, size: 24), | |
const SizedBox(width: 16), | |
Expanded( | |
child: Slider( | |
value: opacity, | |
min: 0.0, | |
max: 1.0, | |
divisions: 100, | |
onChanged: changeOpacity, | |
activeColor: pickerColor, | |
), | |
), | |
Text('${(opacity * 100).toInt()}%'), | |
], | |
), | |
const SizedBox(height: 16), | |
Container( | |
width: 50, | |
height: 50, | |
decoration: BoxDecoration( | |
color: pickerColor.withOpacity(opacity), | |
shape: BoxShape.circle, | |
border: Border.all(color: Colors.white, width: 2), | |
boxShadow: [ | |
BoxShadow( | |
color: Colors.black.withOpacity(0.2), | |
blurRadius: 4, | |
offset: const Offset(0, 2), | |
), | |
], | |
), | |
), | |
const SizedBox(height: 16), | |
Row( | |
mainAxisAlignment: MainAxisAlignment.spaceEvenly, | |
children: [ | |
TextButton( | |
onPressed: () => Navigator.of(context).pop(), | |
child: const Text('CANCEL'), | |
), | |
ElevatedButton( | |
onPressed: () => Navigator.of(context).pop(), | |
child: const Text('SUBMIT'), | |
), | |
], | |
), | |
], | |
), | |
); | |
} | |
} | |
// Update the _showColorOpacityBottomSheet method in DrawingPage class: | |
void _showColorOpacityBottomSheet(CustomPaintingEditorState editorState) { | |
showModalBottomSheet( | |
context: editorState.context, | |
isScrollControlled: true, | |
builder: (BuildContext context) { | |
return SingleChildScrollView( | |
child: ColorOpacityPicker(editorState: editorState), | |
); | |
}, | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment