在開發中,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