前端小白之被逼无奈学flutter~笔记更新第一弹,后续持续更新哦
Flutter
软件环境与编辑器
- 安装flutterJDK,安装教程:https://juejin.cn/post/7047762658237349919
- 编辑器推荐:vscode(code runner , dart ,flutter)
- Android Studio
语言基础
Dart
跨平台性
支持web,android,ios,windows,macos,linux
flutter命令
flutter --version // 版本
flutter doctor // 环境检测
flutter devices // 设备检测
flutter create flutterdemo03 //初始化创建项目
flutter run // 启动项目
flutter run build apk/web/ios // 项目打包
第三方包
pubspec.yaml 文件 中dependencies中新增第三方库
执行flutter packages get 命令,将第三方库拉取到本地
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.0 ## 第三方库
english_words: ^3.1.0
dio: ^4.0.6
dio
网络请求
使用dio第三方库,进行网络请求,并对dio进行封装
/*
* @Author: weiying
* @Date: 2024-08-01 15:52:56
* @LastEditors: weiying
* @LastEditTime: 2024-08-02 14:59:29
* @Description: 网络请求
*/
import 'package:dio/dio.dart';
class HttpConfig {
static const baseUrl = "http://10.4.3.230:5200/EXEASPORTAL";
static const connectTimeout = 5;
static const receiveTimeout = 3;
static const contentType = "application/json; charset=utf-8";
static const accept = "application/json,*/*";
static var token = "";
// static String platform = Platform.isAndroid ? "android" : "ios";
}
class HttpUtils {
//BaseOptions、Options、RequestOptions 都可以配置参数,优先级别依次递增,且可以根据优先级别覆盖参数
Dio dio = Dio(BaseOptions(
//请求基地址,可以包含子路径
baseUrl:HttpConfig.baseUrl,
//连接服务器超时时间,单位是秒.
connectTimeout: 20000,
//响应流上前后两次接受到数据的间隔,单位为秒。
receiveTimeout: 5,
//Http请求头.
headers: {
//do something
"version": "1.0.0"
},
//请求的Content-Type,默认值是"application/json; charset=utf-8",Headers.formUrlEncodedContentType会自动编码请求体.
contentType: HttpConfig.contentType,
//表示期望以那种格式(方式)接受响应数据。接受四种类型 `json`, `stream`, `plain`, `bytes`. 默认值是 `json`,
));
void init(){
//添加拦截器
dio.interceptors.add(InterceptorsWrapper(onRequest: (RequestOptions options, RequestInterceptorHandler handler) {
print("请求之前 header = ${options.headers.toString()}");
// 如果你想完成请求并返回一些自定义数据,你可以使用 `handler.resolve(response)`。
// 如果你想终止请求并触发一个错误,你可以使用 `handler.reject(error)`。
return handler.next(options); //continue
}, onResponse: (Response response, ResponseInterceptorHandler handler) {
print("响应之前");
// 如果你想终止请求并触发一个错误,你可以使用 `handler.reject(error)`。
return handler.next(response); // continue
}, onError: (DioError e, ErrorInterceptorHandler handler) {
print("错误之前");
// 如果你想完成请求并返回一些自定义数据,你可以使用 `handler.resolve(response)`。
return handler.next(e);
}));
}
/*
* get请求
*/
get(url, {data, options, cancelToken}) async {
init();
var response;
try {
response = await dio.get(url, queryParameters: data, options: options, cancelToken: cancelToken);
print('get success---------${response.statusCode}');
print('get success---------${response.data}');
// response.data; 响应体
// response.headers; 响应头
// response.request; 请求体
// response.statusCode; 状态码
} on DioError catch (e) {
print('get error---------$e');
formatError(e);
}
return response;
}
/*
* post请求
*/
post(url, {data, options, cancelToken}) async {
init();
var response;
try {
response = await dio.post(url, data:{
'data':data
}, options: options, cancelToken: cancelToken);
print('post success---------${response.data}');
} on DioError catch (e) {
print('post error---------$e');
formatError(e);
}
return response;
}
/*
* 下载文件
*/
downloadFile(urlPath, savePath) async {
var response;
try {
response = await dio.download(urlPath, savePath, onReceiveProgress: (int count, int total) {
//进度
print("$count $total");
});
print('downloadFile success---------${response.data}');
} on DioError catch (e) {
print('downloadFile error---------$e');
formatError(e);
}
return response.data;
}
/*
* error统一处理
*/
void formatError(DioError e) {
if (e.type == DioErrorType.sendTimeout) {
// It occurs when url is sent timeout.
print("请求超时");
} else if (e.type == DioErrorType.receiveTimeout) {
//It occurs when receiving timeout
print("响应超时");
} else if (e.type == DioErrorType.cancel) {
// When the request is cancelled, dio will throw a error with this type.
print("请求取消");
} else {
//DEFAULT Default error type, Some other Error. In this case, you can read the DioError.error if it is not null.
print("未知错误");
}
}
/*
* 取消请求
*
* 同一个cancel token 可以用于多个请求,当一个cancel token取消时,所有使用该cancel token的请求都会被取消。
* 所以参数可选
*/
void cancelRequests(CancelToken token) {
token.cancel("cancelled");
}
}
引入自己封装的工具类
import 'package:flutter/material.dart';
import 'package:flutterdemo03/util/httpUtil.dart'; // 引入自己封装的工具类
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
Widget build(BuildContext context) {
// 获取表单输入的值
TextEditingController _unameController = TextEditingController();
TextEditingController _upwdController = TextEditingController();
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
autofocus: true,
decoration: InputDecoration(
labelText: "用户名",
hintText: "用户名或邮箱",
prefixIcon: Icon(Icons.person)),
controller: _unameController
),
TextField(
decoration: InputDecoration(
labelText: "密码",
hintText: "您的登录密码",
prefixIcon: Icon(Icons.lock)),
controller: _upwdController,
obscureText: true,
),
TextButton(
child: Text("登录"),
onPressed: ()async {
print(_unameController.text);
var uname = _unameController.text;
var pwd = _upwdController.text;
// 使用自己封装的工具类
var res = await HttpUtils()post("/login", data:{
'userId':uname,
'password':pwd,
'checkCode':'jfkj'
});
print(res);
//导航到新路由
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return NewRoute();
}),
);
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class NewRoute extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("主页"),
),
body: Center(
child: Text("home---这是主页"),
),
);
}
}