前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[- Flutter 数据&状态篇 -] setState

[- Flutter 数据&状态篇 -] setState

作者头像
张风捷特烈
发布2020-04-30 15:20:41
1.3K0
发布2020-04-30 15:20:41
举报
0.1:对我而言,一个产品有四层境界
代码语言:javascript
复制
1.造都造不出来
2.它又不是不能用    <----
3.用的时候大家都不说话
4.如丝般顺滑,易拓展,易修改,易复用

0.2:要说的话

注意:本篇是对状态最基本的使用。虽然比较糙,但是并不代表不重要 后面两篇是基于此篇的优化,所以这篇一定要看懂,才能跟上我的思维。 效果如下,单从界面上来看,我还是比较满意的。


0.3: 简介一下

本项目主要包括以下几点:

代码语言:javascript
复制
1. 输入一个待办事项,下面的ListView动态更新  
2. 条目的复选框选中,条目的文字自动添加下划线
3. 条目的复选框非选中,条目的文字自动取消下划线
4. 三个按钮会根据是否完成而过滤数据,显示相应条目

1.静态界面的实现

万里长征第一步,当然是先把静态界面搞出了。

代码语言:javascript
复制
import 'package:flutter/material.dart';

class TodoList extends StatefulWidget {
  @override
  _TodoListState createState() => _TodoListState();
}

class _TodoListState extends State<TodoList> {
  @override
  Widget build(BuildContext context) {
        return Container();
  }
}

1.1.输入框的组件

通过一个TextField和RaisedButton进行拼合,样式什么的自己看,就不废话了。 我感觉这样挺好看的,不枉我精心调试一番。喜欢的话,可以自己抽个组件。

代码语言:javascript
复制
var textField = TextField(
  controller: new TextEditingController(text: this.text),
  keyboardType: TextInputType.text,
  textAlign: TextAlign.start,
  maxLines: 1,
  cursorColor: Colors.black,
  cursorWidth: 3,
  style: TextStyle(
      fontSize: 16, color: Colors.lightBlue, backgroundColor: Colors.white),
  decoration: InputDecoration(
    filled: true,
    fillColor: Colors.white,
    hintText: '添加一个待办项',
    hintStyle: TextStyle(color: Colors.black26, fontSize: 14),
    contentPadding: EdgeInsets.only(left: 14.0, bottom: 8.0, top: 8.0),
    focusedBorder: OutlineInputBorder(
      borderSide: BorderSide(color: Colors.white),
      borderRadius: BorderRadius.only(
          topLeft: Radius.circular(10), bottomLeft: Radius.circular(10)),
    ),
    enabledBorder: UnderlineInputBorder(
      borderSide: BorderSide(color: Colors.white),
      borderRadius: BorderRadius.only(
          topLeft: Radius.circular(10), bottomLeft: Radius.circular(10)),
    ),
  ),
  onChanged: (str) {
    //输入时的回调
  },
);
var btn = RaisedButton(
  child: Icon(Icons.add),
  padding: EdgeInsets.zero,
  onPressed: () {
    //按钮点击回调
  },
);

var inputBtn = Row(
  mainAxisAlignment: MainAxisAlignment.center,
  children: <Widget>[
    Container(
      child: textField,
      width: 200,
    ),
    ClipRRect(
      borderRadius: BorderRadius.only(
          topRight: Radius.circular(10), bottomRight: Radius.circular(10)),
      child: Container(
        child: btn,
        width: 36,
        height: 36,
      ),
    ),
  ],
);

1.2.三个按钮

三个按钮,比较简单

代码语言:javascript
复制
var op = Row(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: <Widget>[
    RaisedButton(
      color: Colors.blue,
      onPressed: () {
      },
      child: Text("全部"),
    ),
    RaisedButton(
      onPressed: () {
      },
      child: Text("已完成"),
    ),
    RaisedButton(
      onPressed: () {
      },
      child: Text("未完成"),
    ),
  ],
);

1.3.待准备的数据
  • 用一个Map盛放文字和是否选中的
代码语言:javascript
复制
var todo = <String, bool>{};
  • 定义一个状态枚举
代码语言:javascript
复制
enum ShowType { 
    all, 
    todo, 
    done 
}
  • 类中设置初始变量
