Flutter可选择卡片插件flutter_selectable_cards的使用

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

Flutter可选择卡片插件flutter_selectable_cards的使用

简介

flutter_selectable_cards 是一个用于创建可选择卡片的Flutter插件,支持单选和多选功能。你可以使用这个插件轻松地为你的应用创建带有自定义样式的卡片,适用于引导页、表单或其他任何需要选择功能的场景。

功能特性

  • 多选和单选支持:可以根据需求选择多选或单选模式。
  • 任意Widget作为可选择项:可以将任何Flutter Widget作为可选择项。
  • 自定义布局:支持Column、Row和Wrap三种布局方式。
  • 内置简单卡片组件:提供了简单的卡片组件、带复选框/单选按钮的卡片组件以及带图片的卡片组件,也可以使用自定义的Widget。
  • 与Flutter Widget无缝集成:易于与其他Flutter组件结合使用。

快速上手

1. 添加依赖

pubspec.yaml 文件中添加 flutter_selectable_cards 依赖:

dependencies:
  flutter_selectable_cards: ^0.0.2

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

2. 导入并使用插件

在Dart文件中导入 flutter_selectable_cards 包:

import 'package:flutter_selectable_cards/flutter_selectable_cards.dart';
3. 使用 SelectableCard 组件

以下是一个简单的示例,展示了如何使用 SelectableCards 组件:

SelectableCards(
  isMultipleSelection: false, // 设置为false表示单选,true表示多选
  layout: const LayoutWrap(), // 使用Wrap布局
  children: const [
    SimpleCard(
      index: 0,
      child: Padding(
        padding: EdgeInsets.all(8.0),
        child: Text('选择卡片1'),
      ),
    ),
    SimpleCard(
      index: 1,
      child: Padding(
        padding: EdgeInsets.all(8.0),
        child: Text('选择卡片2'),
      ),
    ),
  ],
  onSelected: (index) {
    print('主页面选择了卡片: $index');
  },
)
4. 使用不同的布局

你可以根据需要选择不同的布局方式:

  • Column布局

    SelectableCards(
      layout: const LayoutColumn(
        crossAxisAlignment: CrossAxisAlignment.start,
      ),
      children: [],
    )
    
  • Row布局

    SelectableCards(
      layout: const LayoutRow(),
      children: [],
    )
    
  • Wrap布局

    SelectableCards(
      layout: const LayoutWrap(
        crossAxisAlignment: WrapCrossAlignment.center,
      ),
      children: [],
    )
    

完整示例Demo

