给应用程序添加交互,就是指的是我们点击某个控件的时候,控件的事件能够触发,并且执行一段逻辑。就比较像我们在 HTML
上面的 click事件
。由于是使用 flutter ,在写法上面有比较大的差别。
在官方网站中完成构建布局。官方的地址:https://flutterchina.club/tutorials/layout/
完成这个布局可以对组件的嵌套有一个比较深刻的理解了。
重点内容
键盘输入内容
、通过滑动屏幕移动滑块
、点击时改变状态
,又或者是随着时间的推移而变化
,比如数据Feed会更新状态。这时我们应该选择使用StatefulWidget
创建一个有状态控件。StatelessWidget
创建一个无状态控件。stateless widget
没有内部状态。 Icon
、IconButton
, 和Text
都是无状态widget
, 他们都是 StatelessWidget
的子类。
stateful widget
是动态的. 用户可以和其交互 (例如输入一个表单、 或者移动一个slider滑块),或者可以随时间改变 (也许是数据改变导致的UI更新)。Checkbox
,Radio
, Slider
,InkWell
, Form
, 以及 TextField
都是 stateful widgets
,他们都是 StatefulWidget
的子类。
由上面的说法,我们可以暂时做一个简单的总结:
自定义有状态的widget
实现一个自定义的有状态widget需要创建两个类:
widget
类,继承自StatefulWidget
。widget
状态并定义该widget build()
方法的类,它继承自State
。自定义State类存储可变信息 - 可以在widget的生命周期内改变逻辑和内部状态以下是固定的写法。首先需要创建一个 Widget(下面代码中为 FavoriteWidget
) 继承于 StatefulWidget
。然后给创建的 Widget (下面代码中为 FavoriteWidget
) 创建一个 状态管理的子类 (下面代码中的 _FavoriteWidgetState
)继承于 State
,并且泛型为 FavoriteWidget
。
FavoriteWidget
类管理自己的状态,因此它重写createState()
来创建状态对象。 框架会在构建widget时调用createState()
。
// 创建一个带有状态的 Widget 需要两个类:StatefulWidget 以及 state
class FavoriteWidget extends StatefulWidget {
// 由于是需要自己管理状态,需要重写 createState()方法
@override
_FavoriteWidgetState createState() => new _FavoriteWidgetState();
}
class _FavoriteWidgetState extends State<FavoriteWidget> {
@override
Widget build(BuildContext context) {}
}
状态对象也定义了build
方法。此build
方法创建一个包含红色IconButton
和Text
的行。 该widget
使用IconButton
(而不是Icon
), 因为它具有一个onPressed
属性,该属性定义了处理点击的回调方法。IconButton
也有一个icon
的属性,持有Icon
。
我们定义出两个变量,用来动态的改变图标(_isFavorited )以及展示的数字(_favoriteCount )。
setState 状态方法为固定的写法,格式为:setState( (){} )
通过使用 '$'+变量名
的方式来展示我们的变量值
注意: 以下划线(_)开头的成员或类是私有的。
class _FavoriteWidgetState extends State<FavoriteWidget> {
// 定义出我们交互时,记录状态的变量
bool _isFavorited = true; // 是否喜欢
int _favoriteCount = 41; // 喜欢的计数
void _toggleFavorite() {
// setState 状态方法为固定的写法,格式为:setState( (){} )
setState(() {
// If the lake is currently favorited, unfavorite it.
if (_isFavorited) {
_favoriteCount -= 1;
_isFavorited = false;
// Otherwise, favorite it.
} else {
_favoriteCount += 1;
_isFavorited = true;
}
});
}
// 将控件设置为 stateful 时,需要在 state方法里面 build 处构建
@override
Widget build(BuildContext context) {
return new Row(
mainAxisSize: MainAxisSize.min,
children: [
//由于图标是可以点击的,所以需要使用 IconButton,并且需要判断展示出不同的图标,需要写上逻辑
new IconButton(
icon: (_isFavorited
? new Icon(Icons.star)
: new Icon(Icons.star_border)),
color: Colors.red[500],
// 点击的时候调用函数,来控制显示图标以及计数
onPressed: _toggleFavorite,
),
new SizedBox(
width: 18.0,
child: new Container(
// 通过使用 '$'+变量名 的方式来展示我们的变量值
child: new Text('$_favoriteCount'),
),
),
]);
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
Widget titleSection = new Container(
// ...
child: new Row(
children: [
new Expanded(
child: new Column(
// ...
),
/**** 添加我们自定义的组件 ****/
new FavoriteWidget(),
],
),
);
return new MaterialApp(
// ...
);
}
}
启动完成就可以看到效果了。
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
// 创建一个带有状态的 Widget 需要两个类:StatefulWidget 以及 state
class FavoriteWidget extends StatefulWidget {
// 由于是需要自己管理状态,需要重写 createState()方法
@override
_FavoriteWidgetState createState() => new _FavoriteWidgetState();
}
class _FavoriteWidgetState extends State<FavoriteWidget> {
// 定义出我们交互时,记录状态的变量
bool _isFavorited = true; // 是否喜欢
int _favoriteCount = 41; // 喜欢的计数
void _toggleFavorite() {
// setState 状态方法为固定的写法,格式为:setState( (){} )
setState(() {
// If the lake is currently favorited, unfavorite it.
if (_isFavorited) {
_favoriteCount -= 1;
_isFavorited = false;
// Otherwise, favorite it.
} else {
_favoriteCount += 1;
_isFavorited = true;
}
});
}
// 将控件设置为 stateful 时,需要在 state方法里面 build 处构建
@override
Widget build(BuildContext context) {
return new Row(
mainAxisSize: MainAxisSize.min,
children: [
//由于图标是可以点击的,所以需要使用 IconButton,并且需要判断展示出不同的图标,需要写上逻辑
new IconButton(
icon: (_isFavorited
? new Icon(Icons.star)
: new Icon(Icons.star_border)),
color: Colors.red[500],
// 点击的时候调用函数,来控制显示图标以及计数
onPressed: _toggleFavorite,
),
new SizedBox(
width: 18.0,
child: new Container(
// 通过使用 '$'+变量名 的方式来展示我们的变量值
child: new Text('$_favoriteCount'),
),
),
]);
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
Column buildButtonColumn(IconData icon, String label) {
Color color = Theme.of(context).primaryColor;
return new Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
new Icon(icon, color: color),
new Container(
margin: const EdgeInsets.only(top: 8.0),
child: new Text(
label,
style: new TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.w400,
color: color,
),
),
),
],
);
}
Widget buttonSection = new Container(
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
buildButtonColumn(Icons.call, 'CALL'),
buildButtonColumn(Icons.near_me, 'ROUTE'),
buildButtonColumn(Icons.share, 'SHARE'),
],
),
);
Widget titleSection = new Container(
padding: const EdgeInsets.all(32.0),
child: new Row(
children: [
new Expanded(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
new Container(
padding: const EdgeInsets.only(bottom: 8.0),
child: new Text(
'Oeschinen Lake Campground',
style: new TextStyle(
fontWeight: FontWeight.bold,
),
),
),
new Text(
'Kandersteg, Switzerland',
style: new TextStyle(
color: Colors.grey[500],
),
),
],
),
),
new FavoriteWidget(),
],
),
);
Widget textSection = new Container(
padding: const EdgeInsets.all(32.0),
child: new Text(
'''
Lake Oeschinen lies at the foot of the Blüemlisalp in the Bernese Alps. Situated 1,578 meters above sea level, it is one of the larger Alpine Lakes. A gondola ride from Kandersteg, followed by a half-hour walk through pastures and pine forest, leads you to the lake, which warms to 20 degrees Celsius in the summer. Activities enjoyed here include rowing, and riding the summer toboggan run.
''',
softWrap: true,
),
);
// 创建一个 material 风格的 app
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
// Material 库中的 Scaffold widget 提供了默认的应用栏 (app bar),标题和构成主页面 widget 树结构的 body 属性。 widget 的子树可以非常复杂。
home: new Scaffold(
body: new ListView(
children: [
new Image.asset(
'images/test01.jpg',
height: 240.0,
fit: BoxFit.cover,
),
titleSection,
buttonSection,
textSection,
],
)));
}
}
附:
官方的文档连接:https://flutterchina.club/tutorials/interactive/