代码语言:javascript
复制
class _TodoListState extends State<TodoList> {
  var todo = <String, bool>{};//列表数据
  var text;//当前输入文字
  var showType = ShowType.all;//显示类型
}

1.4:根据数据形成列表

注意:如何Map获取对应索引处的键,值。根据值的true/fase来控制decoration的有无

代码语言:javascript
复制
Widget formList(Map<String, bool> todo) {
    return ListView.builder(
      itemCount: todo.length,
      padding: EdgeInsets.all(8.0),
      itemExtent: 50.0,
      itemBuilder: (BuildContext context, int index) {
        var key = todo.keys.toList()[index];//键
        var value = todo.values.toList()[index];//值
        var text = Align(
          child: Text(
            todo.keys.toList()[index],
            style: TextStyle(
              decorationThickness: 3,
                decoration: value
                    ? TextDecoration.lineThrough
                    : TextDecoration.none,
                decorationColor: Colors.blue),
          ),
          alignment: Alignment.centerLeft,
        );

        return Card(
          child: Row(
            children: <Widget>[
              Checkbox(
                onChanged: (b) {
                 //Checkbox点击
                },
                value: todo.values.toList()[index],
              ),
              text
            ],
          ),
        );
      },
    );
  }

1.5:拼组

这里要注意,用Expanded包一下,ListView才能自延展自己的尺寸 直接写的话啊,由于高度未知,会崩掉。

代码语言:javascript
复制
return Column(
  children: <Widget>[inputBtn, op, Expanded(child: formList(todo))],
);

2.状态的更新
2.1:鸟瞰全局

这里状态有点乱,我画了幅图说明一下:

代码语言:javascript
复制
状态量有三个:text 输入框的文字,todo列表数据,showType展现类型
1.输入框通过监听,改变text的值
2.在添加按钮点击时,将加入到状态值todo中 
3.todo用来渲染Todo列表,根据key和value展现数据和复选框状态
4.复选框通过点击,改变todo的状态,来显示对勾以及文字下划线
5.根据showType的不同,选择过滤的方式。
6.在适宜的状态值改变时,调用老夫的setState来更新

2.2:输入框监听
代码语言:javascript
复制
onChanged: (str) {
  text = str;
},

2.3:点击按钮监听

注意收起键盘的操作FocusScope.of(context).requestFocus(FocusNode());

代码语言:javascript
复制
onPressed: () {
  FocusScope.of(context).requestFocus(FocusNode()); //收起键盘
  if (text != null && text != "") {
    todo[text] = false;//为Map添加数据
    text = "";//输入框文字清空
    setState(() {});
  }
},

2.4:复选框点击
代码语言:javascript
复制
onChanged: (b) {
  todo[key] = b;
  setState(() {});
},

2.5:过滤操作

想了好一会,才想到该如何过滤出想要的元素

代码语言:javascript
复制
showList(ShowType showType) {
  switch (showType) {
    case ShowType.all:
      return formList(todo);
      break;
    case ShowType.todo:
      return formList(Map.fromEntries(todo.entries.where((e) => !e.value)));
      break;
    case ShowType.done:
      return formList(Map.fromEntries(todo.entries.where((e) => e.value)));
      break;
  }
}

2.6:拼合
代码语言:javascript
复制
return Column(
  children: <Widget>[inputBtn, op, Expanded(child: showList(showType))],
);

3. 代码全览
代码语言:javascript
复制
import 'package:flutter/material.dart';

class TodoList extends StatefulWidget {
  @override
  _TodoListState createState() => _TodoListState();
}

enum ShowType { all, todo, done }

class _TodoListState extends State<TodoList> {
  var todo = <String, bool>{};//列表数据
  var text;//当前输入文字
  var showType = ShowType.all;//显示类型

