The time after the title is the time I used to record my update, don’t care

Set component to Chinese (2020.05.20)

At the beginning of the use of some popover components (such as time picker what), found that the inside of the confirm and cancel are English, went to baidu method.

Modifying configuration files

In the corresponding position of the pubspec.yaml file

  flutter_localizations:
    sdk: flutter
Copy the code

Modifying the main entrance

Add in the main entry function (here we also need to introduce package:flutter_localizations/flutter_localizations. Dart)

import 'package:flutter_localizations/flutter_localizations.dart'; 
Copy the code
      // Set the component to Chinese
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: [
        / / here
        const Locale('zh'.'CH'),
        const Locale('en'.'US'),
      ],
      locale: Locale('zh'),
Copy the code

Photo Upload (2020.05.20)

This pit, took me a whole day (actually is the computer card, 10 minutes a small card, 30 minutes a large card, not easy to debug).

The plug-in

image_picker

start

Paste code directly

import 'dart:collection';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:image_picker/image_picker.dart';
import 'package:flutter/material.dart';
import '.. /.. /base/Http.dart';// This is a self-encapsulated HTTP
import 'package:http_parser/http_parser.dart';

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  File _image;

    / / camera
  Future getImage() async {
    var image = await ImagePicker.pickImage(source: ImageSource.camera);
    setState(() {
      uploadImgFunc(image);
      _image = image;
    });
  }
    // Select from camera
  Future openGallery() async {
    var image = await ImagePicker.pickImage(source: ImageSource.gallery);
    setState(() {
      uploadImgFunc(image);
      _image = image;
    });
  }

  uploadImgFunc(File image) async {
    String path = image.path;// File path
    String name = path.substring(path.lastIndexOf("/") + 1, path.length);/ / file name
    String suffix = name.substring(name.lastIndexOf(".") + 1, name.length);// File suffix
    FormData formData = FormData.fromMap({
      "uploadFile":await MultipartFile.fromFile(
        path,
        filename: name,
        contentType:MediaType('image',suffix)// The contentType argument depends, as discussed below)}); Dio dio =new Dio();
    var result = await dio.post<String> ("Interface", data: formData);
    print(result);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Image Picker Example'),
      ),
      body: Center(
        child: _image == null ? Text('No image selected.') : Image.file(_image),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: getImage,
        tooltip: 'Pick Image', child: Icon(Icons.add_a_photo), ), ); }}Copy the code

So that’s an example. Let’s start now.

First, we need to import the image_picker package and add the corresponding item to the pubspec.yaml file

Then import in the corresponding file

import 'dart:io';/ / IO operations
import 'package:dio/dio.dart';
import 'package:image_picker/image_picker.dart';
Copy the code

Write the call method (here taking a photo)

  Future getImage() async {
    var image = await ImagePicker.pickImage(source: ImageSource.camera);// The corresponding plugin is used here
    setState(() {
      uploadImgFunc(image);
      _image = image;//_image needs to be defined in the outer layer
    });
  }
Copy the code

Write upload method (key)

  uploadImgFunc(File image) async {
    String path = image.path;
    String name = path.substring(path.lastIndexOf("/") + 1, path.length);
    String suffix = name.substring(name.lastIndexOf(".") + 1, name.length);
    FormData formData = FormData.fromMap({
      "uploadFile":await MultipartFile.fromFile(// remember to await
        path,
        filename: name,
        contentType:MediaType('image',suffix)
      ),
    });
    Dio dio = new Dio();
    var result = await dio.post<String> ('interface', data: formData);
    print(result);
  }
Copy the code

So after Dio3.0, we’re going to use MultipartFile instead of UploadFileInfo.

MediaType this requires an additional header file, otherwise an error will be reported

import 'package:http_parser/http_parser.dart';
Copy the code

If you have a backend that can be uploaded in binary,

contentType:MediaType('image',suffix)
Copy the code

The top line can be removed, otherwise you must add, no and then if it is to judge the file type, it may not pass. That’s why I’ve been at…… for a long time

Using the camera (as my colleague said) for ios debugging seems to flash back, since I don’t have a MAC system and no money, here’s an article. Take a look.

The official website document also seems to say that I did not read carefully before. You need to add something to the configuration file

Get element position (2020.05.20)

Now, I need to get the location of an element and define the location of a popover (showMenu) based on that location, as shown in the following image

Define a key

GlobalKey positionKey = GlobalKey();
Copy the code

Used on the element you want to locate

