从零开始写第一个Flutter app(六)——添加点击事件交互

目录

本节目标

先简单说明下本节要实现的功能,在上一节的基础上添加点击交互,在点击ListView的Item的时候可以选择或取消选择,选择后变红色的心形图标,取消选择恢复灰色边框图标,如下图所示

代码实现

首先在RandomWordsState类中新增final Set<WordPair> _saved = Set<WordPair>();这一行代码,_saved用于保存所有选中的WordPair

class RandomWordsState extends State<RandomWords> {
  final List<WordPair> _suggestions = <WordPair>[];
  final Set<WordPair> _saved = Set<WordPair>();   // Add this line.
  final TextStyle _biggerFont = TextStyle(fontSize: 18.0);
  ...
}

然后在_buildRow()方法中新增final bool alreadySaved = _saved.contains(pair);这行代码,用于判断改Item是否选中状态

Widget _buildRow(WordPair pair) {
  final bool alreadySaved = _saved.contains(pair);  // Add this line.
  ...
}

然后原来的_buildRow()方法中,ListTitle的trailing属性做如下修改,根据当前item是否选中的状态alreadySaved来显示不同的图标和图标颜色

Widget _buildRow(WordPair pair) {
  final bool alreadySaved = _saved.contains(pair);
  return ListTile(
    title: Text(
      pair.asPascalCase,
      style: _biggerFont,
    ),
    trailing: Icon(   // Add the lines from here... 
      alreadySaved ? Icons.favorite : Icons.favorite_border,
      color: alreadySaved ? Colors.red : null,
    ),                // ... to here.
  );
}

最后添加item的点击事件,在_buildRow()方法中的ListTitle中添加onTap属性,这里是关键的代码,在onTap()中调用了setState()方法,如果当前item状态为已选中,就改成未选中,反之,如果当前item状态为已未选中,就改成选中

很多人可能会有疑问,为什么点击事件处理中,我们只更改了状态值,并未像原生开发中那样主动调用notifydatasetchanged()方法来通知UI更新,但是运行后测试却发现达到预期的效果。这就是setState()方法的神奇之处,调用setState()方法,在里面只需更改状态,其余的框架会帮我处理,会通知更新UI,这也是参照了React的模式。

onTap: () {      // Add 9 lines from here...
  setState(() {
    if (alreadySaved) {
      _saved.remove(pair);
    } else {
      _saved.add(pair);
    }
  });
},

最终_buildRow()方法的代码如下所示

Widget _buildRow(WordPair pair) {
  final alreadySaved = _saved.contains(pair);
  return ListTile(
    title: Text(
      pair.asPascalCase,
      style: _biggerFont,
    ),
    trailing: Icon(
      alreadySaved ? Icons.favorite : Icons.favorite_border,
      color: alreadySaved ? Colors.red : null,
    ),
    onTap: () {      // Add 9 lines from here...
      setState(() {
        if (alreadySaved) {
          _saved.remove(pair);
        } else { 
          _saved.add(pair); 
        } 
      });
    },               // ... to here.
  );
}

最终可运行的代码

最终lib/main.dart的代码如下

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Startup Name Generator',
      home: RandomWords(),
    );
  }
}

class RandomWords extends StatefulWidget {
  @override
  RandomWordsState createState() => new RandomWordsState();
}

class RandomWordsState extends State<RandomWords> {
  final _suggestions = <WordPair>[]; // ListView用的数据源
  final _biggerFont = const TextStyle(fontSize: 18.0); // 字体大小
  final Set<WordPair> _saved = Set<WordPair>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Startup Name Generator'),
      ),
      body: _buildSuggestions(), // body为一个ListView
    );
  }

  Widget _buildSuggestions() {
    return ListView.builder(
        padding: const EdgeInsets.all(16.0), // 设置padding
        itemBuilder: (context, i) {
          if (i.isOdd) return Divider(); // 如果为基数,返回分割线

          final index = i ~/ 2; // 由于divider也占一个位置,所以需除以2计算实际的index
          // 若数据源不够,则一次性生成10条数据,这样就可以实现ListView无限滑动的效果
          if (index >= _suggestions.length) {
            _suggestions.addAll(generateWordPairs().take(10));
          }
          // 生成每一条item布局
          return _buildRow(_suggestions[index]);
        });
  }

  // 创建ListView的Item
  Widget _buildRow(WordPair pair) {
    final bool alreadySaved = _saved.contains(pair);
    return ListTile(
      title: Text(
        pair.asPascalCase,
        style: _biggerFont, // 设置样式字体大小
      ),
      trailing: Icon(   // Add the lines from here...
        alreadySaved ? Icons.favorite : Icons.favorite_border,
        color: alreadySaved ? Colors.red : null,
      ),
      onTap: () {      // Add 9 lines from here...
        setState(() {
          if (alreadySaved) {
            _saved.remove(pair);
          } else {
            _saved.add(pair);
          }
        });
      },
    );
  }
}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值