Flutter basics: calling the gallery and uploading pictures

Summary

This article mainly introduces how flutter calls system albums, cameras, and image uploads. It mainly uses image_picker and dio plug-ins. First, the renderings:

1. Call the gallery and camera

add plugin

image_picker: ^0.6.7+12

ios: Add NSPhotoLibraryUsageDescription NSCameraUsageDescription and NSMicrophoneUsageDescription under the ios/Runner/Info.plist file for permission application and description. I just write it here:

	<key>NSPhotoLibraryUsageDescription</key>
	<string>App需要您的同意,才能访问相册</string>
	<key>NSCameraUsageDescription</key>
    <string>App需要您的同意,才能访问相机</string>
    <key>NSMicrophoneUsageDescription</key>
    <string>App需要您的同意,才能访问麦克风</string>

android: api29 and below need to be added under the application node of the configuration file (android/app/src/mainAndroidManifest.xml):

 android:requestLegacyExternalStorage="true"

image_picker provides

  • getImage(source: ImageSource.gallery)
  • getImage(source:ImageSource.camera)

Call the album and camera respectively, the following is the interface layout:

 body: new Column(
        //crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          new RaisedButton(onPressed: openGallery, child: new Text('图库')),
          new RaisedButton(onPressed: takePhotos, child: new Text('拍照')),
          if (imagePath == null)
            new Expanded(child: new Center(child: new Text('未选择图片')))
          else
            new Expanded(
                child: new Center(
              child: Image.file(imagePath),
            )),
          new RaisedButton(
            onPressed: upLoadImg,
            child: new Text('上传'),
          )
        ],
      ),
      ..省略..

Two buttons are added here to call the gallery and call the camera respectively, and the rest of the screen is used to display pictures. If no picture is selected, a Text('No picture selected');

Call method:

import 'package:image_picker/image_picker.dart';
...省略其他代码....
//调用相册
 void openGallery() async {
    
    
    PickedFile pickedFile = await _picker.getImage(source: ImageSource.gallery);
    final File file = File(pickedFile.path);
    setState(() {
    
    
      imagePath = file;
    });
  }
//调用相机
  void takePhotos() async {
    
    
    PickedFile pickedFile = await _picker.getImage(
      source: ImageSource.camera,
    );
    final File file = File(pickedFile.path);
    setState(() {
    
    
      imagePath = file;
    });
  }

Write two methods to call the photo album and camera, and then get the picture path from the returned PickedFile through File(pickedFile.path) and update it to the Image that displays the picture.

In addition: The image_picker album can only select one picture, if you need to select more than one, you can find other plug-ins in pub.dev .

2. Upload of pictures

The introduction of dio

dio: 3.0.10

upload picture:

import 'package:dio/dio.dart';
//。。。省略。。。
 upLoadImg() async {
    
    
    if (imagePath == null) {
    
    
      showtoast('未选择图片!');
      return;
    }
    String path = imagePath.path;
    var name = path.substring(path.lastIndexOf("/") + 1, path.length);
    FormData formdata = FormData.fromMap(
      {
    
    
        "参数名xxx": await MultipartFile.fromFile(path,
            filename: name,)
      },
    );
    
    BaseOptions option = new BaseOptions(
        contentType: 'multipart/form-data', responseType: ResponseType.plain);

    Dio dio = new Dio(option);
    //application/json
    try {
    
    
      var respone = await dio.post<String>(
          "后台接口https//xxx.xxx...",
          data: formdata);
      if (respone.statusCode == 200) {
    
    
        showtoast('图片上传成功');
      }
    } catch (e) {
    
    
      print("e:" + e.toString() + "   head=" + dio.options.headers.toString());
    }
  }

