Flutter:根据类型对 ListView 项进行排序

Posted

技术标签:

【中文标题】Flutter:根据类型对 ListView 项进行排序【英文标题】:Flutter: Sorting ListView items based on type 【发布时间】:2019-09-15 06:14:25 【问题描述】:

所以我在 Flutter 的项目管理应用程序中有一个 listview.builder。这个列表视图充满了任务(它们可以是:新的、开始的、完成的)。我从 API 获取这些数据,并希望“新”的数据出现在顶部,开始出现在中间的数据和“完成”的数据的底部! - This is how it looks right now 这是我的,请注意我从 API/JSON 获取状态

class ProjectTask 
final int id;
final String description;
final String state;
final List assigned_users;
final List subtasks;

ProjectTask(this.id,
  this.description,
  this.state,
  this.assigned_users,
  this.subtasks);

列表视图

else return ListView.builder(
        itemCount: snapshot.data.length,
        itemBuilder: (BuildContext context, int index) 

          if(snapshot.data[index].state == "done") 
            return Slidable(

              //SLIDABLE STUFF
              delegate: SlidableStrechDelegate(),
              actionExtentRatio: 0.25,
              actions: <Widget>[

                //ACTION ONE
                IconSlideAction(
                  caption: ("Information"),
                  foregroundColor: Colors.white,
                  color: Colors.black38,
                  icon: Icons.info,
                  onTap: () 
                    Navigator.push(context, MaterialPageRoute(builder: (context)=>projectTask(snapshot.data[index])));
                  ,
                ),
              ],

              child: ListTile(
                onTap: () 
                  Navigator.push(context, MaterialPageRoute(builder: (context) => projectTask(
                      snapshot.data[index],
                  )));
                ,
                title: Text("$snapshot.data[index].description[0].toString().toUpperCase()"
                    "$snapshot.data[index].description.toString().substring(1)", maxLines: 1, style: TextStyle(
                    color: Colors.black87, fontSize: 17)
                ),
                subtitle: Text("done"),
                leading: Icon(Icons.check_circle, color: Colors.green),
                trailing: Icon(Icons.arrow_right, color: Colors.black54,),
              ),
            );
          
          else if(snapshot.data[index].state == "started") 
            return Slidable(

              //SLIDABLE STUFF
              delegate: SlidableStrechDelegate(),
              actionExtentRatio: 0.25,
              actions: <Widget>[
                //ACTION ONE
                IconSlideAction(
                  caption: ("Information"),
                  foregroundColor: Colors.white,
                  color: Colors.black38,
                  icon: Icons.info,
                  onTap: () 
                    Navigator.push(context, MaterialPageRoute(builder: (context)=>projectTask(snapshot.data[index])));
                  ,
                ),
              ],
              secondaryActions: <Widget>[

                //ACTION TWO
                IconSlideAction(
                  caption: ("Complete Me"),
                  color: Colors.green,
                  icon: Icons.radio_button_checked,
                  onTap: () 
                    Navigator.push(context, MaterialPageRoute(builder: (context)=>projectTask(snapshot.data[index])));
                  ,
                )
              ],

              child: ListTile(
                onTap: () 
                  Navigator.push(context, MaterialPageRoute(builder: (context) => projectTask(
                    snapshot.data[index],
                  )));
                ,
                title: Text("$snapshot.data[index].description[0].toString().toUpperCase()"
                    "$snapshot.data[index].description.toString().substring(1)", maxLines: 1, style: TextStyle(
                    color: Colors.black87, fontSize: 17)
                ),
                subtitle: Text("working"),
                leading: Icon(Icons.radio_button_checked, color: Colors.blue),
                trailing: Icon(Icons.arrow_right, color: Colors.black54,),
              ),
            );
          
          else 
            return Slidable(

              //SLIDABLE STUFF
              delegate: SlidableStrechDelegate(),
              actionExtentRatio: 0.25,
              actions: <Widget>[
                //ACTION ONE
                IconSlideAction(
                  caption: ("Information"),
                  foregroundColor: Colors.white,
                  color: Colors.black38,
                  icon: Icons.info,
                  onTap: () 
                    Navigator.push(context, MaterialPageRoute(builder: (context)=>projectTask(snapshot.data[index])));
                  ,
                ),
              ],
              secondaryActions: <Widget>[

                //ACTION TWO
                IconSlideAction(
                  caption: ("Start Work"),
                  color: Colors.blue,
                  icon: Icons.radio_button_checked,
                  onTap: () 
                    Navigator.push(context, MaterialPageRoute(builder: (context)=>projectTask(snapshot.data[index])));
                  ,
                )
              ],

              //LISTTILE
              child: ListTile(
                onTap: () 
                  Navigator.push(context, MaterialPageRoute(builder: (context) => projectTask(
                    snapshot.data[index],
                  )));
                ,
                title: Text("$snapshot.data[index].description[0].toString().toUpperCase()"
                    "$snapshot.data[index].description.toString().substring(1)", maxLines: 1, style: TextStyle(
                    color: Colors.black87, fontSize: 17)
                ),
                subtitle: Text("new"),
                leading: Icon(Icons.radio_button_checked, color: Colors.red),
                trailing: Icon(Icons.arrow_right, color: Colors.black54,),
              ),
            );
          
        
      );

