時間外掛和格式化
flutter_cupertino_date_picker
+date_format
參考:
日曆格式化外掛date_format
cloud.tencent.com/developer/a…
import 'package:date_format/date_format.dart';
import 'package:flutter_cupertino_date_picker/flutter_cupertino_date_picker.dart';
void _showDatePicker() {
DatePicker.showDatePicker(
context,
pickerTheme: DateTimePickerTheme(
showTitle: true,
confirm: Text('確定', style: TextStyle(color: Colors.red)),
cancel: Text('取消', style: TextStyle(color: Colors.cyan)),
),
minDateTime: DateTime.parse("2019-05-21"),
// maxDateTime: DateTime.parse(MAX_DATETIME),
initialDateTime: DateTime.now(),
dateFormat: "yyyy-MM-dd",
locale: DateTimePickerLocale.zh_cn,
onConfirm: (dateTime, List<int> index) {
setState(() {
_date = dateTime;
});
},
);
}
複製程式碼
圖片選擇multi_image_picker
參考:
android/app/src/main/AndroidMainFest.xml中加入
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
複製程式碼
android/app/build.gradle中
android {
compileSdkVersion 28
lintOptions {
disable 'InvalidPackage'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.paoding.jihong_horticulture_warehouse"
minSdkVersion 19 //16改成19
targetSdkVersion 28
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
複製程式碼
android/build.gradle
dependencies {
classpath 'com.android.tools.build:gradle:3.5.0'
}
}
複製程式碼
android/gradle/wrapper/gradle-wrapper.properties
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
複製程式碼
最後一條
然後刪掉gradle中原來版本的包
用法參考:
void _uploadPictures() async {
var list =
await MultiImagePicker.pickImages(maxImages: 9, enableCamera: true);
setState(() {
images = images+list;
});
for (var r in list) {
var t = await r.filePath;
await _upLoadImage(File(t));
}
}
_upLoadImage( File croppedFile) async {
String _path = croppedFile.path;
var _name = _path.substring(_path.lastIndexOf("/") + 1, _path.length);
String _suffix = _name.split(".").last.toLowerCase();
ContentType _contentType;
if (_suffix == "jpg") {
_contentType =ContentType("image", "jpeg");
} else if (_suffix == "png") {
_contentType =ContentType("image", 'png');
}
FormData _formData = new FormData.from({
"file": new UploadFileInfo(croppedFile, _name,contentType: _contentType)
});
String host = 'https://app.ji-hong.com.cn/api';
String url='/attachment/upload';
Dio dio = new Dio();
Response response =await dio.post("$host$url", data: _formData);
if (response.statusCode == 200) {
var resCode = response.data['code'];
if (resCode == 200) {
uploadimageList.add(response.data['data']);
print(response.data['data']);
} else if (resCode == 400) {
showToast(response.data['message']);
}
}
}
Widget buildGridView() {
return GridView.builder(
itemCount: images.length + 1,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, crossAxisSpacing: 4, mainAxisSpacing: 3),
itemBuilder: (BuildContext context, int index) {
return index != images.length
? Stack(children: <Widget>[
GestureDetector(
onTap: () {
showDialog(
context: context,
builder: (_) => Center(
child: AssetThumb(
asset: images[index],
width: 300,
height: 300,
),
));
},
child: AssetThumb(
asset: images[index],
width: 105,
height: 105,
),
),
new Positioned(
right: 10,
top: 0.05,
child: new GestureDetector(
onTap: () {
setState(() {
if(uploadimageList.length == images.length){
images.remove(images[index]);
uploadimageList.removeAt(index);}else{
toast("等圖片上傳成功再刪唄");
}
});
},
child: new Container(
decoration: new BoxDecoration(
color: Colors.black45,
shape: BoxShape.circle,
),
child: new Icon(
Icons.close,
color: Colors.white,
size: 20.0,
),
)))
])
: GestureDetector(
onTap: _uploadPictures,
child: Container(
alignment: Alignment.topLeft,
child: LocalImageSelecter.getImage('d_icon_sczp_n',
imageWidth: Adapt.dp(105),
imageHeight: Adapt.dp(105))));
});
}
//提交前的驗證
_getDataList2() async {
if(uploadimageList.length!=images.length){toast("圖片未上傳完畢,稍等。。");return;}
複製程式碼
側滑
flutter_slidable: 0.5.3
toast
toast外掛 pub.flutter-io.cn/packages/ok…
OKToast(
/// set toast style, optional
child:MaterialApp()
);
複製程式碼
自定義封裝:
搞個dart檔案裝這個
import 'package:jihong_horticulture_warehouse/common/CommonInsert.dart';
ToastFuture toast(String text){
return showToast(text,
textPadding:EdgeInsets.fromLTRB(Adapt.dp(14), Adapt.dp(9), Adapt.dp(13), Adapt.dp(9)),
position: ToastPosition(align: Alignment.center,),
backgroundColor: Colors.black,
radius: Adapt.dp(4),
textStyle:
TextStyle(color: MyColors.white, fontSize: MyFonts.mediumminus));
}
複製程式碼
其中Adapt.dp是自適應寬度,要使用的時候引用這個檔案,toast('文字')
;即可
showToastWidget(Center(
child: Container(
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.7),
borderRadius: BorderRadius.circular(10)),
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 28),
child: Column(
children: <Widget>[
LocalImageSelecter.getImage('icon_common_ok',
imageWidth: 44, imageHeight: 44),
SizedBox(
height: 10,
),
Text(
'success',
style: TextStyle(fontSize: 12),
)
],
mainAxisSize: MainAxisSize.min,
),
),
));
複製程式碼
掃描二維碼
有錯誤,由於在pub.dev中引用了最新的版本,導致需要向androidX 移植
改用低版本的,導致包重複。
高階的:不再卑微 - - jdk裡面寫成jre ext.kotlin_version = '1.2.31'圖是1.3.21
Android dependency ‘androidx.core:core’ has different version for the compile (1.0.0) and runtime (1.0.1) classpath. You should manually set the same version via DependencyResolution
複製程式碼
閃光燈英文在
C:\flutter.pub-cache\hosted\pub.dartlang.org\barcode_scan-0.0.6\android\src\main\kotlin\com\apptreesoftware\barcodescan第一個kt檔案裡改成中文
生成二維碼
二維碼生成外掛qr_flutter 3.1.0
低版本的會報錯,謹記。
Flutter picker外掛
彈出列表滑動選擇
https://github.com/yangyxd/flutter_picker/blob/master/example/lib/main.dart
複製程式碼
本地化,長按字元跳出的copy換成複製
在main檔案裡新增:
Widget build(BuildContext context) {
return OKToast(
position: ToastPosition.bottom,
backgroundColor: MyColors.button_bg_grey_deep,
child: MaterialApp(
onGenerateRoute: prefix0.onGenerateRoute,
initialRoute: '/',
title: 'JIHong',
localizationsDelegates: [
PickerLocalizationsDelegate.delegate, // 如果要使用本地化,請新增此行,則可以顯示中文按鈕
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: [
const Locale('en', 'US'),
const Locale('zh', 'CH'),
],
複製程式碼
wifi外掛
後來換成wifi-iot,但是和二維碼外掛衝突,目前手機如果只需要開關wifi的話是挺容易解決的,但是要連線指定wifi應該是隻能android能做到
跑了個deemo
報錯:
gradlew.bat" exited abnormally:
versionCode not found. Define flutter.versionCode in the local.properties file.
解決:
在android/local.properties中加入
sdk.dir=C:\\Users\\EDZ\\AppData\\Local\\Android\\sdk
flutter.sdk=C:\\flutter
下面三句話
flutter.buildMode=debug
flutter.versionName=1.0.0
flutter.versionCode=1
複製程式碼
Flutter 撥打電話和跳轉網頁
url_launcher
pub.flutter-io.cn/packages/ur…
最新版要求的dart.sdk版本要很高
換成url_launcher:5.2.1
flutter_html
pub.flutter-io.cn/packages/fl…
import 'package:flutter_html/flutter_html.dart';
SingleChildScrollView(
child: Html(
data:‘’,
複製程式碼
微信登陸fluwx
獲取code,利用sendAuth
一直出現 沒有這個簽名這個錯誤
deemo的sendAuth我是跑步起來的
然後專案也跟著壞了
重啟了下手機,可以了
main.js
await fluwx.register(
appId: "wx747bca6f419ed7a3",
doOnAndroid: true,
doOnIOS: true,
);
var result = await fluwx.isWeChatInstalled();
print("is installed $result");
複製程式碼
登陸頁面
void initState(){
super.initState();
fluwx.responseFromAuth.listen((response) {
//監聽授權登入回撥
print("code: " + response.code);
});
}
在元件中
ontap:(){ fluwx.sendAuth(scope: "snsapi_userinfo", state: "wechat_sdk_demo_test");}
複製程式碼
相關網站:
地址外掛
import 'package:city_pickers/city_pickers.dart';
String provinceS;
String cityS;
String districtS;
void _selectCity() async {
Result tempResult = await CityPickers.showCityPicker(
context: context,
locationCode: resultAttr != null
? resultAttr.areaId ??
resultAttr.cityId ??
resultAttr.provinceId
: null,
showType: ShowType.pca,
height: 350,
isSort: isSort,
barrierOpacity: barrierOpacityAttr,
itemExtent: customerItemExtent,
cancelWidget: Text('取消',style: TextStyle(color: MyColors.blue_4f,fontSize: MyFonts.f14),),
confirmWidget: Text('確定',style: TextStyle(color: MyColors.blue_4f,fontSize: MyFonts.f14),),
itemBuilder: this.getItemBuilder());
print("locationCode $tempResult");
if (tempResult == null) {
return;
}
this.setState(() {
result = tempResult;
provinceS = result.provinceName;
cityS = result.cityName;
districtS = result.areaName;
pccAddress = "${result.provinceName}${result.cityName}${result?.areaName}";
});
}
複製程式碼
上拉重新整理下拉載入
import 'package:pull_to_refresh/pull_to_refresh.dart';
int biu = 0;//下拉狀態
RefreshController _refreshController =
RefreshController(initialRefresh: false);//是否進去就重新整理
//上拉方法+篩選頁面(方便)
void _onRefresh() async {
// monitor network fetch
await Future.delayed(Duration(milliseconds: 1000));
// if failed,use refreshFailed()
_refreshController.refreshCompleted();
_pageNo = _pageNo2=1;
_list=[];
if(!isPage2) {
_getDataList();
}else{
_getDataList2();
}
_refreshController.loadComplete();
}
//下拉方法
void _onLoading() async {
// monitor network fetch
await Future.delayed(Duration(milliseconds: 1000));
if(!isPage2) {
_pageNo++;
_getDataList();
}else{
_pageNo2++;
_getDataList2();
}
if (biu == 2) {
_refreshController.loadNoData();
//發現只要出現這個無資料狀態就不能再下拉載入,會導致進入篩選頁面也不能下拉
//需要_refreshController.loadComplete();重置下狀態
} else if (biu == 0) {
_refreshController.loadFailed();
} else {
_refreshController.loadComplete();
}
}
bool flag = true;
bool isPage2 = false;//是否篩選頁
int _pageNo = 1;//第幾頁
int _pageNo2 = 1;
List _list = [];
void initState() {
super.initState();
_getDataList();
}
void dispose() { // 銷燬textEditingController
controller1.dispose();
controller2.dispose();
controller3.dispose();
super.dispose();
}
//正常的請求
_getDataList() async {
var res = await HttpManager.netFetch(
context, address.findAllWarehouseComplaint(), {"pageable": {"page": _pageNo, "size": 5}}, null, null, noTip: true);
isPage2 = false;
if (res != null) {
if (res.result) {
if (mounted) {
setState(() {
if (res.data.length != 0) {
_list.addAll(res.data);
biu = 3;
} else {
biu = 2;
}
});
}
}
} else {
biu = 0;
toast(BaseCommon.SERVER_ERROR);
}
}
//篩選頁的請求+下拉
_getDataList2() async{
isPage2 = true;
Map<String,dynamic> map = new Map();
map = {"providerName":controller3.text,"plantName":controller1.text,"status":status,"complaintName":controller2.text,"pageable": {"page": _pageNo2, "size": 5}};
var res = await HttpManager.netFetch(
context, address.filterWarehouseComplaint(), map, null, null, noTip: true);
if (res != null) {
if (res.result) {
if (mounted) {
if(_pageNo2==1&&res.data.length == 0){
if (mounted) {
setState(() {
flag = false;
});
}
}
else if (res.data.length != 0) {
setState(() {
_list.addAll(res.data);
});
biu = 3;
} else {
biu = 2;
}
}
}
} else {
biu = 0;
toast(BaseCommon.SERVER_ERROR);
}
}
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomPadding: false,//讓鍵盤可以覆蓋佈局
key: key7,
backgroundColor: MyColors.grey_f5,
appBar: MyAppBar(
title: "售後投訴",
isBack: true,
rightEvent: InkWell(
child: Text("篩選"),
onTap: _handlerDrawerButton,
// Scaffold.of(context).openEndDrawer();
// CommonUtil.openPage(context, forgetPassword2());
),
),
body: SmartRefresher(
enablePullDown: true,
enablePullUp: true,
header: WaterDropHeader(),
footer: CustomFooter(
builder: (BuildContext context, LoadStatus mode) {
Widget body;
if (mode == LoadStatus.idle) {
body = Text("上拉載入");
} else if (mode == LoadStatus.loading) {
body = CupertinoActivityIndicator();
} else if (mode == LoadStatus.failed) {
body = Text("載入失敗!點選重試!");
} else if (mode == LoadStatus.canLoading) {
body = Text("鬆手,載入更多!");
} else {
body = Text("沒有更多資料了!");
}
return Container(
height: 55.0,
child: Center(child: body),
);
},
),
controller: _refreshController,
onRefresh: _onRefresh,
onLoading: _onLoading,
child: flag
? ListView.builder(
itemBuilder: (context, index) {
return _buildList(_list[index]);
},
itemCount: _list.length,
)
: new SearchError(callback: (val) => onDataChange(val)),
),
endDrawer: Container(
複製程式碼