[Flutter Widget]ExpansionTile

前言


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

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

代码:


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没有很大的差别了。

构造方法:

代码:


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实现的啊,感兴趣的小伙伴可以去看下源码哈。

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

代码:

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事件我们可以很轻松的实现我们想要的变换效果。

一起来看下:

代码:

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标识的定制

试一试


根据讲到的知识完成如下效果(注意图标颜色变化)

原文发布于微信公众号 - flutter开发者(Flutter_Developers)

原文发表时间:2018-10-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏everhad

Android自定义评分控件:RatingStarView

RatingStarView Android自定义的评分控件,类似RatingBar那样的,使用星星图标(full、half、empty)作为rating值的“...

3569
来自专栏小灰灰

Java 实现图片合成

图片合成 利用Java的绘图方法,实现图片合成 在开始之前,先定一个小目标,我们希望通过图片合成的方式,创建一个类似下面样式的图片 ? I. 设计思路 首先...

1.2K10
来自专栏章鱼的慢慢技术路

使用Photoshop实现雪花飘落的效果

1834
来自专栏Golang语言社区

【Go 语言社区】HTML5 canvas验证码识别

canvas 的历史这个 HTML 元素是为了客户端矢量图形而设计的。它自己没有行为,但却把一个绘图 API 展现给客户端 JavaScript 以使脚本能够把...

4484
来自专栏Android知识点总结

开源计划之--Android绘图库--LogicCanvas

Painter采用单例模式 优化原型模式,各Shape采用深拷贝来解决构造较长、繁琐的情况 比较new 对象和拷贝的效率问题,拷贝一点。具体见文:来谈谈Ja...

1213
来自专栏算法channel

Python-GUI|Tk类,属性文档使用指南

这是一篇tkinter相关API的介绍性地帮助文档,包括常用的包,类结构图,属性取值等,可以作为一个工具文档,供大家查阅。 01Tk中的包 __main...

3297
来自专栏HT

HTML5版的String Avoider小游戏

HTML5版的String Avoider小游戏 http://www.newgrounds.com/portal/view/300760 蛮简单也蛮考验耐心,...

2158
来自专栏Coco的专栏

谈谈一些有趣的CSS题目(三)-- 层叠顺序与堆栈上下文知多少

1625
来自专栏知晓程序

开发 | 「小游戏」开发难?不妨先从 2048 入手试试看

最近流行微信「跳一跳」小游戏,我也心血来潮写了一个微信小程序版 2048,本篇文章主要分享实现 2048 的算法以及注意的点,一起来学习吧!

1284
来自专栏Java成神之路

JavaUtil_03_图片处理工具类

1664

扫码关注云+社区