Flutter网页图片裁剪插件image_cropper_for_web的使用
Flutter网页图片裁剪插件 image_cropper_for_web
的使用
image_cropper_for_web
是一个用于在Flutter Web应用中实现图片裁剪功能的插件。本文将介绍如何使用该插件,并提供一个完整的示例代码。
安装插件
首先,您需要在项目的 pubspec.yaml
文件中添加依赖:
dependencies:
flutter:
sdk: flutter
image_cropper: ^1.4.1
image_picker: ^0.8.5+3
dotted_border: ^2.0.0
然后运行 flutter pub get
来安装这些依赖。
示例代码
以下是一个完整的示例代码,展示了如何在Flutter Web应用中使用 image_cropper_for_web
插件进行图片上传和裁剪操作。
import 'package:dotted_border/dotted_border.dart';
import 'package:flutter/material.dart';
import 'package:image_cropper/image_cropper.dart';
import 'package:image_picker/image_picker.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
highlightColor: const Color(0xFFD0996F),
canvasColor: const Color(0xFFFDF5EC),
textTheme: TextTheme(
headlineSmall: ThemeData.light()
.textTheme
.headlineSmall!
.copyWith(color: const Color(0xFFBC764A)),
),
iconTheme: IconThemeData(
color: Colors.grey[600],
),
appBarTheme: const AppBarTheme(
backgroundColor: Color(0xFFBC764A),
centerTitle: false,
foregroundColor: Colors.white,
actionsIconTheme: IconThemeData(color: Colors.white),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ButtonStyle(
backgroundColor: WidgetStateColor.resolveWith(
(states) => const Color(0xFFBC764A)),
foregroundColor: WidgetStateColor.resolveWith(
(states) => Colors.white,
),
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: ButtonStyle(
foregroundColor: WidgetStateColor.resolveWith(
(states) => const Color(0xFFBC764A),
),
side: WidgetStateBorderSide.resolveWith(
(states) => const BorderSide(color: Color(0xFFBC764A))),
),
),
textButtonTheme: TextButtonThemeData(
style: ButtonStyle(
foregroundColor: WidgetStateColor.resolveWith(
(states) => const Color(0xFFBC764A),
),
),
),
iconButtonTheme: IconButtonThemeData(
style: ButtonStyle(
foregroundColor: WidgetStateColor.resolveWith(
(states) => const Color(0xFFBC764A),
),
),
),
colorScheme: ColorScheme.fromSwatch().copyWith(
background: const Color(0xFFFDF5EC),
primary: const Color(0xFFD0996F),
),
),
home: const MyHomePage(title: 'Image Cropper Demo'),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({
super.key,
required this.title,
});
final String title;
[@override](/user/override)
Widget build(BuildContext context) {
final screenWidth = MediaQuery.of(context).size.width;
if (screenWidth > 700) {
return _HomePage(
key: const ValueKey('desktop'),
title: title,
displayStyle: PageDisplayStyle.desktop,
);
} else {
return _HomePage(
key: const ValueKey('mobile'),
title: title,
displayStyle: PageDisplayStyle.mobile,
);
}
}
}
enum PageDisplayStyle {
desktop,
mobile,
}
class _HomePage extends StatefulWidget {
final PageDisplayStyle displayStyle;
final String title;
const _HomePage({
super.key,
required this.displayStyle,
required this.title,
});
[@override](/user/override)
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<_HomePage> {
String? _uploadedBlobUrl;
String? _croppedBlobUrl;
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: widget.displayStyle == PageDisplayStyle.mobile
? AppBar(title: Text(widget.title))
: null,
body: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (widget.displayStyle == PageDisplayStyle.desktop)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 24.0),
child: Text(
widget.title,
style: Theme.of(context)
.textTheme
.displayMedium!
.copyWith(color: Theme.of(context).highlightColor),
),
),
Expanded(child: _body()),
],
),
);
}
Widget _body() {
if (_croppedBlobUrl != null || _uploadedBlobUrl != null) {
return _imageCard();
} else {
return _uploaderCard();
}
}
Widget _imageCard() {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Card(
elevation: 4.0,
child: Padding(
padding: const EdgeInsets.all(24.0),
child: _image(),
),
),
const SizedBox(height: 24.0),
_menu(),
],
),
);
}
Widget _image() {
final screenWidth = MediaQuery.of(context).size.width;
final screenHeight = MediaQuery.of(context).size.height;
if (_croppedBlobUrl != null) {
return ConstrainedBox(
constraints: BoxConstraints(
maxWidth: 0.8 * screenWidth,
maxHeight: 0.7 * screenHeight,
),
child: Image.network(_croppedBlobUrl!));
} else if (_uploadedBlobUrl != null) {
return ConstrainedBox(
constraints: BoxConstraints(
maxWidth: 0.8 * screenWidth,
maxHeight: 0.7 * screenHeight,
),
child: Image.network(_uploadedBlobUrl!),
);
} else {
return const SizedBox.shrink();
}
}
Widget _menu() {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
FloatingActionButton(
onPressed: () {
_clear();
},
backgroundColor: Colors.redAccent,
tooltip: 'Delete',
heroTag: null,
child: const Icon(Icons.delete),
),
if (_croppedBlobUrl == null)
Padding(
padding: const EdgeInsets.only(left: 32.0),
child: FloatingActionButton(
onPressed: () {
_cropImage();
},
backgroundColor: const Color(0xFFBC764A),
tooltip: 'Crop',
heroTag: null,
child: const Icon(Icons.crop),
),
)
],
);
}
Widget _uploaderCard() {
return Center(
child: Card(
elevation: 4.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16.0),
),
child: SizedBox(
width: 380.0,
height: 300.0,
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
DottedBorder(
radius: const Radius.circular(12.0),
borderType: BorderType.RRect,
dashPattern: const [8, 4],
color: Theme.of(context).highlightColor.withOpacity(0.4),
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(
Icons.image,
color: Theme.of(context).highlightColor,
size: 80.0,
),
const SizedBox(height: 24.0),
Text(
'Upload an image to start',
style:
Theme.of(context).textTheme.headlineSmall!.copyWith(
color: Theme.of(context).highlightColor,
),
)
],
),
),
),
const SizedBox(height: 24.0),
ElevatedButton(
onPressed: () {
_uploadImage();
},
style: ElevatedButton.styleFrom(foregroundColor: Colors.white),
child: const Text('Upload'),
),
],
),
),
),
);
}
Future<void> _cropImage() async {
if (_uploadedBlobUrl != null) {
WebUiSettings settings;
if (widget.displayStyle == PageDisplayStyle.mobile) {
final screenWidth = MediaQuery.of(context).size.width;
final screenHeight = MediaQuery.of(context).size.height;
settings = WebUiSettings(
context: context,
presentStyle: WebPresentStyle.page,
size: CropperSize(
width: (screenWidth * 0.9).round(),
height: (screenHeight * 0.8).round(),
),
themeData: const WebThemeData(backIcon: Icons.arrow_back_ios_new),
);
} else {
settings = WebUiSettings(
context: context,
presentStyle: WebPresentStyle.dialog,
size: const CropperSize(
width: 520,
height: 520,
),
);
}
final croppedFile = await ImageCropper().cropImage(
sourcePath: _uploadedBlobUrl!,
uiSettings: [settings],
);
if (croppedFile != null) {
setState(() {
_croppedBlobUrl = croppedFile.path;
});
}
}
}
Future<void> _uploadImage() async {
final pickedFile =
await ImagePicker().pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
final blobUrl = pickedFile.path;
debugPrint('picked blob: $blobUrl');
setState(() {
_uploadedBlobUrl = blobUrl;
});
}
}
void _clear() {
setState(() {
_uploadedBlobUrl = null;
_croppedBlobUrl = null;
});
}
}
更多关于Flutter网页图片裁剪插件image_cropper_for_web的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter网页图片裁剪插件image_cropper_for_web的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter Web项目中使用image_cropper_for_web
插件来实现网页图片裁剪功能的代码案例。
首先,你需要在你的pubspec.yaml
文件中添加image_cropper
和image_cropper_for_web
依赖:
dependencies:
flutter:
sdk: flutter
image_cropper: ^3.0.0 # 请检查最新版本号
image_cropper_for_web: ^2.0.0 # 请检查最新版本号
然后运行flutter pub get
来安装这些依赖。
接下来,你需要进行一些配置以确保插件在Web平台上正常工作。在web/index.html
文件中,添加以下代码以允许文件输入(这对图片上传是必要的):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flutter Web App</title>
<!-- 添加以下meta标签 -->
<meta name="google-signin-client_id" content="YOUR_GOOGLE_SIGN_IN_CLIENT_ID">
<meta name="google-signin-scope" content="profile email">
<input type="file" id="file-input" accept="image/*" style="display:none;" multiple>
</head>
<body>
<script>
window.addEventListener('load', function() {
// For allowing file input in image_cropper_for_web
var fileInput = document.getElementById('file-input');
fileInput.click();
});
</script>
<script src="main.dart.js" type="application/javascript"></script>
</body>
</html>
注意:上面的HTML配置中的file-input
部分是为了处理文件输入,但通常image_cropper_for_web
插件会自动处理这些,这里的代码只是为了展示如何可能需要进行一些额外的配置。实际上,你通常不需要手动触发文件输入。
然后,在你的Dart代码中,你可以这样使用image_cropper_for_web
插件:
import 'package:flutter/material.dart';
import 'package:image_cropper/image_cropper.dart';
import 'package:image_picker/image_picker.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Image Cropper for Web Demo'),
),
body: Center(
child: CropImageButton(),
),
),
);
}
}
class CropImageButton extends StatefulWidget {
@override
_CropImageButtonState createState() => _CropImageButtonState();
}
class _CropImageButtonState extends State<CropImageButton> {
File? _imageFile;
Future<void> _pickImage(ImageSource source) async {
final ImagePicker _picker = ImagePicker();
final XFile? image = await _picker.pickImage(source: source);
if (image != null) {
final File imageFile = File(image.path);
final CroppedFile croppedFile = await ImageCropper().cropImage(
sourcePath: image.path,
aspectRatioPresets: [
CropAspectRatioPreset.square,
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.original,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio16x9
],
androidUiSettings: AndroidUiSettings(
toolbarTitle: 'Cropper',
toolbarColor: Colors.deepOrange,
toolbarWidgetColor: Colors.white,
initAspectRatio: CropAspectRatioPreset.original,
lockAspectRatio: false,
),
iosUiSettings: IOSUiSettings(
minimumAspectRatio: 1.0,
),
);
setState(() {
if (croppedFile != null) {
_imageFile = File(croppedFile.path);
}
});
}
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () => _pickImage(ImageSource.gallery),
child: Text('Pick Image from Gallery'),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () => _pickImage(ImageSource.camera),
child: Text('Pick Image from Camera'),
),
SizedBox(height: 20),
if (_imageFile != null)
Image.file(_imageFile!),
],
);
}
}
在这个例子中,我们创建了一个简单的Flutter应用,其中包含两个按钮,一个用于从画廊中选择图片,另一个用于从相机中选择图片。选择图片后,将使用ImageCropper
进行裁剪,并将裁剪后的图片显示在屏幕上。
请注意,由于Web平台的限制,直接从相机选择图片可能不总是可行,这取决于用户的浏览器和权限设置。因此,在实际应用中,你可能需要处理这些潜在的错误和限制。
确保你已经按照插件的官方文档进行了所有必要的配置,并且已经处理了所有可能的平台差异和错误情况。