It is very simple to get the file according to the file path and file name through the MultipartFile.fromFile method, add it to the form and upload it to the server.
Finally, let me talk about the problem I encountered: the image upload format is wrong, the file can be uploaded to the server through the above code, and the interface also returns 200, but the partner in the background found that the file suffix has changed to .octet-stream and changed to .jpg can be displayed normally. But why became .octet-stream? ? I checked a lot of information and said that the body parameter needs to be changed to form-data instead of binary, so I changed the code to:

BaseOptions option = new BaseOptions(
        contentType: 'multipart/form-data', responseType: ResponseType.plain);

    Dio dio = new Dio(option);

However, it is useless. In fact, the default contentType of the parameter uploaded through FormData is multipart/form-data. Finally, it is found that the file type MediaType needs to be specified when the parameter is constructed. . .

 FormData formdata = FormData.fromMap(
      {
    
    
        "参数名xxx": await MultipartFile.fromFile(path,
            filename: name, contentType: MediaType('image', 'jpeg'))
      },
    );
注意:MediaType在http_parser包下,需要手动引入:
import 'package:http_parser/http_parser.dart';

3. Complete code

Finally attach the complete code

import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:image_picker/image_picker.dart';
import 'package:http_parser/http_parser.dart';

class ImageSelector extends StatefulWidget {
    
    
  String title;

  ImageSelector({
    
    Key key, this.title}) : super(key: key);

  @override
  ImageState createState() => new ImageState(title);
}

class ImageState extends State<ImageSelector> {
    
    
  final _picker = ImagePicker();
  String title;
  File imagePath;

  ImageState(this.title);

  @override
  Widget build(BuildContext context) {
    
    
    // TODO: implement build
    return new Scaffold(
      appBar: new AppBar(title: new Text('$title')),
      body: new Column(
        //crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          new RaisedButton(onPressed: openGallery, child: new Text('图库')),
          new RaisedButton(onPressed: takePhotos, child: new Text('拍照')),
          if (imagePath == null)
            new Expanded(child: new Center(child: new Text('未选择图片')))
          else
            new Expanded(
                child: new Center(
              child: Image.file(imagePath),
            )),
          new RaisedButton(
            onPressed: upLoadImg,
            child: new Text('上传'),
          )
        ],
      ),
    );
  }

  void openGallery() async {
    
    
    PickedFile pickedFile = await _picker.getImage(source: ImageSource.gallery);
    final File file = File(pickedFile.path);
    setState(() {
    
    
      imagePath = file;
    });
  }

  void takePhotos() async {
    
    
    PickedFile pickedFile = await _picker.getImage(
      source: ImageSource.camera,
    );
    final File file = File(pickedFile.path);
    setState(() {
    
    
      imagePath = file;
    });
  }

  upLoadImg() async {
    
    
    if (imagePath == null) {
    
    
      showtoast('未选择图片!');
      return;
    }
    String path = imagePath.path;
    var name = path.substring(path.lastIndexOf("/") + 1, path.length);
    FormData formdata = FormData.fromMap(
      {
    
    
        "参数名xxx": await MultipartFile.fromFile(path,
            filename: name, contentType: MediaType('image', 'jpeg'))
      },
    );

    BaseOptions option = new BaseOptions(
        contentType: 'multipart/form-data', responseType: ResponseType.plain);

    Dio dio = new Dio(option);
    //application/json
    try {
    
    
      var respone = await dio.post<String>(
          "后台接口https//xxx.xxx...",
          data: formdata);
      if (respone.statusCode == 200) {
    
    
        showtoast('图片上传成功');
      }
    } catch (e) {
    
    
      print("e:" + e.toString() + "   head=" + dio.options.headers.toString());
    }
  }

  void showtoast(String toast) {
    
    
    Fluttertoast.showToast(
        msg: toast, gravity: ToastGravity.BOTTOM, textColor: Colors.grey);
  }
}

Summarize

Simple implementation of photo album, camera call and picture upload, solves the problem of wrong format of picture upload.

Guess you like

Origin blog.csdn.net/weixin_40652755/article/details/109724270