  @override
  Widget build(BuildContext context) {
    var textField = TextField(
      controller: new TextEditingController(text: this.text),
      keyboardType: TextInputType.text,
      textAlign: TextAlign.start,
      maxLines: 1,
      cursorColor: Colors.black,
      cursorWidth: 3,
      style: TextStyle(
          fontSize: 16, color: Colors.lightBlue, backgroundColor: Colors.white),
      decoration: InputDecoration(
        filled: true,
        fillColor: Colors.white,
        hintText: '添加一个待办项',
        hintStyle: TextStyle(color: Colors.black26, fontSize: 14),
        contentPadding: EdgeInsets.only(left: 14.0, bottom: 8.0, top: 8.0),
        focusedBorder: OutlineInputBorder(
          borderSide: BorderSide(color: Colors.white),
          borderRadius: BorderRadius.only(
              topLeft: Radius.circular(10), bottomLeft: Radius.circular(10)),
        ),
        enabledBorder: UnderlineInputBorder(
          borderSide: BorderSide(color: Colors.white),
          borderRadius: BorderRadius.only(
              topLeft: Radius.circular(10), bottomLeft: Radius.circular(10)),
        ),
      ),
      onChanged: (str) {
        text = str;
      },
    );

    var btn = RaisedButton(
      child: Icon(Icons.add),
      padding: EdgeInsets.zero,
      onPressed: () {
        FocusScope.of(context).requestFocus(FocusNode()); //收起键盘
        if (text != null && text != "") {
          todo[text] = false;
          text = "";
          setState(() {});
        }
      },
    );

    var inputBtn = Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Container(
          child: textField,
          width: 200,
        ),
        ClipRRect(
          borderRadius: BorderRadius.only(
              topRight: Radius.circular(10), bottomRight: Radius.circular(10)),
          child: Container(
            child: btn,
            width: 36,
            height: 36,
          ),
        ),
      ],
    );

    var op = Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: <Widget>[
        RaisedButton(
          color: Colors.blue,
          textTheme: ButtonTextTheme.primary,
          onPressed: () {
            showType = ShowType.all;
            setState(() {});
          },
          child: Text("全部"),
        ),
        RaisedButton(
          onPressed: () {
            showType = ShowType.done;
            setState(() {});
          },
          child: Text("已完成"),
        ),
        RaisedButton(
          onPressed: () {
            showType = ShowType.todo;
            setState(() {});
          },
          child: Text("未完成"),
        ),
      ],
    );

    return Column(
      children: <Widget>[inputBtn, op, Expanded(child: showList(showType))],
    );
  }

  showList(ShowType showType) {
    switch (showType) {
      case ShowType.all:
        return formList(todo);
        break;
      case ShowType.todo:
        return formList(Map.fromEntries(todo.entries.where((e) => !e.value)));
        break;
      case ShowType.done:
        return formList(Map.fromEntries(todo.entries.where((e) => e.value)));
        break;
    }
  }

  Widget formList(Map<String, bool> todo) {
    return ListView.builder(
      itemCount: todo.length,
      padding: EdgeInsets.all(8.0),
      itemExtent: 50.0,
      itemBuilder: (BuildContext context, int index) {
        var key = todo.keys.toList()[index];
        var value = todo.values.toList()[index];
        var text = Align(
          child: Text(
            todo.keys.toList()[index],
            style: TextStyle(
              decorationThickness: 3,
                decoration: value
                    ? TextDecoration.lineThrough
                    : TextDecoration.none,
                decorationColor: Colors.blue),
          ),
          alignment: Alignment.centerLeft,
        );

        return Card(
          child: Row(
            children: <Widget>[
              Checkbox(
                onChanged: (b) {
                  todo[key] = b;
                  setState(() {});
                },
                value: todo.values.toList()[index],
              ),
              text
            ],
          ),
        );
      },
    );
  }
}

到这里效果就已经实现了,但是状态值四溢,看着感觉有些难看。 坏的代码就相当于你有个女友,又丑又乱,又凶又恶,有事没事给你找茬。 然而你还不得不一直面对她,问了你一句为什么这么傻,你含着泪说:"又不是不..."

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年07月26日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0.1:对我而言,一个产品有四层境界
    • 0.2:要说的话
      • 0.3: 简介一下
      • 1.静态界面的实现
        • 1.1.输入框的组件
          • 1.2.三个按钮
            • 1.3.待准备的数据
              • 1.4:根据数据形成列表
                • 1.5:拼组
                • 2.状态的更新
                  • 2.1:鸟瞰全局
                    • 2.2:输入框监听
                      • 2.3:点击按钮监听
                        • 2.4:复选框点击
                          • 2.5:过滤操作
                            • 2.6:拼合
                            • 3. 代码全览
                            领券
                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档