Flutter开发者

ExpansionTile

2018-10-08

上期回顾

在前面的文章红我们学习了Chip的用法,使用Chip可以很方便的完成对想要的东西打上想要的标签。在文章的最后让大家实现如下的效果

其实实现起来非常的简单,使用随机的颜色和随机的图标来完成Wrap的布局,代码非常的简单。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106

import 'package:flutter/material.dart';
import 'dart:math';

void main() {
runApp(MaterialApp(
home: MyApp(),
));
}

class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
final List<MyChip> listData = [];
final List<Icon> icons = [];

Color _randomColor() {

var red = Random.secure().nextInt(255);
var greed = Random.secure().nextInt(255);
var blue = Random.secure().nextInt(255);
return Color.fromARGB(255, red, greed, blue);
}

@override
void initState() {
super.initState();

icons.add(Icon(Icons.delete_forever, color: _randomColor()));
icons.add(Icon(Icons.message, color: _randomColor()));
icons.add(Icon(Icons.print, color: _randomColor()));
icons.add(Icon(Icons.add, color: _randomColor()));
icons.add(Icon(Icons.security, color: _randomColor()));
icons.add(Icon(Icons.cake, color: _randomColor()));
icons.add(Icon(Icons.http, color: _randomColor()));
icons.add(Icon(Icons.location_city, color: _randomColor()));
icons.add(Icon(Icons.apps, color: _randomColor()));
for (int i = 0; i < 20; i++) {
listData.add(new MyChip("add$i", _randomColor(),
icons[Random.secure().nextInt(icons.length)], _removeChip));
}
}

void _removeChip(MyChip chip) {
setState(() {
listData.remove(chip);
});
}

void _addChip(MyChip chip) {
setState(() {
listData.add(chip);
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Chip"),
actions: <Widget>[
new IconButton(
icon: new Icon(Icons.add),
onPressed: () {
_addChip(MyChip("add", _randomColor(),
icons[Random.secure().nextInt(icons.length)], _removeChip));
})
],
),
body: Wrap(
spacing: 5.0,
runSpacing: 5.0,
children: listData,
),
);
}
}

class MyChip extends StatelessWidget {
final tipText;
final color;
final avatar;

var callback;

MyChip(this.tipText, this.color, this.avatar, this.callback);

@override
Widget build(BuildContext context) {
return Chip(
label: Text(tipText),
onDeleted: () {
callback(this);
},
avatar: avatar,
labelStyle: TextStyle(
color: color,
),
deleteIconColor: color,
deleteButtonTooltipMessage: "删除该条",
);
}
}

在今天的文章中我们来看下ExpansionTile的使用。

ExpansionTile

ExpansionTile是什么东西?其实就是一个有标题可以展开的控件而已,其他就跟其他的layout没有很大的差别了。

构造方法:

1
2
3
4
5
6
7
8
9
10
ExpansionTile({
Key key,
this.leading,//和ListTitle类似,在文字前面的Widget
@required this.title,//和ListTitle类似,文字
this.backgroundColor,//背景
this.onExpansionChanged,//展开或者关闭的监听
this.children = const <Widget>[],//内部孩子
this.trailing,//和ListTitle类似,右侧图标
this.initiallyExpanded = false,//默认是否展开
})

ExpansionTile的构造方法可以说也是足够的简单,哈。

为什么说ExpansionTile的很多属性都跟ListTitle类似啊?那是因为它内部就是使用ListTitle实现的啊,感兴趣的小伙伴可以去看下源码哈。

接下来还是来看个简单的例子吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30



import 'package:flutter/material.dart';

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('ExpansionTile')),
body: ListView(children: <Widget>[
ExpansionTile(title: const Text('更多精彩'), children: <Widget>[
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(3.0),
color: Colors.blueAccent,
),
height: 100.0,
margin: EdgeInsets.all(5.0),
),
])
]));
}
}

void main() {
runApp(MaterialApp(
home: MyApp(),
));
}

在上面的代码中,我们仅仅定义ExpansionTile的title和children两个属性,children我们仅仅放了一个高度为100的Container。

看下效果:

当然,我们可以给ExpansionTil设置背景颜色,并设置默认展开

backgroundColor: Colors.blueAccent.withOpacity(0.1),

initiallyExpanded: true,

当然,我们也可以给ExpansionTile设置一个leading或者修改右侧展开关闭图标

leading: Icon(Icons.whatshot,color: Colors.redAccent,),

trailing: Icon(Icons.chevron_right),

可以看到我们在文字的左侧放置了一个“火”的图标,把文字的右侧的图标改成了一个向右的小箭头,效果还不错,但是细心的小伙伴会发现右侧的箭头并没有像默认的trailing那样会随着ExpansionTile的展开和关闭来做变换。

所以这里我们就需要借助于我们前面讲到的动画的知识了,借助于RotationTransition和ExpansionTile的onExpansionChanged事件我们可以很轻松的实现我们想要的变换效果

一起来看下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

import 'package:flutter/material.dart';

void main() {
runApp(new MaterialApp(
home: MyApp(),
));
}

class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
Animation animation;
AnimationController animationController;

@override
void initState() {
super.initState();
animationController = new AnimationController(
vsync: this, duration: Duration(milliseconds: 200));
animation = new Tween(begin: 0.0, end: 0.5).animate(animationController);
}

_changeOpacity(bool expand) {
setState(() {
if (expand) {
animationController.forward();

} else {
animationController.reverse();


}
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('ExpansionTile')),
body: ListView(children: <Widget>[
ExpansionTile(
title: const Text('更多精彩'),
backgroundColor: Colors.blueAccent.withOpacity(0.1),
initiallyExpanded: true,
leading: Icon(
Icons.whatshot,
color: Colors.redAccent,
),
trailing: RotationTransition(
turns: animation,
child: const Icon(Icons.chevron_right),
),
onExpansionChanged: (bool){
_changeOpacity(bool);
},
children: <Widget>[
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(3.0),
color: Colors.blueAccent),
height: 100.0,
margin: EdgeInsets.all(5.0),
),
])
]));
}
}

效果如下:

当然,我在这里仅仅是为了演示,界面就这样子哈,大家可以根据自己的需要来定制自己的界面

小结

  • 使用ExpansionTile可以很轻松的实现界面View展开效果
  • 使用动画可以完成自己对trailing标识的定制

试一试

根据讲到的知识完成如下效果

使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

打赏请备注姓名或者昵称,方便我后期统计哦

关注公众号,及时查阅最新文章