Flutter 實現ActionSheet底部彈出菜單操做表:打開相機或相冊上傳圖片後GridView網格佈局顯示圖片

CupertinoActionSheet組件 -- ActionSheet in Flutter

在開發中,ActionSheet也是比較經常使用的控件,Flutter裏面也提供了相應的控件 CupertinoActionSheet
CupertinoActionSheet組件 -- ActionSheet in Flutter

CupertinoActionSheet具體使用

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();
        },
      ),
    );
  }

image_picker 使用相機或相冊

pubspec.yaml文件裏添加:html

image\_picker : ^lastest\_version

image_picker,一個適用於iOS和Android的Flutter插件,用於從圖像庫中獲取圖像和使用相機拍攝新照片。android

配置訪問相機、相冊權限

iOS

在Info.plist文件中,該文件位於<項目根目錄> /ios/Runner/Info.plist中,增長:ios

<!-- 相冊 -->   
    <key>NSPhotoLibraryUsageDescription</key>   
    <string>App須要您的贊成,才能訪問相冊</string>   
    <!-- 相機 -->   
    <key>NSCameraUsageDescription</key>   
    <string>App須要您的贊成,才能訪問相機</string>

Android

在AndroidManifest.xml文件中,該文件位於<項目根目錄> android/app/src/main/AndroidManifest.xml中,增長:git

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />

image_picker具體使用:

// 聲明一個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

圖片顯示 GridView

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

相關文章
相關標籤/搜索