Skip to content

Commit 21c26ab

Browse files
Merge pull request #30 from sikandernoori/main
CustomCropShape - Ratio #24
2 parents fd8ac46 + ed7eb26 commit 21c26ab

File tree

4 files changed

+113
-2
lines changed

4 files changed

+113
-2
lines changed

example/lib/main.dart

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ class MyHomePage extends StatefulWidget {
4040

4141
class _MyHomePageState extends State<MyHomePage> {
4242
late CustomImageCropController controller;
43+
CustomCropShape _currentShape = CustomCropShape.Circle;
44+
final TextEditingController _widthController = TextEditingController();
45+
final TextEditingController _heightController = TextEditingController();
46+
47+
double _width = 16;
48+
double _height = 9;
4349

4450
@override
4551
void initState() {
@@ -53,6 +59,24 @@ class _MyHomePageState extends State<MyHomePage> {
5359
super.dispose();
5460
}
5561

62+
void _changeCropShape(CustomCropShape newShape) {
63+
setState(() {
64+
_currentShape = newShape;
65+
});
66+
}
67+
68+
void _updateRatio() {
69+
setState(() {
70+
if (_widthController.text.isNotEmpty) {
71+
_width = double.tryParse(_widthController.text) ?? 16;
72+
}
73+
if (_heightController.text.isNotEmpty) {
74+
_height = double.tryParse(_heightController.text) ?? 9;
75+
}
76+
});
77+
FocusScope.of(context).unfocus();
78+
}
79+
5680
@override
5781
Widget build(BuildContext context) {
5882
return Scaffold(
@@ -68,14 +92,18 @@ class _MyHomePageState extends State<MyHomePage> {
6892
// image: const AssetImage('assets/test.png'), // Any Imageprovider will work, try with a NetworkImage for example...
6993
image: const NetworkImage(
7094
'https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png'),
71-
shape: CustomCropShape.Square,
95+
shape: _currentShape,
96+
ratio: _currentShape == CustomCropShape.Ratio
97+
? Ratio(width: _width, height: _height)
98+
: null,
7299
canRotate: true,
73100
canMove: false,
74101
canScale: false,
75102
customProgressIndicator: const CupertinoActivityIndicator(),
76103
),
77104
),
78105
Row(
106+
mainAxisAlignment: MainAxisAlignment.spaceAround,
79107
children: [
80108
IconButton(
81109
icon: const Icon(Icons.refresh), onPressed: controller.reset),
@@ -106,11 +134,61 @@ class _MyHomePageState extends State<MyHomePage> {
106134
}
107135
},
108136
),
137+
PopupMenuButton<CustomCropShape>(
138+
icon: const Icon(Icons.crop_original),
139+
onSelected: _changeCropShape,
140+
itemBuilder: (BuildContext context) {
141+
return CustomCropShape.values.map((shape) {
142+
return PopupMenuItem<CustomCropShape>(
143+
value: shape,
144+
child: getShapeIcon(shape),
145+
);
146+
}).toList();
147+
},
148+
)
109149
],
110150
),
151+
if (_currentShape == CustomCropShape.Ratio)
152+
SizedBox(
153+
child: Row(
154+
children: [
155+
Expanded(
156+
child: TextField(
157+
controller: _widthController,
158+
keyboardType: TextInputType.number,
159+
decoration: const InputDecoration(labelText: 'Width'),
160+
),
161+
),
162+
const SizedBox(width: 16.0),
163+
Expanded(
164+
child: TextField(
165+
controller: _heightController,
166+
keyboardType: TextInputType.number,
167+
decoration: const InputDecoration(labelText: 'Height'),
168+
),
169+
),
170+
const SizedBox(width: 16.0),
171+
ElevatedButton(
172+
onPressed: _updateRatio,
173+
child: const Text('Update Ratio'),
174+
),
175+
],
176+
),
177+
),
111178
SizedBox(height: MediaQuery.of(context).padding.bottom),
112179
],
113180
),
114181
);
115182
}
183+
184+
Widget getShapeIcon(CustomCropShape shape) {
185+
switch (shape) {
186+
case CustomCropShape.Circle:
187+
return const Icon(Icons.circle_outlined);
188+
case CustomCropShape.Square:
189+
return const Icon(Icons.square_outlined);
190+
case CustomCropShape.Ratio:
191+
return const Icon(Icons.crop_16_9_outlined);
192+
}
193+
}
116194
}

