Flutter嵌套选择列表插件nested_choice_list的使用

发布于 1周前 作者 wuwangju 来自 Flutter

Flutter嵌套选择列表插件nested_choice_list的使用

安装

首先,你需要在 pubspec.yaml 文件中添加依赖项:

dependencies:
  nested_choice_list: latest_version

然后运行 flutter pub get 来安装包。

示例代码

下面是一个完整的示例代码,展示了如何使用 NestedChoiceList 插件来创建一个嵌套的选择列表界面。这个示例包括了单选模式和多选模式,并且提供了回调函数来处理用户的选择操作。

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'NestedChoiceList Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const HomePage(),
    );
  }
}

// Home page
class HomePage extends StatefulWidget {
  const HomePage({super.key});

  [@override](/user/override)
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  bool showSelectedItems = true;
  bool enableSelectAll = true;
  bool showNavigationPath = false;
  bool enableMultiSelect = false;
  bool enableSearch = false;

  NestedChoiceEntity? selectedItem;
  List<NestedChoiceEntity>? selectedItems;

  final items = const [
    NestedChoiceEntity(
      value: 'value1',
      label: 'label1 level1',
      children: [
        NestedChoiceEntity(value: 'value2', label: 'label2 level 2'),
        NestedChoiceEntity(value: 'value3', label: 'label3 level 2'),
        NestedChoiceEntity(
          value: 'value4',
          label: 'label4 level 2',
          children: [
            NestedChoiceEntity(value: 'value2', label: 'label2 level 3'),
            NestedChoiceEntity(value: 'value3', label: 'label3 level 3'),
            NestedChoiceEntity(
              value: 'value4',
              label: 'label4 level 3',
              children: [
                NestedChoiceEntity(value: 'value2', label: 'label2 level 4'),
                NestedChoiceEntity(value: 'value3', label: 'label3 level 4'),
                NestedChoiceEntity(value: 'value4', label: 'label4 level 4'),
              ],
            ),
          ],
        ),
      ],
    ),
    NestedChoiceEntity(
      value: 'value2',
      label: 'label2 level1',
      children: [
        NestedChoiceEntity(value: 'value2', label: 'label2 level 2'),
        NestedChoiceEntity(value: 'value3', label: 'label3 level 2'),
        NestedChoiceEntity(
          value: 'value4',
          label: 'label4 level 2',
          children: [
            NestedChoiceEntity(value: 'value2', label: 'label2 level 3'),
            NestedChoiceEntity(value: 'value3', label: 'label3 level 3'),
            NestedChoiceEntity(value: 'value4', label: 'label4 level 3'),
          ],
        ),
      ],
    ),
    NestedChoiceEntity(
      value: 'value3',
      label: 'label3 level1',
      children: [
        NestedChoiceEntity(value: 'value2', label: 'label2 level 2'),
        NestedChoiceEntity(value: 'value3', label: 'label3 level 2'),
        NestedChoiceEntity(value: 'value4', label: 'label4 level 2'),
      ],
    ),
    NestedChoiceEntity(value: 'value4', label: 'label4 level1'),
  ];

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('NestedChoiceList'),
      ),
      body: SingleChildScrollView(
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Column(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              CheckboxListTile.adaptive(
                title: const Text('ShowNavigationPath'),
                value: showNavigationPath,
                onChanged: (newValue) {
                  setState(() {
                    showNavigationPath = newValue ?? false;
                  });
                },
              ),
              const Divider(),
              CheckboxListTile.adaptive(
                title: const Text('EnableMultiSelect'),
                value: enableMultiSelect,
                onChanged: (newValue) {
                  setState(() {
                    enableMultiSelect = newValue ?? false;
                  });
                },
              ),
              const Divider(),
              CheckboxListTile.adaptive(
                title: const Text('EnableSelectAll'),
                value: enableSelectAll,
                onChanged: (newValue) {
                  setState(() {
                    enableSelectAll = newValue ?? false;
                  });
                },
              ),
              const Divider(),
              CheckboxListTile.adaptive(
                title: const Text('ShowSelectedItems'),
                value: showSelectedItems,
                onChanged: (newValue) {
                  setState(() {
                    showSelectedItems = newValue ?? false;
                  });
                },
              ),
              const Divider(),
              CheckboxListTile.adaptive(
                title: const Text('EnableSearch'),
                value: enableSearch,
                onChanged: (newValue) {
                  setState(() {
                    enableSearch = newValue ?? false;
                  });
                },
              ),
              const Divider(),
              ElevatedButton(
                onPressed: () async {
                  final result = await Navigator.of(context).push(
                    MaterialPageRoute(
                      builder: (_) =&gt; DemoOf NestedChoiceList(
                        items: items,
                        showSelectedItems: showSelectedItems,
                        enableSelectAll: enableSelectAll,
                        showNavigationPath: showNavigationPath,
                        enableMultiSelect: enableMultiSelect,
                        enableSearch: enableSearch,
                      ),
                    ),
                  );
                  if (result is NestedChoiceEntity) {
                    setState(() {
                      selectedItem = result;
                      selectedItems = null;
                    });
                  } else if (result is List&lt;NestedChoiceEntity&gt;) {
                    setState(() {
                      selectedItem = null;
                      selectedItems = result;
                    });
                  }
                },
                child: const Text(
                  'Show Demo',
                  style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                ),
              ),
              const Divider(),
              const Text(
                '⇩ Result ⇩',
                style: TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                  color: Colors.black,
                ),
              ),
              const SizedBox(
                height: 20,
              ),
              if (selectedItem != null)
                Text(
                  'onTapItem: ${selectedItem!.label}',
                  style: const TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.bold,
                    color: Colors.orange,
                  ),
                ),
              if (selectedItems != null)
                Text(
                  'onSelectionChange: $selectedItems',
                  style: const TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.bold,
                    color: Colors.orange,
                  ),
                )
            ],
          ),
        ),
      ),
    );
  }
}

