在开发中,ActionSheet也是比较经常使用的控件,Flutter里面也提供了相应的控件CupertinoActionSheet
。
CupertinoActionSheet组件 -- ActionSheet in Flutter
import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; import 'package:app/common/toast.dart'; // 从底部弹出CupertinoActionSheet使用showCupertinoModalPopup void _handleTap() { // 某个GestureDetector的事件 if (operateType == 'add' || operateType == 'Edit') { showCupertinoModalPopup( context: context, builder: (BuildContext context) => actionSheet(), ).then((value) {}); } } // 底部弹出菜单actionSheet Widget actionSheet() { return new CupertinoActionSheet( title: new Text( '菜单', style: descriptiveTextStyle, ), actions: <Widget>[ CupertinoActionSheetAction( child: const Text( '打开相机拍照', style: TextStyle( fontSize: 14.0, fontFamily: 'PingFangRegular', ), ), onPressed: () { // 打开相机拍照 _getCameraImage(); // 关闭菜单 Navigator.of(context).pop(); }, ), CupertinoActionSheetAction( child: const Text( '打开相册,选取照片', style: TextStyle( fontSize: 14.0, fontFamily: 'PingFangRegular', ), ), onPressed: () { // 打开相册,选取照片 _getGalleryImage(); // 关闭菜单 Navigator.of(context).pop(); }, ) ], cancelButton: CupertinoActionSheetAction( child: new Text( '取消', style: TextStyle( fontSize: 13.0, fontFamily: 'PingFangRegular', color: const Color(0xFF666666), ), ), onPressed: () { // 关闭菜单 Navigator.of(context).pop(); }, ), ); }
在pubspec.yaml文件里添加:html
image\_picker : ^lastest\_version
image_picker,一个适用于iOS和Android的Flutter插件,用于从图像库中获取图像和使用相机拍摄新照片。android
在Info.plist文件中,该文件位于<项目根目录> /ios/Runner/Info.plist中,增长:ios
<!-- 相册 --> <key>NSPhotoLibraryUsageDescription</key> <string>App须要您的赞成,才能访问相册</string> <!-- 相机 --> <key>NSCameraUsageDescription</key> <string>App须要您的赞成,才能访问相机</string>
在AndroidManifest.xml文件中,该文件位于<项目根目录> android/app/src/main/AndroidManifest.xml中,增长:git
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.FLASHLIGHT" />
// 声明一个list,存放image Widget List<Widget> imageList = List(); List<String> _imgUrls = []; // 存放图片路径 File _cameraImage; File _galleryImage; Future _getCameraImage() async { print('调用了: 打开相机'); var image = await ImagePicker.pickImage(source: ImageSource.camera); // 使用相机 setState(() { _cameraImage = image; print('_cameraImage: ' + _cameraImage.toString()); _uploadPic(_cameraImage); }); } Future _getGalleryImage() async { print('调用了: 打开相册'); var image = await ImagePicker.pickImage(source: ImageSource.gallery); // 使用图库 setState(() { _galleryImage = image; print('_galleryImage: ' + _galleryImage.toString()); _uploadPic(_galleryImage); }); } // 上传图片 void _uploadPic(File imgfile) async { showLoading(context, '上传中,请等待......'); try { String path = imgfile.path; // print('Image path: ' + path); var str = path.split('-'); var filename = str[str.length - 1]; String uploadServer = BaseUrl.uploadServer; FormData formData = FormData.fromMap({ "file": await MultipartFile.fromFile(path, filename: filename), }); Response response = await dio.post(uploadServer, data: formData); // print(response); setState(() { dynamic rtn = jsonDecode(response.toString()); // 解析接口返回的json数据 // print(rtn); String imgUrl = rtn['data']; _imgUrls.add(imgUrl); // print(" _imgUrls:" + _imgUrls.toString()); var isUrl = imgUrl.startsWith('http'); if (!isUrl) { imgUrl = BaseUrl.url + imgUrl; } imageList ..add(Image.network( imgUrl, height: 50, width: 50, fit: BoxFit.fitWidth, // 显示可能拉伸,可能裁剪,宽度充满 )); // print(" imageList:" + imageList.toString()); }); } on DioError catch (e) { //catch 提示 print('catch 提示: ' + e.toString()); if (e.response != null) { print(e.response.data); } else { showToast("数据加载失败"); print(e.request); print(e.message); } } finally { // 隐藏loading框 Navigator.of(context).pop(); } }
其中,showLoading是Flutter 经常使用的提示框showToast、showLoading、showConfirmDialog文章中提到的共用方法。github
Widget _buildGridViewList() { return new Container( width: MediaQuery.of(context).size.width - 40, color: const Color(0xFFFFFFFF), padding: EdgeInsets.only(left: 8.0), child: GridView.builder( shrinkWrap: true, //是否根据子widget的总长度来设置GridView的长度,默认值为false gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( mainAxisSpacing: 3, crossAxisSpacing: 3, crossAxisCount: 3, //每行三列 childAspectRatio: 1.0, //显示区域宽高相等 ), itemCount: imageList.length, itemBuilder: (context, index) { // print("调用了 imageList[" + index.toString() + "]" + imageList[index].toString()); return new Stack( // 堆叠组件 children: <Widget>[ Container( alignment: Alignment.center, height: 54, // width: 54.0, color: const Color(0xFFFFFFFF), padding: EdgeInsets.only(left: 8.0), child: imageList[index], ), Container( height: 54, // width: 54.0, padding: new EdgeInsets.fromLTRB(0, 10, 0, 0), alignment: Alignment.bottomRight, child: GestureDetector( onTap: () => _handleTapDelePic(index), child: Padding( padding: const EdgeInsets.only(right: 5), child: new Text('删除'), ), ), ), ], ); }, ), ); } void _handleTapDelePic(int index) { // print('点击删除 ' + index.toString()); setState(() { imageList.removeAt(index); //删除位置为index的元素 _imgUrls.removeAt(index); //删除位置为index的元素 }); }
CupertinoActionSheet组件 -- ActionSheet in Flutter
Flutter-CupertinoActionSheet的使用
【Flutter】ActionSheet, Alert, Dialog
popup: CupertinoActionSheet组件 -- Actionsheet in flutter
Image Picker plugin for Flutter
Flutter ImagePicker Plugin (No implementation found for method pickImage)
iOS关于相机相册权限设置
image_picker: (最经常使用场景,从相册选择或手机拍照获得照片)json
GridView
Flutter中打造多行列列表GridView组件的使用
Flutter GridView.count 及 GridView.builder
Flutter网格型布局 - GridView篇segmentfault