You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从SQFLITE创建的List中正确获取单个字段值?

问题说明

开发基于Flutter的本地便签应用,使用sqflite做数据持久化,支持用户输入标题(title)、描述(description)保存,需求为点击保存后,在Card组件构成的列表中支持三种展示规则:仅展示标题、仅展示描述、同时展示标题与描述。

在buildNotes方法中编写child: Text(notes[NoteFields.description])读取描述内容时,无法正常获取数据,抛出如下错误:

type 'String' is not a subtype of type 'int' of 'index'

原实现代码如下:

class NotesPage extends StatefulWidget {
  @override
  _NotesPageState createState() => _NotesPageState();
}

class _NotesPageState extends State<NotesPage> {
  late List<Note> notes;
  bool isLoading = false;

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

  @override
  void dispose() {
    NotesDatabase.instance.close();
    super.dispose();
  }

  Future refreshNotes() async {
    setState(() => isLoading = true);
    this.notes = await NotesDatabase.instance.readAllNotes();
    setState(() => isLoading = false);
  }

  @override
  Widget build(BuildContext context) => Scaffold(
    appBar: AppBar(
      title: Text('Notes', style: TextStyle(fontSize: 24)),
      actions: [Icon(Icons.search), SizedBox(width: 12)],
    ),
    body: Center(
      child: isLoading
          ? CircularProgressIndicator()
          : notes.isEmpty
          ? Text('No Notes', style: TextStyle(color: Colors.white, fontSize: 24))
          : buildNotes(notes),
    ),
    floatingActionButton: FloatingActionButton(
      backgroundColor: Colors.black,
      child: Icon(Icons.add),
      onPressed: () async {
        await Navigator.of(context).push(
          MaterialPageRoute(builder: (context) => AddEditNotePage()),
        );
        refreshNotes();
      },
    ),
  );

  Widget buildNotes(notes) =>
        Card(
          child: Text(notes[NoteFields.description]),
        );
}
错误原因
  1. 传入buildNotes的notes是List<Note>类型的对象数组,List仅支持int类型的下标作为索引获取对应位置的元素,代码中传入NoteFields.description(String类型的字段名)作为索引,直接触发类型不匹配错误。
  2. 代码混淆了List和Map的取值逻辑:如果是从sqflite直接查出的List<Map<String, dynamic>>结构,可以用字符串键取字段值,但查询结果已经被转为List<Note>实体类列表,不能再用Map的键值语法取值。
  3. 现有buildNotes仅返回单个Card组件,没有遍历整个便签列表,无法渲染多条数据。
修复方案
  1. 先确认Note实体类的序列化/反序列化逻辑正常,保证从数据库查出的Map数据能正确转为Note对象:
// 数据库字段常量类
class NoteFields {
  static const String id = '_id';
  static const String title = 'title';
  static const String description = 'description';
  static final List<String> values = [id, title, description];
}

// Note实体类
class Note {
  final int? id;
  final String title;
  final String description;

  Note({
    this.id,
    required this.title,
    required this.description,
  });

  // 数据库查询结果Map转Note对象
  factory Note.fromMap(Map<String, dynamic> map) {
    return Note(
      id: map[NoteFields.id] as int?,
      title: map[NoteFields.title] as String,
      description: map[NoteFields.description] as String,
    );
  }
}
  1. 重写buildNotes方法,用ListView.builder遍历列表渲染所有便签,通过int下标取到单个Note对象后,直接访问对象属性取值,同时增加展示模式控制逻辑,支持三种展示规则:
// 展示模式枚举
enum NoteDisplayMode {
  onlyTitle,
  onlyDescription,
  showAll,
}

// 在_NotesPageState中增加当前展示模式的状态变量
NoteDisplayMode displayMode = NoteDisplayMode.showAll;

Widget buildNotes(List<Note> notes) {
  return ListView.builder(
    padding: EdgeInsets.all(12),
    itemCount: notes.length,
    itemBuilder: (context, index) {
      // 用int下标取当前位置的单个Note对象
      final Note currentNote = notes[index];
      Widget cardContent;

      // 根据当前展示模式拼接内容
      switch (displayMode) {
        case NoteDisplayMode.onlyTitle:
          cardContent = Text(
            currentNote.title,
            style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
          );
          break;
        case NoteDisplayMode.onlyDescription:
          cardContent = Text(currentNote.description);
          break;
        case NoteDisplayMode.showAll:
          cardContent = Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisSize: MainAxisSize.min,
            children: [
              Text(
                currentNote.title,
                style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
              ),
              SizedBox(height: 6),
              Text(currentNote.description),
            ],
          );
          break;
      }

      return Card(
        margin: EdgeInsets.symmetric(vertical: 6),
        child: Padding(
          padding: EdgeInsets.all(12),
          child: cardContent,
        ),
      );
    },
  );
}
  1. 如果需要切换展示模式,只需修改displayMode状态变量并触发setState即可。

内容的提问来源于stack exchange,提问作者Ashish Magar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 16:45:45