以下是一个完整的示例,展示了如何使用 flutter_selectable_cards 插件来创建一个多选项卡的应用程序,每个选项卡展示了不同类型的选择卡片。

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

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

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

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  List<int> selectedImageMulti = [];
  int selectedImageSingle = -1;
  int anyWidgetSelected = -1;
  int anyWidgetSelectedRow = -1;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: const Text('选择卡片示例'),
        ),
        body: DefaultTabController(
          length: 4,
          child: Column(
            children: <Widget>[
              const TabBar(
                isScrollable: true,
                tabs: [
                  Tab(text: '选择卡片'),
                  Tab(text: '单选卡片'),
                  Tab(text: '带图片的卡片'),
                  Tab(text: '任意Widget'),
                ],
              ),
              Expanded(
                child: TabBarView(
                  children: [
                    // 选择卡片示例
                    SingleChildScrollView(
                      child: Padding(
                        padding: const EdgeInsets.all(16.0),
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            const Text(
                              '多选卡片',
                              style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                            ),
                            const SizedBox(height: 10),
                            Center(
                              child: SelectableCards(
                                isMultipleSelection: true,
                                layout: const LayoutWrap(crossAxisAlignment: WrapCrossAlignment.center),
                                children: const [
                                  SimpleCard(
                                    index: 0,
                                    child: Padding(
                                      padding: EdgeInsets.all(8.0),
                                      child: Text('多选卡片1'),
                                    ),
                                  ),
                                  SimpleCard(
                                    index: 1,
                                    child: Padding(
                                      padding: EdgeInsets.all(8.0),
                                      child: Text('多选卡片2'),
                                    ),
                                  ),
                                ],
                                onSelected: (index) {
                                  print('选择了卡片: $index');
                                },
                              ),
                            ),
                            const SizedBox(height: 20),
                            const Text(
                              '单选卡片',
                              style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                            ),
                            const SizedBox(height: 10),
                            Center(
                              child: SelectableCards(
                                isMultipleSelection: false,
                                layout: const LayoutWrap(crossAxisAlignment: WrapCrossAlignment.center),
                                children: const [
                                  SimpleCard(
                                    index: 0,
                                    child: Padding(
                                      padding: EdgeInsets.all(8.0),
                                      child: Text('单选卡片1'),
                                    ),
                                  ),
                                  SimpleCard(
                                    index: 1,
                                    child: Padding(
                                      padding: EdgeInsets.all(8.0),
                                      child: Text('单选卡片2'),
                                    ),
                                  ),
                                ],
                                onSelected: (index) {
                                  print('选择了单选卡片: $index');
                                },
                              ),
                            ),
                            const SizedBox(height: 20),
                            const Text(
                              'Column布局示例',
                              style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                            ),
                            const SizedBox(height: 10),
                            const Text(
                              '多选Column布局',
                              style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                            ),
                            const SizedBox(height: 10),
                            LayoutColumnExample(isMultipleSelection: true),
                            const SizedBox(height: 20),
                            const Text(
                              '单选Column布局',
                              style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                            ),
                            const SizedBox(height: 10),
                            LayoutColumnExample(isMultipleSelection: false),
                            const SizedBox(height: 20),
                            const Text(
                              'Row布局示例',
                              style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                            ),
                            const SizedBox(height: 10),
                            const Text(
                              '多选Row布局',
                              style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                            ),
                            const SizedBox(height: 10),
                            LayoutRowExample(isMultipleSelection: true),
                            const SizedBox(height: 20),
                            const Text(
                              '单选Row布局',
                              style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                            ),
                            const SizedBox(height: 10),
                            LayoutRowExample(isMultipleSelection: false),
                            const SizedBox(height: 20),
                            const Text(
                              'Wrap布局示例',
                              style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                            ),
                            const SizedBox(height: 10),
                            const Text(
                              '多选Wrap布局',
                              style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                            ),
                            const SizedBox(height: 10),
                            LayoutWrapExample(isMultipleSelection: true),
                            const SizedBox(height: 20),
                            const Text(
                              '单选Wrap布局',
                              style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                            ),
                            const SizedBox(height: 10),
                            LayoutWrapExample(isMultipleSelection: false),
                            const SizedBox(height: 20),
                          ],
                        ),
                      ),
                    ),
                    // 单选卡片示例
                    SingleChildScrollView(
                      child: Padding(
                        padding: const EdgeInsets.all(16.0),
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            const Text(
                              '多选卡片(带单选按钮设计)',
                              style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                            ),
                            const SizedBox(height: 10),
                            Center(
                              child: SelectableCards(
                                isMultipleSelection: true,
                                layout: const LayoutWrap(crossAxisAlignment: WrapCrossAlignment.center),
                                children: const [
                                  RadioCard(
                                    index: 0,
                                    title: '单选卡片1',
                                    subtitle: '单选卡片1副标题',
                                  ),
                                  RadioCard(
                                    index: 1,
                                    title: '单选卡片2',
                                    subtitle: '单选卡片2副标题',
                                  ),
                                ],
                                onSelected: (index) {
                                  print('选择了卡片: $index');
                                },
                              ),
                            ),
                            const SizedBox(height: 20),
                            const Text(
                              '单选卡片(带单选按钮设计)',
                              style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                            ),
                            const SizedBox(height: 10),
                            Center(
                              child: SelectableCards(
                                isMultipleSelection: false,
                                layout: const LayoutWrap(crossAxisAlignment: WrapCrossAlignment.center),
                                children: const [
                                  RadioCard(
                                    index: 0,
                                    title: '单选卡片1',
                                    subtitle: '单选卡片1副标题',
                                  ),
                                  RadioCard(
                                    index: 1,
                                    title: '单选卡片2',
                                    subtitle: '单选卡片2副标题',
                                  ),
                                ],
                                onSelected: (index) {
                                  print('选择了单选卡片: $index');
                                },
                              ),
                            ),
                          ],
                        ),
                      ),
                    ),
                    // 带图片的卡片示例
                    SingleChildScrollView(
                      child: Padding(
                        padding: const EdgeInsets.all(16.0),
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            const Text(
                              '多选卡片(带图片)',
                              style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                            ),
                            const SizedBox(height: 10),
                            Center(
                              child: SelectableCards(
                                isMultipleSelection: true,
                                layout: const LayoutWrap(crossAxisAlignment: WrapCrossAlignment.center),
                                children: [
                                  CardWithImage(
                                    index: 0,
                                    imageUrl: 'https://st2.depositphotos.com/1011969/6070/i/450/depositphotos_60704945-stock-photo-number-1.jpg',
                                    text: '卡片1 ${selectedImageMulti.contains(0) ? '已选' : ''}',
                                  ),
                                  CardWithImage(
                                    index: 1,
                                    imageUrl: 'https://st2.depositphotos.com/1011969/6070/i/450/depositphotos_60704955-stock-photo-number-2.jpg',
                                    text: '卡片2 ${selectedImageMulti.contains(1) ? '已选' : ''}',
                                  ),
                                ],
                                onSelected: (index) {
                                  setState(() {
                                    selectedImageMulti = index;
                                  });
                                  print('选择了卡片: $index');
                                },
                              ),
                            ),
                            const SizedBox(height: 20),
                            const Text(
                              '单选卡片(带图片)',
                              style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                            ),
                            const SizedBox(height: 10),
                            Center(
                              child: SelectableCards(
                                isMultipleSelection: false,
                                layout: const LayoutWrap(crossAxisAlignment: WrapCrossAlignment.center),
                                children: [
                                  CardWithImage(
                                    index: 0,
                                    imageUrl: 'https://st2.depositphotos.com/1011969/6070/i/450/depositphotos_60704945-stock-photo-number-1.jpg',
                                    text: '单选卡片1 ${selectedImageSingle == 0 ? '已选' : ''}',
                                  ),
                                  CardWithImage(
                                    index: 1,
                                    imageUrl: 'https://st2.depositphotos.com/1011969/6070/i/450/depositphotos_60704955-stock-photo-number-2.jpg',
                                    text: '单选卡片2 ${selectedImageSingle == 1 ? '已选' : ''}',
                                  ),
                                ],
                                onSelected: (index) {
                                  setState(() {
                                    selectedImageSingle = index;
                                  });
                                  print('选择了单选卡片: $index');
                                },
                              ),
                            ),
                          ],
                        ),
                      ),
                    ),
                    // 任意Widget示例
                    SingleChildScrollView(
                      child: Padding(
                        padding: const EdgeInsets.all(16.0),
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            const Text(
                              '任意Widget',
                              style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                            ),
                            const SizedBox(height: 10),
                            const Text(
                              '任何Widget都可以用作SelectableCards的子项',
                              style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                            ),
                            const SizedBox(height: 10),
                            const Text(
                              '容器示例',
                              style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                            ),
                            const SizedBox(height: 10),
                            SelectableCards(
                              isMultipleSelection: false,
                              layout: const LayoutWrap(crossAxisAlignment: WrapCrossAlignment.center),
                              children: [
                                Container(
                                  width: 100,
                                  height: 100,
                                  color: Colors.red,
                                  child: Center(
                                    child: Text(
                                        '容器1 ${anyWidgetSelected == 0 ? '已选' : ''}'),
                                  ),
                                ),
                                Container(
                                  width: 100,
                                  height: 100,
                                  color: Colors.blue,
                                  child: Center(
                                    child: Text(
                                        '容器2 ${anyWidgetSelected == 1 ? '已选' : ''}'),
                                  ),
                                ),
                              ],
                              onSelected: (index) {
                                setState(() {
                                  anyWidgetSelected = index;
                                });
                                print('选择了卡片: $index');
                              },
                            ),
                            const SizedBox(height: 20),
                            const Text(
                              'Text in LayoutRow 示例',
                              style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                            ),
                            const SizedBox(height: 10),
                            SelectableCards(
                              isMultipleSelection: false,
                              layout: const LayoutRow(
                                mainAxisAlignment: MainAxisAlignment.center,
                              ),
                              children: [
                                Container(
                                  padding: const EdgeInsets.all(8.0),
                                  child: Center(
                                    child: Text(
                                      '容器1 ${anyWidgetSelectedRow == 0 ? '已选' : ''}',
                                      style: const TextStyle(
                                        fontSize: 16,
                                        fontWeight: FontWeight.bold,
                                      ),
                                    ),
                                  ),
                                ),
                                Container(
                                  padding: const EdgeInsets.all(8.0),
                                  child: Center(
                                    child: Text(
                                      '容器2 ${anyWidgetSelectedRow == 1 ? '已选' : ''}',
                                      style: const TextStyle(
                                        fontSize: 16,
                                        fontWeight: FontWeight.bold,
                                      ),
                                    ),
                                  ),
                                ),
                              ],
                              onSelected: (index) {
                                setState(() {
                                  anyWidgetSelectedRow = index;
                                });
                                print('选择了卡片: $index');
                              },
                            ),
                            const SizedBox(height: 20),
                            const Text(
                              '任何Widget都可以用作SelectableCards的子项,并且可以用于多选或单选',
                            ),
                          ],
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class LayoutColumnExample extends StatelessWidget {
  final bool isMultipleSelection;

  const LayoutColumnExample({required this.isMultipleSelection});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return SelectableCards(
      isMultipleSelection: isMultipleSelection,
      layout: const LayoutColumn(
        mainAxisAlignment: MainAxisAlignment.center,
      ),
      children: const [
        SimpleCard(
          index: 0,
          child: Padding(
            padding: EdgeInsets.all(8.0),
            child: Text('Column卡片1'),
          ),
        ),
        SimpleCard(
          index: 1,
          child: Padding(
            padding: EdgeInsets.all(8.0),
            child: Text('Column卡片2'),
          ),
        ),
      ],
      onSelected: (index) {
        print('LayoutColumnExample选择了卡片: $index');
      },
    );
  }
}

