前言
还未安装环境的童鞋可以看下这个flutter环境安装
不错的学习网站:
1.flutter官方中文网站:https://flutterchina.club/docs/
2.Flutter七日游(张风捷特烈):https://juejin.im/user/5b42c0656fb9a04fe727eb37
3.咸鱼官方博客:https://zhuanlan.zhihu.com/xytech
ps:前2个都比较基础,最后一个比较深入
计划将基础控件,布局控件结束后,再进行自定义绘制控件
基础控件
widget: 小器具,装饰品,窗口小部件;这里统一称为控件
要学flutter,肯定要先学会怎么使用控件
统计了一部分控件,做了一个表格:
widget | flutter | android |
---|---|---|
文本 | Text |
TextView |
按钮 | ||
漂浮按钮 | RaisedButton |
Button |
扁平按钮 | FlatButton |
|
边框按钮 | OutlineButton |
|
图片按钮 | IconButton |
ImageButton |
浮动动作按钮 | FloatingActionButton |
FloatingActionButton |
编辑框 | TextField |
EditText |
图片 | Image |
ImageView |
图标 | Icon |
|
复选框 | Checkbox |
CheckBox |
单选框 | Radio |
RadioButton |
单选开关 | Switch |
Switch |
底部弹框 | SnackBar |
SnackBar |
滚动控件 | SingleChildScrollView |
ScrollView |
线性滚动列表 | ListView |
RecyclerView (LinearLayoutManager ) |
网格滚动列表 | GridView |
RecyclerView (GridLayoutManager ) |
自定义滚动 | CustomScrollView |
RecyclerView (StaggeredGridLayoutManager ) |
滚动条 | ScrollBar |
|
弹框 | Dialog |
AlertDialog |
进度条 | ProgressIndicator |
ProgressBar |
圆形进度条 | CircularProgressIndicator |
|
线性进度条 | LinearProgressIndicator |
|
滑动条 | Slider |
SeekBar |
导航栏 | AppBar |
ToolBar |
选项栏 | TapBar+TapBarView |
|
底部导航栏 | BottomNavigationBar |
|
分割线 | Divider |
|
侧滑菜单 | Drawer |
DrawerLayout |
底抽屉 | BottomSheet |
BottomSheet |
流式标签 | Chip |
Chip |
圆形头像 | CircleAvatar |
控件很多,怎么学习来快呢?(ps:自我感觉)
学习之前,我们需要明确2个感念:
- StatelessWidget:无中间状态变化的widget,需要更新展示内容就得通过重新new,flutter推荐尽量使用StatelessWidget
- StatefullWidget:存在中间状态变化的widget,state类用于存放中间态,通过调用state.setState()进行此节点及以下的整个子树更新
然后我们了解androidstudio
的三个快捷键
快捷键 | 作用 |
---|---|
stless | 创建一个StatelessWidget |
stful | 创建一个StatefullWidget |
stanim | 创建一个StatefullWidget ,且包含动画 |
准备工作完成
接下来我们以ScrollBar为例,来学习这个控件:
我们创建一个新的flutter工程时,系统会创建一大堆文件,那么我们的dart代码是在哪呢?
dart代码就在同级目录下的lib文件中
这里会发现同时存在android和ios 2个文件夹,对的,flutter编译后的应用是同时支持双端的(ps:或者说是三端,fuchsia已经在布局了)
enum TargetPlatform {
/// Android: <https://www.android.com/>
android,
/// Fuchsia: <https://fuchsia.googlesource.com/>
fuchsia,
/// iOS: <http://www.apple.com/ios/>
iOS,
}
回归正题,系统会创建一个main.dart文件
import 'package:flutter/material.dart';
//main 程序的主入口
void main() => runApp(MyApp());
//运行一个MaterialApp控件
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
//应用的图标名称
title: 'Flutter Demo',
//主题
theme: ThemeData(
primarySwatch: Colors.blue,
),
//主界面
home: MainPage()
);
}
}
这里代码基本固定了,你肯定要使用MaterialApp
控件的,否则不好看(我这里不说不符合规范)
class MainPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
//脚手架
return Scaffold(
//相当于toolbar,导航栏
appBar: AppBar(
title: Text("flutter"),
),
//正文
body: ScrollBarDemo
);
}
}
我们要开始创建一个ScrollBar
了,先看下其的源码:
class Scrollbar extends StatefulWidget {
/// typically a [Scrollable] widget.
const Scrollbar({
Key key,
@required this.child,
}) : super(key: key);
/// Typically a [ListView] or [CustomScrollView].
final Widget child;
@override
_ScrollbarState createState() => _ScrollbarState();
}
源码说需要传递一个child
,且必须为Scrollable
,然后给了2个选择[ListView] 或 [CustomScrollView]
构造函数中的{}
表示可选命名参数,@required
表示child
这个参数必须传递
Scrollable
我们可以大胆的猜测,能滚动的控件肯定都包涵这个控件,所以我们选类似android中的那个ScrollView
的控件SingleChildScrollView
然后我们写下代码
class ScrollBarDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scrollbar(
child: SingleChildScrollView(
child:Container()
)
);
}
}
接下来看看SingleChildScrollView
class SingleChildScrollView extends StatelessWidget {
const SingleChildScrollView({
Key key,
this.scrollDirection = Axis.vertical,
this.reverse = false,
this.padding,
bool primary,
this.physics,
this.controller,
this.child,
}) : ...,super(key: key);//省略了断言
final Axis scrollDirection; //滚动方向,水平和垂直
final bool reverse; //是否反向,默认不启用
final EdgeInsetsGeometry padding;//间距
final ScrollController controller;//滑动控制器
final bool primary;//默认true
final ScrollPhysics physics;//超过物理边界后的动画效果
final Widget child;
...
@override
Widget build(BuildContext context) {
...
//内部创建了一个Scrollable控件
final Scrollable scrollable = Scrollable(
axisDirection: axisDirection,
controller: scrollController,
physics: physics,
viewportBuilder: (BuildContext context, ViewportOffset offset) {
return _SingleChildViewport(
axisDirection: axisDirection,
offset: offset,
child: contents,
);
},
);
return primary && scrollController != null
? PrimaryScrollController.none(child: scrollable)
: scrollable;
}
}
源码可以看出,所有参数都是可选的,也就是说child其实也可以不传的,但这样就整个界面就是空白的
class ScrollBarDemo extends StatelessWidget {
final String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
@override
Widget build(BuildContext context) {
return Scrollbar(
child: SingleChildScrollView(
child:Container(
color: Colors.redAccent,
width: 360,
child: Column(
//创建一个Text控件列表
children: str.split("").map((c) => Text(c, textScaleFactor: 2.0,)).toList(),
)
)
)
);
}
}
关于布局、监听、路由、手势等接下来在介绍
小小的总结一下
1.遇到一个widget,先看它的构造函数(可能有多个)
a. StatelessWidget,看其build
方法做了什么
b. StatefulWidget,先找到createState()
,然后在state
类中看其build
方法做了什么
2.配合源码中的英文注释加以理解
3.动手实践一番,测试效果
最后说明一下,flutter生成的代码都封装在libflutter.so中,不再是以前的.class文件
github代码:https://github.com/leaf-fade/flutterDemo
小尾巴:文章有错误的地方请不吝指出,会及时更改