标题后面的时间是我用来记录自己更新上去的时间,不用在意
设置组件为中文(2020.05.20)
刚开始去使用一些弹窗组件(例如时间选择器什么的),发现里面的确定和取消都是英文,就去百度了一下方法。
改配置文件
在pubspec.yaml文件的对应位置加上
flutter_localizations:
sdk: 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'),
图片上传(2020.05.20)
这个坑,花了我整整一天的时间(其实就是电脑卡,10分钟一小卡,30分钟一大卡,不好调试)。
插件
开始
直接贴代码
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文件里面添加对应项
然后在对应文件引入
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系统,也没钱,这里找个了文章。大家看看吧。
官网文档好像也有说,之前没看仔细。需要在配置文件里面加东西
获取元素位置(2020.05.20)
现在,我要获取某个元素的位置,然后按照位置来定义一个弹窗(showMenu)的位置,例如下图
定义一个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数字软键盘没有'完成'按钮(2020.05.20)
当我们把输入框(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,
showDialog视图数据刷新不及时(2020.05.21)
使用showDialog后,通过setState()无法更新当前dialog。因为dialog其实是另一个页面,准确地来说是另一个路由,因为dialog的关闭也是通过navigator来pop的,所以它的地位跟你当前主页面一样,所以我们需要使用另外的方式来实现。
我们先看看showDialog的最基本写法
showDialog(
context: context,
builder: (context) {
return AlertDialog(
...
);
}
);
第一种方法
解决问题后的写法
showDialog(
context: context,
builder: (context) {
return StatefulBuilder(//这里需要先使用StatefulBuilder
builder: (context, state) {//多了个state
return AlertDialog(
title: Text('弹窗标题'),
content: Container(
height: ScreenAdaper.height(200),//ScreenAdaper这个是自己的屏幕适配,大家可以直接使用数字的
child: Column(
children: <Widget>[
InkWell(
child: Row(
children: <Widget>[
Image.asset(
'images/task_leadicon.png',
width:ScreenAdaper.height(60),
)
],
),
onTap: () async {
state(() {//这个是重点
//...这里进行赋值操作
});
},
),
],
),
),
actions: <Widget>[
FlatButton(
child: Text('确认'),
onPressed: () async {
Navigator.pop(context);
},
),
FlatButton(
child: Text('取消'),
onPressed: () {
Navigator.pop(context);
},
),
],
);
},
);
});
第二种方法
这个还有另外一种写法,就是自己再去定义一个弹窗,不过这种我没有试过,这里直接贴别人的代码
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';
});
},
);
}
}
上面的坑都是我自己在开发遇到并且解决了的,如果你也遇到这些坑,而且我提的方法也有用的话,给个赞吧!!!如果没有起到作用,能否在评论区留下有用的方法