class LayoutRowExample extends StatelessWidget {
  final bool isMultipleSelection;

  const LayoutRowExample({required this.isMultipleSelection});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return SelectableCards(
      isMultipleSelection: isMultipleSelection,
      layout: const LayoutRow(
        mainAxisAlignment: MainAxisAlignment.center,
      ),
      children: const [
        SimpleCard(
          index: 0,
          child: Padding(
            padding: EdgeInsets.all(8.0),
            child: Text('Row卡片1'),
          ),
        ),
        SimpleCard(
          index: 1,
          child: Padding(
            padding: EdgeInsets.all(8.0),
            child: Text('Row卡片2'),
          ),
        ),
      ],
      onSelected: (index) {
        print('LayoutRowExample选择了卡片: $index');
      },
    );
  }
}

class LayoutWrapExample extends StatelessWidget {
  final bool isMultipleSelection;

  const LayoutWrapExample({required this.isMultipleSelection});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return SelectableCards(
      isMultipleSelection: isMultipleSelection,
      layout: const LayoutWrap(
        crossAxisAlignment: WrapCrossAlignment.center,
      ),
      children: const [
        SimpleCard(
          index: 0,
          child: Padding(
            padding: EdgeInsets.all(8.0),
            child: Text('Wrap卡片1'),
          ),
        ),
        SimpleCard(
          index: 1,
          child: Padding(
            padding: EdgeInsets.all(8.0),
            child: Text('Wrap卡片2'),
          ),
        ),
      ],
      onSelected: (index) {
        print('LayoutWrapExample选择了卡片: $index');
      },
    );
  }
}

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

