Flutter踩坑日記(持續更新...)

歡樂症患者發表於2020-05-20

我自己踩的坑

設定元件為中文

剛開始去使用一些彈窗元件(例如時間選擇器什麼的),發現裡面的確定和取消都是英文,就去百度了一下方法。

改配置檔案

在pubspec.yaml檔案的對應位置加上

  flutter_localizations:
    sdk: flutter
複製程式碼

Flutter踩坑日記(持續更新...)

修改主入口

在主入口函式新增(這裡還需要引入package:flutter_localizations/flutter_localizations.dart)

import 'package:flutter_localizations/flutter_localizations.dart'; 
複製程式碼
      //設定元件為中文
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: [
        //此處
        const Locale('zh', 'CH'),
        const Locale('en', 'US'),
      ],
      locale: Locale('zh'),
複製程式碼

Flutter踩坑日記(持續更新...)

圖片上傳

這個坑,花了我整整一天的時間(其實就是電腦卡,10分鐘一小卡,30分鐘一大卡,不好除錯)。

Flutter踩坑日記(持續更新...)

外掛

image_picker

開始

直接貼程式碼

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';//這個是自己封裝後的http
import 'package:http_parser/http_parser.dart';

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

class _MyHomePageState extends State<MyHomePage> {
  File _image;

    //照相
  Future getImage() async {
    var image = await ImagePicker.pickImage(source: ImageSource.camera);
    setState(() {
      uploadImgFunc(image);
      _image = image;
    });
  }
    //從相機選擇
  Future openGallery() async {
    var image = await ImagePicker.pickImage(source: ImageSource.gallery);
    setState(() {
      uploadImgFunc(image);
      _image = image;
    });
  }

  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(
        path,
        filename: name,
        contentType:MediaType('image',suffix)//contentType這個引數看情況,下面會講到
      ),
    });
    Dio dio = new Dio();
    var result = await dio.post<String>("介面", 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),
      ),
    );
  }
}

複製程式碼

上面就是一個例子了,現在開始講解。

首先,我們需要引入image_picker這個包,在pubspec.yaml檔案裡面新增對應項

Flutter踩坑日記(持續更新...)
然後在對應檔案引入

import 'dart:io';//io操作
import 'package:dio/dio.dart';
import 'package:image_picker/image_picker.dart';
複製程式碼

寫呼叫方法(這裡以拍照為例)

  Future getImage() async {
    var image = await ImagePicker.pickImage(source: ImageSource.camera);//這裡用到了對應外掛
    setState(() {
      uploadImgFunc(image);
      _image = image;//_image需要在外層定義
    });
  }
複製程式碼

寫上傳方法(重點)

  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(//這裡記得加await
        path,
        filename: name,
        contentType:MediaType('image',suffix)
      ),
    });
    Dio dio = new Dio();
    var result = await dio.post<String>('介面', data: formData);
    print(result);
  }
複製程式碼

dio3.0之後就使用MultipartFile不再使用UploadFileInfo。

MediaType這個需要額外引一個標頭檔案,不然會報錯

import 'package:http_parser/http_parser.dart';
複製程式碼

假如,你們的後端是可以用二進位制的方法來上傳的話,

contentType:MediaType('image',suffix)
複製程式碼

上面那一行可以去掉,不然的話一定要加上,不然後端如果是判斷檔案型別的話可能就過不了。我就是因為這個卡了很久......

ios真機除錯的時候用相機(我同事說的)好像會閃退,因為我沒有mac系統,也沒錢,這裡找個了文章。大家看看吧。

官網文件好像也有說,之前沒看仔細。需要在配置檔案裡面加東西

Flutter踩坑日記(持續更新...)
Flutter踩坑日記(持續更新...)

Flutter踩坑日記(持續更新...)

獲取元素位置

現在,我要獲取某個元素的位置,然後按照位置來定義一個彈窗(showMenu)的位置,例如下圖

Flutter踩坑日記(持續更新...)

定義一個key

GlobalKey positionKey = GlobalKey();
複製程式碼

在需要定位的元素上使用

Text(
      '其他',
      key: positionKey,
      textAlign: TextAlign.center,
      style: TextStyle(
        height: 2.5,
        color: Color.fromRGBO(255, 106, 0, 1),
        fontSize: ScreenAdaper.size(30),
   )
複製程式碼

使用key來獲取位置

在函式內去獲取

    RenderBox renderBox =
        positionKey.currentContext.findRenderObject();
    var offset = renderBox.localToGlobal(Offset.zero);
    print(offset.dx)//橫座標
    print(offset.dx)//縱座標
複製程式碼

ios數字軟鍵盤沒有'完成'按鈕

當我們把輸入框(TextField)的型別(keyboardType)設定number時,Android和ios就會彈出數字鍵盤而不是英文鍵盤,但是ios數字軟鍵盤是沒有所謂的完成按鈕(就是點選後軟鍵盤會收回去)。這時候,我們就需要用到一個外掛了

keyboard_actions

這是一個可以解決上面問題的外掛,如何引入同上面提過的。

使用

在需要用到的元件內先定義一個基礎設定,這裡的actions裡面KeyboardAction有很多設定,推薦去看一下官方文件

  KeyboardActionsConfig _buildConfig(BuildContext context) {
    return KeyboardActionsConfig(
      keyboardActionsPlatform: KeyboardActionsPlatform.ALL,
      keyboardBarColor: Colors.grey[200],
      nextFocus: true,
      actions: [
        KeyboardAction(
          focusNode: _nodeNumberNode,//下面會提到
          toolbarButtons: [
            (node) {
              return GestureDetector(
                onTap: () => node.unfocus(),
                child: Container(
                  padding: EdgeInsets.fromLTRB(8, 8, 16, 8),
                  child: Text(
                    "完成",
                    style: TextStyle(color: Colors.black),
                  ),
                ),
              );
            },
          ],
        ),
      ],
    );
  }
複製程式碼

然後,我們需要定義一個FocusNode來對應設定和輸入框

final FocusNode _nodeNumberNode = FocusNode();
複製程式碼

輸入框設定,需要包一層KeyboardActions

KeyboardActions(
    config: _buildConfig(context),//上面定義的那個基礎設定
    chlid:Container(
        child:TextField(
            focusNode: _nodeNumberNode,
            keyboardType: TextInputType.number,
            textInputAction: TextInputAction.done,
            decoration: InputDecoration(
                hintText: '請輸入',
                border: InputBorder.none,
            ),
            autofocus: false,
            onChanged: (value) {
                setState(() {
                    //賦值操作
                });
            },
        )
    )
)
複製程式碼

這樣就可以了,不過有個要注意的點,然後你的輸入框是放在ListView裡面的話,需要給ListView加一個屬性

shrinkWrap: false,
複製程式碼

相關文章