- main.dart初始化
main(){
runApp(
Text('123',textDirection: TextDirection.rtl,)
);
}
以上text添加属性不会自动热重载,而是需要点击
runApp是Flutter内部提供的一个函数,当我们启动一个Flutter应用程序时就是从调用这个函数开始的
-
Widget
flutter中万物皆可widget,及组件 -
material设计风格
-
scaffold 脚手架 搭建页面的基本结构
-
flutter的劝退嵌套 可以封装自己的组件
-
statelessWideget
class MyStatelessWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return <返回我们的Widget要渲染的Widget,比如一个Text Widget>;
}
}
包含一个必须重写的方法build
build方法的解析
- fluttter在拿到我们自己创建的statelesswidget时,聚会执行它的build方法
- 我们需要在build方法中告诉flutter,我们的widget希望渲染什么元素,比如一个text widget
- statelesswidget没办法主动去执行build方法,当我们使用的数据发生改变时,build方法会被重新执行
build方法什么情况下会被执行
- 当我们的statelesswidget第一次被插入到widget树中时
- 当我们的父widget发生改变时,子widget会被重新构建
- 如果我们的widget以来inheriterwidget的一些数据,inheritedWidget数据发生改变时
- statefulwidget
7.1 定义到widget中的数据都是不可变的(TODO),需要用final来修饰
7.2 既然widget时不可变的,那么statefulwidget如何来存储可变的在状态呢
fkutter将statefulwidget时必须创建两个类,一个类继承自statefulwidget,作为widget树的一部分,一个类继承子state,用于记录statefulwifget会变化的状态并且根据状态的变化,构建出新的widget
7.3 生命周期
I/flutter (13258): HomeBody build
I/flutter (13258): 执行了MyCounterWidget的构造方法
I/flutter (13258): 执行了MyCounterWidget的createState方法
I/flutter (13258): 执行MyCounterState的构造方法
I/flutter (13258): 执行MyCounterState的init方法
I/flutter (13258): 执行MyCounterState的didChangeDependencies方法
I/flutter (13258): 执行执行MyCounterState的build方法
I/flutter (13258): HomeBody build
I/flutter (13258): 执行了MyCounterWidget的构造方法
I/flutter (13258): 执行MyCounterState的didUpdateWidget方法
I/flutter (13258): 执行执行MyCounterState的build方法
7.3.1 执行state类的构造方法(constructor)来创建对象
7.3.2 执行initstate,一般用于数据初始化或是发送网络请求
注意 这个方法是重写父类的方法,必须调用super,因为父类中会进行一些其他操作
7.3.3 执行didChangeDependencies,这个方法会在①调用initstate时 ② 从其他对象依赖一些数据发生改变时被调用
7.3.4 执行build
7.3.5 当前widget不再使用时,会调用disdpose进行销毁
7.3.6 手动调用setstate方法会根据最新的状态来重新调用build方法,构建对应的widgets
7.3.7 执行didUpdateWidget方法实在父widget触发重建时,系统会调用didUpdateWidget方法
- 图片widget
加颜色滤镜
Container(
child: Image.network(
"http://img0.dili360.com/ga/M01/48/3C/wKgBy1kj49qAMVd7ADKmuZ9jug8377.tub.jpg",
alignment: Alignment.topCenter,
repeat: ImageRepeat.repeatY,
color: Colors.blueGrey,
colorBlendMode: BlendMode.colorDodge,
),
width: 300,
height: 300,
color: Colors.yellow,
),
- boxdecoration
Container(
width: 150,
height: 150,
child: Icon(Icons.pets, size: 32, color: Colors.white),
decoration: BoxDecoration(
color: Colors.amber, // 背景颜色
border: Border.all(
color: Colors.redAccent,
width: 1,
style: BorderStyle.solid
), // 这里也可以使用Border.all统一设置
borderRadius: BorderRadius.circular(20), // 这里也可以使用.only分别设置
boxShadow: [
BoxShadow(
offset: Offset(3, 3),
color: Colors.deepPurpleAccent,
blurRadius: 5
)
],
gradient: LinearGradient(
begin: Alignment.bottomLeft,
end: Alignment.topRight,
colors: [
Colors.blueGrey,
Colors.orangeAccent
]
)
),
)
- listview
分割器
class MySeparatedDemo extends StatelessWidget {
Divider blueColor = Divider(color: Colors.blue);
Divider redColor = Divider(color: Colors.red);
@override
Widget build(BuildContext context) {
return ListView.separated(
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: Icon(Icons.people),
title: Text("联系人${index+1}"),
subtitle: Text("联系人电话${index+1}"),
);
},
separatorBuilder: (BuildContext context, int index) {
return index % 2 == 0 ? redColor : blueColor;
},
itemCount: 100
);
}
}
- slivers
如果一个滑动的视图里需要一个标题视图,一个列表视图,一个网格视图,那么我们怎么能让他们做到统一的滑动效果呢,用customscrollview来统一管理多个滚动视图,在customscrollview中,每一个独立的可滚动的widget被称之为sliver
class HomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return showCustomScrollView();
}
Widget showCustomScrollView() {
return new CustomScrollView(
slivers: <Widget>[
const SliverAppBar(
expandedHeight: 250.0,
flexibleSpace: FlexibleSpaceBar(
title: Text('Coderwhy Demo'),
background: Image(
image: NetworkImage(
"https://tva1.sinaimg.cn/large/006y8mN6gy1g72j6nk1d4j30u00k0n0j.jpg",
),
fit: BoxFit.cover,
),
),
),
new SliverGrid(
gridDelegate: new SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200.0,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 4.0,
),
delegate: new SliverChildBuilderDelegate(
(BuildContext context, int index) {
return new Container(
alignment: Alignment.center,
color: Colors.teal[100 * (index % 9)],
child: new Text('grid item $index'),
);
},
childCount: 10,
),
),
SliverFixedExtentList(
itemExtent: 50.0,
delegate:
SliverChildBuilderDelegate((BuildContext context, int index) {
return new Container(
alignment: Alignment.center,
color: Colors.lightBlue[100 * (index % 9)],
child: new Text('list item $index'),
);
}, childCount: 20),
),
const SliverAppBar(
backgroundColor: Colors.white,
flexibleSpace: FlexibleSpaceBar(
titlePadding: const EdgeInsets.all(0),
title: Center(
child: Text(
'---end---',
style: TextStyle(
color: Colors.black),
textAlign: TextAlign.center,
),
)
),
),
],
);
}
}
- 监听滚动事件
12.1 滚动到指定位置时,出现返回顶部按钮
class MyHomePage extends StatefulWidget {
@override
State<StatefulWidget> createState() => MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> {
ScrollController _controller;
bool _isShowTop = false;
@override
void initState() {
// 初始化ScrollController
_controller = ScrollController();
// 监听滚动
_controller.addListener(() {
var tempSsShowTop = _controller.offset >= 1000;
if (tempSsShowTop != _isShowTop) {
setState(() {
_isShowTop = tempSsShowTop;
});
}
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("ListView展示"),
),
body: ListView.builder(
itemCount: 100,
itemExtent: 60,
controller: _controller,
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text("item$index"));
}
),
floatingActionButton: !_isShowTop ? null : FloatingActionButton(
child: Icon(Icons.arrow_upward),
onPressed: () {
_controller.animateTo(0, duration: Duration(milliseconds: 1000), curve: Curves.ease);
},
),
);
}
}
12.2 监听什么时候开始滚动,什么事件结束滚动
class MyHomeNotificationDemo extends StatefulWidget {
@override
State<StatefulWidget> createState() => MyHomeNotificationDemoState();
}
class MyHomeNotificationDemoState extends State<MyHomeNotificationDemo> {
int _progress = 0;
@override
Widget build(BuildContext context) {
return NotificationListener(
onNotification: (ScrollNotification notification) {
// 1.判断监听事件的类型
if (notification is ScrollStartNotification) {
print("开始滚动.....");
} else if (notification is ScrollUpdateNotification) {
// 当前滚动的位置和总长度
final currentPixel = notification.metrics.pixels;
final totalPixel = notification.metrics.maxScrollExtent;
double progress = currentPixel / totalPixel;
setState(() {
_progress = (progress * 100).toInt();
});
print("正在滚动:${notification.metrics.pixels} - ${notification.metrics.maxScrollExtent}");
} else if (notification is ScrollEndNotification) {
print("结束滚动....");
}
return false;
},
child: Stack(
alignment: Alignment(.9, .9),
children: <Widget>[
ListView.builder(
itemCount: 100,
itemExtent: 60,
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text("item$index"));
}
),
CircleAvatar(
radius: 30,
child: Text("$_progress%"),
backgroundColor: Colors.black54,
)
],
),
);
}
}
- 封装一个打分widget
class HYStarRating extends StatefulWidget {
final double rating;
final double maxRating;
final Widget unselectedImage;
final Widget selectedImage;
final int count;
final double size;
final Color unselectedColor;
final Color selectedColor;
HYStarRating({
@required this.rating,
this.maxRating = 10,
this.size = 30,
this.unselectedColor = const Color(0xffbbbbbb),
this.selectedColor = const Color(0xffe0aa46),
Widget unselectedImage,
Widget selectedImage,
this.count = 5,
}): unselectedImage = unselectedImage ?? Icon(Icons.star, size: size, color: unselectedColor,),
selectedImage = selectedImage ?? Icon(Icons.star, size: size, color: selectedColor);
@override
_HYStarRatingState createState() => _HYStarRatingState();
}
class _HYStarRatingState extends State<HYStarRating> {
@override
Widget build(BuildContext context) {
return Container(
child: Stack(//重叠显示
children: <Widget>[
Row(children: getUnSelectImage(), mainAxisSize: MainAxisSize.min),
Row(children: getSelectImage(), mainAxisSize: MainAxisSize.min),
],
),
);
}
// 获取评星
List<Widget> getUnSelectImage() {
return List.generate(widget.count, (index) => widget.unselectedImage);
}
List<Widget> getSelectImage() {
// 1.计算Star个数和剩余比例等 最高分数和星星个数比
double oneValue = widget.maxRating / widget.count;
// 当前分数所占星星比例整数
int entireCount = (widget.rating / oneValue).floor();
double leftValue = widget.rating - entireCount * oneValue;
// 当前分数所占星星比例小数
double leftRatio = leftValue / oneValue;
// 2.获取start
List<Widget> selectedImages = [];
for (int i = 0; i < entireCount; i++) {
selectedImages.add(widget.selectedImage);
}
// 3.计算 裁剪星星
Widget leftStar = ClipRect(
clipper: MyRectClipper(width: leftRatio * widget.size),
child: widget.selectedImage,
);
selectedImages.add(leftStar);
return selectedImages;
}
}
class MyRectClipper extends CustomClipper<Rect>{
final double width;
MyRectClipper({
this.width
});
@override
Rect getClip(Size size) {
return Rect.fromLTRB(0, 0, width, size.height);
}
@override
bool shouldReclip(MyRectClipper oldClipper) {
return width != oldClipper.width;
}
}