lib/custom_image_crop.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ export 'package:custom_image_crop/src/widgets/custom_image_crop_widget.dart';
55
export 'package:custom_image_crop/src/painters/dotted_path_painter.dart';
66
export 'package:custom_image_crop/src/painters/solid_path_painter.dart';
77
export 'package:custom_image_crop/src/models/model.dart';
8+
export 'package:custom_image_crop/src/models/ratio.dart';

lib/src/models/ratio.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class Ratio {
2+
final double width;
3+
final double height;
4+
5+
Ratio({required this.width, required this.height});
6+
}

lib/src/widgets/custom_image_crop_widget.dart

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'dart:async';
22
import 'dart:ui' as ui;
33

4+
import 'package:custom_image_crop/src/models/ratio.dart';
45
import 'package:flutter/material.dart';
56
import 'package:gesture_x_detector/gesture_x_detector.dart';
67
import 'package:vector_math/vector_math_64.dart' as vector_math;
@@ -29,9 +30,19 @@ class CustomImageCrop extends StatefulWidget {
2930
/// The color in front of the cropped area
3031
final Color overlayColor;
3132

32-
/// The shape of the cropping area
33+
/// The shape of the cropping area.
34+
/// Possible values:
35+
/// - [CustomCropShape.Circle] Crop area will be circular.
36+
/// - [CustomCropShape.Square] Crop area will be a square.
37+
/// - [CustomCropShape.Ratio] Crop area will have a specified aspect ratio.
3338
final CustomCropShape shape;
3439

40+
/// Ratio of the cropping area.
41+
/// If [shape] is set to [CustomCropShape.Ratio], this property is required.
42+
/// For example, to create a square crop area, use [Ratio(width: 1, height: 1)].
43+
/// To create a rectangular crop area with a 16:9 aspect ratio, use [Ratio(width: 16, height: 9)].
44+
final Ratio? ratio;
45+
3546
/// How to fit image inside visible space
3647
final CustomImageFit imageFit;
3748

@@ -94,10 +105,15 @@ class CustomImageCrop extends StatefulWidget {
94105
this.canScale = true,
95106
this.canMove = true,
96107
this.customProgressIndicator,
108+
this.ratio,
97109
Paint? imagePaintDuringCrop,
98110
Key? key,
99111
}) : this.imagePaintDuringCrop = imagePaintDuringCrop ??
100112
(Paint()..filterQuality = FilterQuality.high),
113+
assert(
114+
!(shape == CustomCropShape.Ratio && ratio == null),
115+
"If shape is set to Ratio, ratio should not be null.",
116+
),
101117
super(key: key);
102118

103119
@override
@@ -260,6 +276,15 @@ class _CustomImageCropState extends State<CustomImageCrop>
260276
radius: cropWidth / 2,
261277
),
262278
);
279+
case CustomCropShape.Ratio:
280+
return Path()
281+
..addRect(
282+
Rect.fromCenter(
283+
center: Offset(width / 2, height / 2),
284+
width: cropWidth,
285+
height: cropWidth * widget.ratio!.height / widget.ratio!.width,
286+
),
287+
);
263288
default:
264289
return Path()
265290
..addRect(
@@ -352,6 +377,7 @@ class _CustomImageCropState extends State<CustomImageCrop>
352377
enum CustomCropShape {
353378
Circle,
354379
Square,
380+
Ratio,
355381
}
356382

357383
enum CustomImageFit {

0 commit comments

Comments
 (0)