// ignore_for_file: sort_child_properties_last
import 'dart:typed_data';
import 'package:http/http.dart' as http;
import 'package:crop_your_image/crop_your_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
centerTitle: true,
elevation: 2,
title: Text(
"Crop Your Image",
style: TextStyle(fontSize: 22, color: Colors.black, fontWeight: FontWeight.w500),
),
backgroundColor: Colors.blue[200],
),
// appBar: AppBar(
// title: Text('Crop Your Image Demo'),
// ),
body: CropSample(),
),
);
}
}
class CropSample extends StatefulWidget {
@override
_CropSampleState createState() => _CropSampleState();
}
class _CropSampleState extends State<CropSample> {
static const _images = const [
'https://media.istockphoto.com/id/1464634920/photo/woman-sits-by-lake-in-glacier-national-park.jpg?s=2048x2048&w=is&k=20&c=oM5rATfC-TeSZAXN9TuL5iuT6wi3ubsZlgqd3XLdZsY=',
'https://images.freeimages.com/variants/DVg6TTGcRiJSdhEbY212DbAu/f4a36f6589a0e50e702740b15352bc00e4bfaf6f58bd4db850e167794d05993d?fmt=webp&h=350',
'https://media.istockphoto.com/id/666066516/photo/rock-band-performs-on-stage-guitarist-bass-guitar-and-drums.jpg?s=2048x2048&w=is&k=20&c=NqfTXWJrlbyL79ug5qmrRJCRop8A96XDK-tfqQ6MUU4=',
'https://images.freeimages.com/images/large-previews/aed/three-bees-on-sunflower-1337029.jpg?fmt=webp&w=500',
];
final _cropController = CropController();
final _imageDataList = <Uint8List>[];
var _loadingImage = false;
var _currentImage = 0;
set currentImage(int value) {
setState(() {
_currentImage = value;
});
_cropController.image = _imageDataList[_currentImage];
}
var _isSumbnail = false;
var _isCropping = false;
var _isCircleUi = false;
Uint8List? _croppedData;
var _statusText = '';
@override
void initState() {
_loadAllImages();
super.initState();
}
Future<void> _loadAllImages() async {
setState(() {
_loadingImage = true;
});
for (final assetName in _images) {
_imageDataList.add(await _load(assetName));
}
setState(() {
_loadingImage = false;
});
}
Future<Uint8List> _load(String imageUrl) async {
final response = await http.get(Uri.parse(imageUrl));
if (response.statusCode == 200) {
return response.bodyBytes;
} else {
throw Exception('Failed to load image: $imageUrl');
}
}
// Future<Uint8List> _load(String assetName) async {
// final assetData = await rootBundle.load(assetName);
// return assetData.buffer.asUint8List();
// }
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
height: double.infinity,
child: Center(
child: Visibility(
visible: !_loadingImage && !_isCropping,
child: Column(
children: [
if (_imageDataList.length >= 4)
Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
_buildSumbnail(_imageDataList[0]),
const SizedBox(width: 16),
_buildSumbnail(_imageDataList[1]),
const SizedBox(width: 16),
_buildSumbnail(_imageDataList[2]),
const SizedBox(width: 16),
_buildSumbnail(_imageDataList[3]),
],
),
),
Expanded(
child: Visibility(
visible: _croppedData == null,
child: Stack(
children: [
if (_imageDataList.isNotEmpty) ...[
Crop(
willUpdateScale: (newScale) => newScale < 5,
controller: _cropController,
image: _imageDataList[_currentImage],
onCropped: (croppedData) {
setState(() {
_croppedData = croppedData;
_isCropping = false;
});
},
withCircleUi: _isCircleUi,
onStatusChanged: (status) => setState(() {
_statusText = <CropStatus, String>{
CropStatus.nothing: 'Crop has no image data',
CropStatus.loading: 'Crop is now loading given image',
CropStatus.ready: 'Crop is now ready!',
CropStatus.cropping: 'Crop is now cropping image',
}[status] ??
'';
}),
initialSize: 0.5,
maskColor: _isSumbnail ? Colors.white : null,
cornerDotBuilder: (size, edgeAlignment) => const SizedBox.shrink(),
interactive: true,
fixCropRect: true,
radius: 20,
initialRectBuilder: (viewportRect, imageRect) {
return Rect.fromLTRB(
viewportRect.left + 24,
viewportRect.top + 24,
viewportRect.right - 24,
viewportRect.bottom - 24,
);
},
),
IgnorePointer(
child: Padding(
padding: const EdgeInsets.all(24),
child: Container(
decoration: BoxDecoration(
border: Border.all(width: 4, color: Colors.white),
borderRadius: BorderRadius.circular(20),
),
),
),
),
],
Positioned(
right: 16,
bottom: 16,
child: GestureDetector(
onTapDown: (_) => setState(() => _isSumbnail = true),
onTapUp: (_) => setState(() => _isSumbnail = false),
child: CircleAvatar(
backgroundColor: _isSumbnail ? Colors.blue.shade50 : Colors.blue,
child: Center(
child: Icon(Icons.crop_free_rounded),
),
),
),
),
],
),
replacement: Center(
child: _croppedData == null ? SizedBox.shrink() : Image.memory(_croppedData!),
),
),
),
if (_croppedData == null)
Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: Icon(Icons.crop_7_5),
onPressed: () {
_isCircleUi = false;
_cropController.aspectRatio = 16 / 4;
},
),
IconButton(
icon: Icon(Icons.crop_16_9),
onPressed: () {
_isCircleUi = false;
_cropController.aspectRatio = 16 / 9;
},
),
IconButton(
icon: Icon(Icons.crop_5_4),
onPressed: () {
_isCircleUi = false;
_cropController.aspectRatio = 4 / 3;
},
),
IconButton(
icon: Icon(Icons.crop_square),
onPressed: () {
_isCircleUi = false;
_cropController
..withCircleUi = false
..aspectRatio = 1;
},
),
IconButton(
icon: Icon(Icons.circle),
onPressed: () {
_isCircleUi = true;
_cropController.withCircleUi = true;
}),
],
),
const SizedBox(height: 16),
Container(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
setState(() {
_isCropping = true;
print("hello");
});
_isCircleUi ? _cropController.cropCircle() : _cropController.crop();
},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Text('CROP IT!'),
),
),
),
const SizedBox(height: 40),
],
),
),
const SizedBox(height: 16),
Text(_statusText),
const SizedBox(height: 16),
],
),
replacement: const CircularProgressIndicator(),
),
),
);
}
Expanded _buildSumbnail(Uint8List data) {
final index = _imageDataList.indexOf(data);
return Expanded(
child: InkWell(
onTap: () {
_croppedData = null;
currentImage = index;
},
child: Container(
height: 100,
decoration: BoxDecoration(
border: index == _currentImage
? Border.all(
width: 8,
color: Colors.blue,
)
: null,
),
child: Image.memory(
data,
fit: BoxFit.cover,
),
),
),
);
}
}