Text(
      'other',
      key: positionKey,
      textAlign: TextAlign.center,
      style: TextStyle(
        height: 2.5,
        color: Color.fromRGBO(255.106.0.1),
        fontSize: ScreenAdaper.size(30),Copy the code

Use key to get the location

Get it inside the function

    RenderBox renderBox =
        positionKey.currentContext.findRenderObject();
    var offset = renderBox.localToGlobal(Offset.zero);
    print(offset.dx)/ / the abscissa
    print(offset.dx)/ / ordinate
Copy the code

Ios Digital soft Keyboard has no ‘done’ button (2020.05.20)

When the keyboardType of the TextField is set to number, Android and ios pop up numeric keyboards instead of English ones, but ios numeric soft keyboards don’t have a done button. At this point, we need a plug-in

keyboard_actions

This is a plugin that can solve the above problem, how to introduce the same as mentioned above.

use

Define a basic setting for the components you need to use. There are many Settings for KeyboardAction in the Actions section. I recommend checking the official documentation

  KeyboardActionsConfig _buildConfig(BuildContext context) {
    return KeyboardActionsConfig(
      keyboardActionsPlatform: KeyboardActionsPlatform.ALL,
      keyboardBarColor: Colors.grey[200],
      nextFocus: true,
      actions: [
        KeyboardAction(
          focusNode: _nodeNumberNode,// This will be mentioned below
          toolbarButtons: [
            (node) {
              return GestureDetector(
                onTap: () => node.unfocus(),
                child: Container(
                  padding: EdgeInsets.fromLTRB(8.8.16.8),
                  child: Text(
                    "Complete", style: TextStyle(color: Colors.black), ), ), ); },],],],); }Copy the code

We then need to define a FocusNode to correspond to the Settings and input fields

final FocusNode _nodeNumberNode = FocusNode();
Copy the code

Input box Settings, need to wrap a layer of KeyboardActions

KeyboardActions(
    config: _buildConfig(context),// The base Settings defined above
    chlid:Container(
        child:TextField(
            focusNode: _nodeNumberNode,
            keyboardType: TextInputType.number,
            textInputAction: TextInputAction.done,
            decoration: InputDecoration(
                hintText: 'Please enter',
                border: InputBorder.none,
            ),
            autofocus: false,
            onChanged: (value) {
                setState(() {
                    // Assign}); },)))Copy the code

That’s fine, but there’s one caveat, and then if your input field is inside the ListView, you need to add a property to the ListView

shrinkWrap: false.Copy the code

The showDialog view does not refresh in time.

After showDialog is used, the current dialog cannot be updated by setState(). Since dialog is actually another page, another route to be exact, and since dialog is also popped through the Navigator, it has the same status as your current main page, so we need to use a different way to implement it.

Let’s start by looking at the most basic form of showDialog

showDialog(
    context: context,
    builder: (context) {
      return AlertDialog(
        ...
      );
    }
);
Copy the code

The first way

After solving the problem

showDialog(
    context: context,
    builder: (context) {
      return StatefulBuilder(// Use StatefulBuilder first
        builder: (context, state) {// Add state
          return AlertDialog(
            title: Text('Popover title'),
            content: Container(
              height: ScreenAdaper.height(200),//ScreenAdaper is your own screen adaptation, you can use the numbers directly
              child: Column(
                children: <Widget>[
                  InkWell(
                    child: Row(
                      children: <Widget>[
                       Image.asset(
                            'images/task_leadicon.png',
                            width:ScreenAdaper.height(60),
                        )
                      ],
                    ),
                    onTap: () async {
                      state(() {// This is the main point
                        / /... I'm going to do an assignment here
                      });
                    },
                  ),
                ],
              ),
            ),
            actions: <Widget>[
              FlatButton(
                child: Text('confirm'),
                onPressed: () async {
                  Navigator.pop(context);
                },
              ),
              FlatButton(
                child: Text('cancel'), onPressed: () { Navigator.pop(context); },),,); }); });Copy the code

The second way

There’s another way to write this, which is to define a popover yourself, but I haven’t done that yet, but I’m going to paste someone else’s code

showDialog(
    context: context,
    builder: (context) {
        String label = 'test';
        return DialogContent(
            label: label,
        );
    });
class DialogContent extends StatefulWidget {
  final String label;
  DialogContent({Key key, this.label}) : super(key: key);
  @override
  State<StatefulWidget> createState() => DialogContentState();
}
class DialogContentState extends State<DialogContent> {
  String label = ' ';
  @override
  void initState() {
    super.initState();
    label = widget.label;
  }
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      child: Text(label),
      onTap: () {
        setState(() {
          label = 'test9'; }); }); }}Copy the code

The above pit is my own development encountered and solved, if you also encountered these pit, and the method I mentioned is also useful, give a thumbs up!! If it doesn’t work, leave a helpful tip in the comments section