class Demo of NestedChoiceList extends StatelessWidget {
  const Demo of NestedChoiceList({
    required this.items,
    super.key,
    required this.showSelectedItems,
    required this.enableSelectAll,
    required this.showNavigationPath,
    required this.enableMultiSelect,
    required this.enableSearch,
  });

  final List&lt;NestedChoiceEntity&gt; items;
  final bool showSelectedItems;
  final bool enableSelectAll;
  final bool showNavigationPath;
  final bool enableMultiSelect;
  final bool enableSearch;

  [@override](/user/override)
  Widget build(BuildContext context) {
    List&lt;NestedChoiceEntity&gt; selectedItems = [];
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      body: NestedChoiceList(
        items: items,
        showSelectedItems: showSelectedItems,
        enableSelectAll: enableSelectAll,
        showNavigationPath: showNavigationPath,
        enableMultiSelect: enableMultiSelect,
        enableSearch: enableSearch,
        style: const NestedListStyle(),
        onTapItem: (item) {
          debugPrint('onTapItem -&gt; $item');
          Navigator.of(context).pop(item);
        },
        onSelectionChange: (items) {
          debugPrint('onSelectionChange -&gt; $items');
          selectedItems = items;
        },
        onNavigationChange: (pageIndex) {
          debugPrint('onNavigationChange -&gt; pageIndex: $pageIndex');
        },
      ),
      bottomNavigationBar: enableMultiSelect
          ? SafeArea(
              child: ElevatedButton(
                onPressed: () {
                  Navigator.of(context).pop(selectedItems);
                },
                child: const Text('Confirm selected items'),
              ),
            )
          : null,
    );
  }
}

更多关于Flutter嵌套选择列表插件nested_choice_list的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter嵌套选择列表插件nested_choice_list的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter中使用nested_choice_list插件来实现嵌套选择列表的示例代码。请注意,由于nested_choice_list并非一个官方或广泛认可的Flutter插件(在撰写此回复时),我假设这是一个自定义或第三方插件,并且以下示例代码是基于一般嵌套列表选择逻辑的假设实现。如果你使用的插件有特定的API或方法,请参考其官方文档进行调整。

