android+flutter开发笔记(一)
对flutter的详细解惑答案:https://blog.csdn.net/zhangxiangliang2/article/details/75675693
flutter的基础组件使用,参考大神整理:https://blog.csdn.net/sinat_17775997/article/details/82180605
********************************************************************
flutter项目的入口
void main() {
runApp(new MaterialApp(
title: 'My app', // used by the OS task switcher
home: new MyScaffold(),
));
}
或
void main() => runApp(AppSplashPage());
********************************************************************
1、首先是flutter的环境配置和开发环境配置
整理地址:https://blog.csdn.net/u010326875/article/details/88865345
2、然后对于新的语言形式,面向对象的,就会涉及到声明周期:
官方文档介绍:https://book.flutterchina.club/chapter3/flutter_widget_intro.html
1》、android的里面的声明周期存在的类有:
Activity、Fragment、view、service等等; (这里不再赘述了)
2》、flutter里也有声明周期,对应的控件有:
StatelessWidget、StatefulWidget
参考:https://www.imooc.com/article/details/id/68585
一、StatelessWidget的声明周期: ( 构造方法、build )比如:
class MyApp extends StatelessWidget {
//构造函数
MyApp({Key key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
当然,StatelessWidget类里面的方法有:
abstract class StatelessWidget extends Widget {
const StatelessWidget({ Key key }) : super(key: key);
@override
StatelessElement createElement() => StatelessElement(this);
@protected
Widget build(BuildContext context);
}
二、StatefulWidget的声明周期:(构造方法、initState()、build()、setState()、didUpdateWidget()、build())
class MyHomePage extends StatefulWidget {
//构造函数
MyHomePage({Key key, this.title}) : super(key: key);
//定义变量
final String title;
//生命周期函数
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State
@override
Widget build(BuildContext context) {
}
3、flutter里有一个类似于gradle的文件 pubspec.yaml :
官方文档介绍:https://book.flutterchina.club/chapter2/flutter_package_mgr.html?h=pubspec.yaml
一个完整的应用程序往往会依赖很多第三方包,正如在原生开发中,Android使用Gradle来管理依赖,iOS用Cocoapods或Carthage来管理依赖,而Flutter也有自己的依赖管理工具,本节我们主要介绍一下flutter如何使用配置文件pubspec.yaml(位于项目根目录)来管理第三方依赖包。
YAML是一种直观、可读性高并且容易被人类阅读的文件格式,它和xml或Json相比,它语法简单并非常容易解析,所以YAML常用于配置文件,Flutter也是用yaml文件作为其配置文件,Flutter项目默认的配置文件是pubspec.yaml
需要注意的几个点:(pubspec.yaml)
//依赖的第三方的包,等等,按照下面的格式来写;
1》、dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2
## 实现页面加载的loading库
flutter_spinkit: "^3.1.0"
2》、Flutter里面的依赖资源
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
assets:
- images/beijing_log.png ##背景logo图
- images/beijing.jpg ##背景图
3》、在pubspec.yaml添加依赖包后,需要执行 get package 来获取依赖包资源
4、第一个页面,设置整个页面的背景图片:
官方文档介绍图片添加:https://book.flutterchina.club/chapter3/img_and_icon.html
1》、在工程的“根目录下”创建images文件夹里面放上要展示的图片:
android--------------
lib------------------
ios------------------
images---------------
bg.jpg
2》、首先在这里遇到一个坑,flutter加载图片时需要在: pubspec.yaml中声明图片的列表的比如:
参考:https://www.jianshu.com/p/c6135bc044e4
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
assets:
- images/bg.jpg #这个位置格式和图片全名称不能错
3》、Scaffold(
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("images/bg.jpg"),
fit: BoxFit.cover,
),
),
child: Center(
child: Text('Hello Wolrd', style: TextStyle(fontSize: 22.0, color: Colors.white),),
),
),
);
参考:https://www.jianshu.com/p/69aaaa9ffe08
5、主题颜色的使用:
1》、使用Dart的Color类里提供的颜色和对应的透明度值:
new MaterialApp(
title: title,
theme: new ThemeData(
brightness: Brightness.dark,
primaryColor: Colors.lightBlue[800],//颜色值
accentColor: Colors.cyan[600],//颜色值
),
);
2》、使用自定义的ARGB的格式:
参考:https://blog.csdn.net/mengks1987/article/details/84819431
Color c = const Color(0xFF42A5F5);//16进制的ARGB
Color c = const Color.fromARGB(0xFF, 0x42, 0xA5, 0xF5);
Color c = const Color.fromARGB(255, 66, 165, 245);
Color c = const Color.fromRGBO(66, 165, 245, 1.0);//opacity:不透明度
new MaterialApp(
title: title,
theme: new ThemeData(
brightness: Brightness.dark,
primaryColor: const Color(0xFF42A5F5),//自定义颜色值
accentColor: const Color(0xFF42A5F5),//自定义颜色值
),
);
6、组件设置padding:
https://book.flutterchina.club/chapter5/container.html
child: Column(
mainAxisAlignment: MainAxisAlignment.start,//内容从最上面开始
children:
Padding(
//顶部添加50像素补白
padding: const EdgeInsets.only(top: 50.0),//left、top、right、bottom
//图片组件
child: Image(
image: AssetImage("images/beijing_log.png"),
width: 300,
height: 300,
),
),
Text(
'You have pushed the button this many times:',
),
],
),
7、容器添加margin的使用:
https://book.flutterchina.club/chapter5/container.html
body: Container(
// 相当于直接制定了该Container的宽和高,且它的优先级要高于width和height
constraints: new BoxConstraints.expand(width: 250.0, height: 150.0),
margin: const EdgeInsets.all(10.0),//设置整个页面的margin边距值
margin: const EdgeInsets.only(top: 50.0),//left、top、right、bottom 设置margin的边距值
}
8、使用组件TextFiled软键盘弹出导致的bug
【flutter 溢出BUG】 bottom overflowed by 113 PIXELS
解决办法参考:https://blog.csdn.net/u012280292/article/details/81988886
一开始直接使用Scaffold布局,body:new Column 然后结果调出键盘的时候就报这个错了,解决办法是使用SingleChildScrollView包装一下:
body: Container(
alignment: Alignment.topCenter,
//设置登录页面背景图片
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("images/beijing.jpg"),
fit: BoxFit.cover,
),),
child: Center(
child: new SingleChildScrollView(
child: new ConstrainedBox(
//约束布局
constraints: new BoxConstraints(
minHeight: 1000.0,//这个最小的高度一定要设置偏大一些,否则页面内容只有居中不能从顶部罗列组件布局
),
child: new Column(
mainAxisAlignment: MainAxisAlignment.start, //内容从最上面开始
children:
Padding(
//左边添加8像素补白
padding: const EdgeInsets.only(top: 10.0),
child: Image(
image: AssetImage("images/beijing_log.png"),
width: 280,
height: 280,
alignment: Alignment.topCenter,
),
),
],
),
),
),
),
),
9、flutter动态改变变量的内容,而改变VIEW Text的内容值,比如:
StatefulWidget------------------------------------------------
String resultInfoShowText='111';//声明变量
Text(resultInfoShowText),//使用变量
OutlineButton(//点击按钮,改变变量的值,需要在setState里改变
splashColor: const Color(0xFFFFFFFF),
child: Text('按钮'),
onPressed: () {
setState(() {
resultInfoShowText = '漠天';
});
},
),
10、页面StatefulWidget下的组件,抽出一部分单独处理,为了防止内容太多不好管理:
//页面加载器,作为主页面
class LoginPage extends StatefulWidget {
//生命周期函数
@override
LoginPageState createState() => LoginPageState();
}
//主页面(就是类似于activity)
class LoginPageState extends State
//密码控制器,设置监听用
static TextEditingController pwdController=new TextEditingController();
//账号控制器,设置监听用
static TextEditingController nameController=new TextEditingController();
//密码和账号的Container内容
MainContentContainer _mainContentContainer = new MainContentContainer(nameController,pwdController);
//账号密码结果
String resultName = '',resultPwd = '',resultInfoShowText='';
@override
void initState() {
// TODO: implement initState
super.initState();
//设置账号监听(获取TextFiled的内容)
nameController.addListener((){
resultName = nameController.text;
print(resultName);
});
//设置密码监听(获取TextFiled的内容)
pwdController.addListener((){
resultPwd = pwdController.text;
print(resultPwd);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
// appBar: new AppBar(
// title: Text('登录页面'),
// ),
body: Container(
alignment: Alignment.topCenter,
//设置登录页面背景图片
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("images/beijing.jpg"),
fit: BoxFit.cover,
),),
child: Center(
child: new SingleChildScrollView(
child: new ConstrainedBox(
//约束布局
constraints: new BoxConstraints(
minHeight: 1000.0,//这个最小的高度一定要设置偏大一些,否则页面内容只有居中不能从顶部罗列组件布局
),
child: new Column(
mainAxisAlignment: MainAxisAlignment.start, //内容从最上面开始
children:
_mainContentContainer,
],
),
),
),
),
),
);
}
}
//抽出登录页面的账号密码部分(输入框内容的展示)
class MainContentContainer extends Container {
static TextEditingController nameController,pwdController;
MainContentContainer(TextEditingController nameControllerFrom,TextEditingController pwdControllerFrom){
nameController = nameControllerFrom;
pwdController = pwdControllerFrom;
}
@override
// TODO: implement margin
EdgeInsetsGeometry get margin => new EdgeInsets.fromLTRB(50.0, 0, 50.0, 10.0);
@override
// TODO: implement child
Widget get child =>
new SingleChildScrollView(
child: new ConstrainedBox(
//约束布局
constraints: new BoxConstraints(
minHeight: 0.0,
),
child: new Column(
children:
TextField(
controller: nameController,
autofocus: true,
decoration: InputDecoration(
labelText: "用户名",
hintText: "用户名或邮箱",
prefixIcon: Icon(Icons.person),
),
obscureText: true,
style: TextStyle(color: const Color(0xFFFFFFFF)) ,
cursorColor: const Color(0xFFFFFFFF),
),
TextField(
controller: pwdController,
decoration: InputDecoration(
labelText: "密码",
hintText: "您的登录密码",
prefixIcon: Icon(Icons.lock),
),
obscureText: true,
style: TextStyle(color: const Color(0xFFFFFFFF)) ,
cursorColor: const Color(0xFFFFFFFF),
),
])
)
);
}
11、flutter设置控件组件的宽度全屏:
由于flutter的button不支持直接设置width和height所以可以通过Container来实现,也可以通过padding来实现,参考:https://juejin.im/post/5b85f1de6fb9a01a0f24a233
width: double.infinity,
height: double.infinity
//登录按钮
new Container(
height: 40.0,
width: double.infinity,
margin:EdgeInsets.only(left: 50.0,top: 20.0,right: 50.0,bottom: 0.0),
child: OutlineButton(
borderSide: BorderSide(color: const Color(0xFFFFFFFF),width: 1.0,style: BorderStyle.solid),
child: Text('登录'),
onPressed: () {
},
),
),
12、flutter的TextFiled组件的基本使用:
参考:https://book.flutterchina.club/chapter3/input_and_form.html
TextField(
controller: nameController,
focusNode: nameFocusNode,
autofocus: true,
maxLength: 11,
keyboardType: TextInputType.phone,
decoration: InputDecoration(
labelText: "用户名",
hintText: "用户名或邮箱",
prefixIcon: Icon(Icons.person),
hintStyle: TextStyle(color: Colors.green, fontSize: 13.0),
border: InputBorder.none,//隐藏下划线
),
obscureText: true,
),
13、android studio,使用flutter开发,冷启动优化的处理:
1》、flutter工程,对android studio已经做过处理的;在style.xml里:
2》、在对应的 launch_background.xml里:
3》、在纯android原生的项目里,对冷启动的优化:
https://blog.csdn.net/u010326875/article/details/88852940
14、flutter里,Map键值对的使用:
Map
15、flutter里面loading的实现:
参考提供的库:https://pub.flutter-io.cn/packages/flutter_spinkit
1》、Installing
dependencies://在pubspec.yawl文件添加
flutter_spinkit: "^3.1.0"
eg:dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2
## 实现页面加载的loading库
flutter_spinkit: "^3.1.0"
2》、Import
import 'package:flutter_spinkit/flutter_spinkit.dart';
3》、使用
SpinKitRotatingCircle(
color: Colors.white,
size: 50.0,
);
我这边的使用:
https://blog.csdn.net/u010326875/article/details/88976789
16、flutter让组件在最上层展示,比如:loading弹框
flutter有提供stack布局来管理展示层级:
child: Center(
child:new Stack(
children:
Image,//背景图片
new SpinKitHourGlass(color: Colors.blueAccent, size: 30.0,),//loading控件
]
)
)
17、请求接口,访问网络:
1》、以登录接口为例,测试:
参考官方文档:https://book.flutterchina.club/chapter10/http.html 使用基础的HttpClient实现post请求接口:
//+++++++++++++++++++++++++++++++++++ 请求登录接口 +++++++++++++++++++++++++++++++++++++++++++++++++++++
try {
//创建一个HttpClient
HttpClient httpClient = new HttpClient();
Uri uri=Uri(scheme: "https", host: "www.zgjdy.cn", path: "/entrance/mobile_login");
//打开Http连接
HttpClientRequest request = await httpClient.postUrl(uri);
Map
"username":name,
"password":pwd
};
request.add(utf8.encode(json.encode(paramsMap)));
//等待连接服务器(会将请求信息发送给服务器)
HttpClientResponse response = await request.close();
//读取响应内容
String result = await response.transform(utf8.decoder).join();
setState(() {
resultInfoShowText = result;
});
//关闭client后,通过该client发起的所有请求都会中止。
httpClient.close();
} catch (e) {
resultInfoShowText = "请求失败:$e";
} finally {
setState(() {
isShowLoading=false;
});
}
//++++++++++++++++++++++++++++++++++ 请求登录接口 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2》、Flutter 网络请求的三种简单实现,
参考:https://blog.csdn.net/weixin_33955681/article/details/88294968 (这篇帖子比较详细,也挺简单)
第一个登录页面+HttpClient调用登录接口demo源码:https://download.csdn.net/download/u010326875/11082948