1 回复

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


当然,以下是如何在Flutter项目中使用flutter_selectable_cards插件的一个简单示例。这个插件允许用户从一个卡片集合中选择一个或多个卡片。

首先,确保你已经在pubspec.yaml文件中添加了flutter_selectable_cards依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_selectable_cards: ^最新版本号  # 替换为实际最新版本号

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

接下来,你可以在你的Flutter应用中使用这个插件。以下是一个简单的示例代码,展示如何创建一个可选择卡片的界面:

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

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

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

class SelectableCardsScreen extends StatefulWidget {
  @override
  _SelectableCardsScreenState createState() => _SelectableCardsScreenState();
}

class _SelectableCardsScreenState extends State<SelectableCardsScreen> {
  List<String> selectedCards = [];

  @override
  Widget build(BuildContext context) {
    List<CardModel> cards = [
      CardModel(
        title: 'Card 1',
        description: 'This is the first card.',
        image: NetworkImage('https://via.placeholder.com/150'),
      ),
      CardModel(
        title: 'Card 2',
        description: 'This is the second card.',
        image: NetworkImage('https://via.placeholder.com/150'),
      ),
      CardModel(
        title: 'Card 3',
        description: 'This is the third card.',
        image: NetworkImage('https://via.placeholder.com/150'),
      ),
    ];

    return Scaffold(
      appBar: AppBar(
        title: Text('Selectable Cards Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: SelectableCards(
          cards: cards,
          onSelectedCardChanged: (List<int> selectedIndexes) {
            setState(() {
              selectedCards = selectedIndexes
                  .map((index) => cards[index].title)
                  .toList();
            });
          },
        ),
      ),
      bottomNavigationBar: BottomAppBar(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Text('Selected Cards: ${selectedCards.join(", ")}'),
          ],
        ),
      ),
    );
  }
}

class CardModel {
  String title;
  String description;
  ImageProvider image;

  CardModel({required this.title, required this.description, required this.image});
}

在这个示例中,我们定义了一个CardModel类来表示卡片的数据,包括标题、描述和图片。然后在SelectableCardsScreen中,我们创建了一个卡片列表,并使用SelectableCards小部件来显示这些卡片。

当用户选择卡片时,onSelectedCardChanged回调会被触发,我们在这个回调中更新selectedCards列表,并在底部导航栏中显示选中的卡片标题。

请注意,由于flutter_selectable_cards插件的具体API可能会随着版本更新而变化,因此请务必参考最新的官方文档和示例代码来确保代码的正确性。如果插件的API有所变化,可能需要调整上述代码以匹配新的API。

回到顶部