首先,确保你已经在pubspec.yaml文件中添加了nested_choice_list(或相应的插件名称,如果它存在的话):

dependencies:
  flutter:
    sdk: flutter
  nested_choice_list: ^x.y.z  # 替换为实际的版本号

然后,运行flutter pub get来安装依赖。

接下来,是一个示例代码,展示如何使用一个假设的NestedChoiceList组件来实现嵌套选择列表:

import 'package:flutter/material.dart';
import 'package:nested_choice_list/nested_choice_list.dart'; // 假设的插件导入

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Nested Choice List Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: NestedChoiceListScreen(),
    );
  }
}

class NestedChoiceListScreen extends StatefulWidget {
  @override
  _NestedChoiceListScreenState createState() => _NestedChoiceListScreenState();
}

class _NestedChoiceListScreenState extends State<NestedChoiceListScreen> {
  // 假设的数据结构
  final List<ChoiceItem> choices = [
    ChoiceItem(
      id: '1',
      title: 'Category 1',
      children: [
        ChoiceItem(id: '1-1', title: 'Subcategory 1-1'),
        ChoiceItem(id: '1-2', title: 'Subcategory 1-2'),
      ],
    ),
    ChoiceItem(
      id: '2',
      title: 'Category 2',
      children: [
        ChoiceItem(id: '2-1', title: 'Subcategory 2-1'),
        ChoiceItem(
          id: '2-2',
          title: 'Subcategory 2-2',
          children: [
            ChoiceItem(id: '2-2-1', title: 'Sub-subcategory 2-2-1'),
          ],
        ),
      ],
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Nested Choice List Demo'),
      ),
      body: NestedChoiceList(
        choices: choices,
        onSelectionChanged: (selectedItems) {
          // 处理选择变更
          print('Selected items: $selectedItems');
        },
      ),
    );
  }
}

// 假设的ChoiceItem类,用于表示列表项
class ChoiceItem {
  final String id;
  final String title;
  final List<ChoiceItem>? children;

  ChoiceItem({required this.id, required this.title, this.children});
}

// 假设的NestedChoiceList组件(实际上你应该使用插件提供的组件)
class NestedChoiceList extends StatefulWidget {
  final List<ChoiceItem> choices;
  final ValueChanged<List<String>> onSelectionChanged;

  NestedChoiceList({required this.choices, required this.onSelectionChanged});

  @override
  _NestedChoiceListState createState() => _NestedChoiceListState();
}

class _NestedChoiceListState extends State<NestedChoiceList> {
  // 省略了实际的实现细节,因为这取决于插件的具体API
  // 以下是一个简化的逻辑示例,用于说明如何处理选择

  List<String> _selectedItems = [];

  void _handleItemTap(ChoiceItem item) {
    setState(() {
      if (_selectedItems.contains(item.id)) {
        _selectedItems.remove(item.id);
      } else {
        _selectedItems.add(item.id);
      }
      widget.onSelectionChanged(_selectedItems);
    });
  }

  @override
  Widget build(BuildContext context) {
    // 实际的构建逻辑取决于插件的API,这里仅展示一个概念性的实现
    return ListView.builder(
      itemCount: widget.choices.length,
      itemBuilder: (context, index) {
        final item = widget.choices[index];
        return ListTile(
          title: Text(item.title),
          trailing: Checkbox(
            value: _selectedItems.contains(item.id),
            onChanged: (value) {
              _handleItemTap(item);
              // 注意:对于真正的嵌套列表,这里需要递归处理子项
            },
          ),
          onTap: () => _handleItemTap(item), // 处理点击事件
        );
        // 注意:这里省略了子项的处理逻辑,真正的实现需要递归渲染子项
      },
    );
  }
}

注意:上述代码是一个简化的示例,用于说明概念。真正的nested_choice_list插件(如果存在)可能会有不同的API和组件使用方式。你应该查阅该插件的官方文档来了解如何正确使用它。如果插件不存在,你可能需要自己实现一个嵌套选择列表组件,或者寻找一个合适的第三方库。

回到顶部