JSON

[

    "id": 7,
    "description": "Finishedddddd",
    "state": "done",
    "assigned_users": [
        
            "username": "hugo",
            "fullname": "Hugo Johnsson"
        
    ],
    "subtasks": []
,

    "id": 9,
    "description": "Newwww task for Huuugo",
    "state": "started",
    "assigned_users": [
        
            "username": "hugo",
            "fullname": "Hugo Johnsson"
        
    ],
    "subtasks": []
,

    "id": 11,
    "description": "Google presentation om IKEAS ekonomi",
    "state": "done",
    "assigned_users": [
        
            "username": "studentone",
            "fullname": "Student One"
        
    ],
    "subtasks": []
,

    "id": 15,
    "description": "entail",
    "state": "new",
    "assigned_users": [],
    "subtasks": [
        
            "id": 1,
            "description": "dasdasdasd"
        ,
        
            "id": 2,
            "description": "fsdfsdfsdf"
        
    ]
,

    "id": 17,
    "description": "gmmgmsgd",
    "state": "new",
    "assigned_users": [],
    "subtasks": []
,

    "id": 18,
    "description": "dasd",
    "state": "started",
    "assigned_users": [],
    "subtasks": []
,

    "id": 19,
    "description": "fsdfdsfsd",
    "state": "started",
    "assigned_users": [],
    "subtasks": []
,

    "id": 20,
    "description": "Werner",
    "state": "new",
    "assigned_users": [],
    "subtasks": []
,

    "id": 21,
    "description": "teadfsd",
    "state": "done",
    "assigned_users": [],
    "subtasks": []
,

    "id": 22,
    "description": "task",
    "state": "new",
    "assigned_users": [],
    "subtasks": []
,

    "id": 23,
    "description": "asdasd",
    "state": "started",
    "assigned_users": [],
    "subtasks": []
,

    "id": 24,
    "description": "asdasd",
    "state": "new",
    "assigned_users": [
        
            "username": "hugo",
            "fullname": "Hugo Johnsson"
        
    ],
    "subtasks": []

]

【问题讨论】:

【参考方案1】:

您应该在创建ListView 之前对数据进行排序。您可以使用基本的dart sort method。基本上你只需要实现compare function,它返回一个整数,返回值的符号指定项目顺序。

阅读此示例代码以更好地理解:

enum TaskState 
  newTask, done, started


class Task 
  Task(this.id, this.state);
  final int id;
  final TaskState state;

  String toString() 
    return "$id";
  


int compare(TaskState a, TaskState b) 
  if (a == b) return 0;
  switch(a) 
    case TaskState.newTask:
      return -1;
      break;
    case TaskState.started:
      if(b == TaskState.newTask) return 1;
      return -1;
      break;
    case TaskState.done:
      return 1;
      break;
  


void main() 
  List<Task> list = [
    Task(1, TaskState.done),
    Task(3, TaskState.newTask),
    Task(4, TaskState.started),
    Task(2, TaskState.done),
    Task(10, TaskState.newTask),
  ];
  list.sort((a, b) => compare(a.state, b.state));
  print(list);


在你的代码中实现应该是这样的

FutureBuilder<List<ProjectTask>>(
  future: someQuery(),
  builder: (BuildContext context, AsyncSnapshot<dynamic> snap) 
    snap.data.sort((a, b) => 
      if (a == b) return 0;
      switch(a) 
        case "new":
          return -1;
          break;
        case "started":
          if(b == "new") return 1;
          return -1;
          break;
        case "done":
          return 1;
          break;
      
    );
    return ListView.builder(
      ...
    )
  
)

【讨论】:

谢谢,你能解释一下我将如何以一种好的方式实现它吗? :) 其实很简单。我已经编辑了答案并添加了一个实现

以上是关于Flutter:根据类型对 ListView 项进行排序的主要内容,如果未能解决你的问题,请参考以下文章

Flutter中如何根据视口高度约束ListView

Flutter的布局

Flutter listview下拉刷新,上拉加载更多封装

Flutter ListView 项目根据 TextField 中添加的数字进行更改

Flutter项目中ListView的滚动不流畅

Flutter 在 ListView 返回类型 String 中显示嵌套 json 不是类型转换中类型“Map<String, dynamic>”的子类型