Flutter级联布局插件cascade_widget的使用

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

Flutter级联布局插件cascade_widget的使用

概述

本文档将介绍如何在Flutter项目中使用cascade_widget插件来实现级联选择和单选多选功能。

预览

使用方法

级联选择组件 CascadeWidget

CascadeWidget(
  list: testList, // 数据源
  selectedCallBack: (selectedList) { // 选择回调
    for (final e in selectedList) {
      debugPrint('name:${e.name}, id:${e.id}');
    }
  },
  fieldDecoration: FieldDecoration( // 输入框样式
    hintText: '请选择',
    hintStyle: const TextStyle(color: Colors.black45),
    border: OutlineInputBorder(
      borderRadius: BorderRadius.circular(8),
      borderSide: const BorderSide(color: Colors.grey),
    ),
    focusedBorder: OutlineInputBorder(
      borderRadius: BorderRadius.circular(8),
      borderSide: const BorderSide(
        color: Colors.black87,
      ),
    ),
  ),
  chipDecoration: const ChipDecoration( // 芯片样式
    backgroundColor: Colors.blueAccent,
    runSpacing: 2,
    spacing: 10,
    labelStyle: TextStyle(
      color: Colors.white,
    ),
    deleteIcon: Icon(Icons.clear_outlined, color: Colors.white, size: 16),
  ),
)

多选组件 MultipleSelectWidget

MultipleSelectWidget(
  list: mulList, // 数据源
  selectedCallBack: (selectedList) { // 选择回调
    for (final e in selectedList) {
      debugPrint('name:${e.name}, id:${e.id}');
    }
  },
  fieldDecoration: FieldDecoration( // 输入框样式
    hintText: '多选',
    hintStyle: const TextStyle(
      color: Colors.black45,
      fontSize: 14,
    ),
    padding: const EdgeInsets.symmetric(
      horizontal: 12,
    ),
    border: OutlineInputBorder(
      borderRadius: BorderRadius.circular(4),
      borderSide: const BorderSide(color: Colors.grey),
    ),
    focusedBorder: OutlineInputBorder(
      borderRadius: BorderRadius.circular(4),
      borderSide: const BorderSide(
        color: Colors.black87,
      ),
    ),
    clearIcon: const Icon(
      Icons.clear,
      size: 14,
    ),
    style: const TextStyle(
      fontSize: 14,
    ),
  ),
  chipDecoration: const ChipDecoration( // 芯片样式
    backgroundColor: Colors.black12,
    padding: EdgeInsets.symmetric(
      horizontal: 6,
      vertical: 2,
    ),
    runSpacing: 0,
    spacing: 5,
    labelStyle: TextStyle(
      color: Colors.black87,
      fontSize: 12,
    ),
    borderRadius: BorderRadius.all(Radius.circular(4)),
    deleteIcon: Icon(
      Icons.clear_outlined,
      color: Colors.black54,
      size: 15,
    ),
  ),
  popupDecoration: const PopupDecoration( // 弹出框样式
    isShowFullPathFromSearch: false,
    popupHeight: 300,
  ),
)

完整示例代码

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

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

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

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

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final cascadeController = CascadeWidgetController();
  final testList = [
    DropDownMenuModel(
      id: '1',
      name: '一级 1',
      children: [
        DropDownMenuModel(
          id: '11',
          name: '二级 1-1',
          children: [
            DropDownMenuModel(id: '111', name: '三级 1-1-1', children: []),
            DropDownMenuModel(id: '112', name: '三级 1-1-2', children: []),
            DropDownMenuModel(id: '113', name: '三级 1-1-3', children: []),
          ],
        ),
        DropDownMenuModel(id: '12', name: '二级 1-2', children: [
          DropDownMenuModel(id: '121', name: '三级 1-2-1', children: []),
        ]),
      ],
    ),
    DropDownMenuModel(
      id: '2',
      name: '一级 2',
      children: [
        DropDownMenuModel(id: '21', name: '二级 2-1', children: [
          DropDownMenuModel(id: '211', name: '三级 2-1-1', children: []),
        ]),
        DropDownMenuModel(id: '22', name: '二级 2-2', children: [
          DropDownMenuModel(id: '221', name: '三级 2-2-1', children: []),
        ]),
        DropDownMenuModel(id: '23', name: '二级 2-3', children: [
          DropDownMenuModel(id: '231', name: '三级 2-3-1', children: []),
        ]),
      ],
    ),
    DropDownMenuModel(
      id: '3',
      name: '一级 3',
      children: [
        DropDownMenuModel(id: '31', name: '二级 3-1', children: [
          DropDownMenuModel(id: '311', name: '三级 3-1-1', children: []),
        ]),
        DropDownMenuModel(id: '32', name: '二级 3-2', children: [
          DropDownMenuModel(id: '221', name: '三级 3-2-1', children: []),
        ]),
        DropDownMenuModel(id: '3-3', name: '二级 3-3', children: [
          DropDownMenuModel(id: '331', name: '三级 3-3-1', children: []),
        ]),
      ],
    ),
  ];

  final mulList = [
    DropDownMenuModel(id: '1', name: '选项 1', children: []),
    DropDownMenuModel(id: '2', name: '选项 2', children: []),
    DropDownMenuModel(id: '3', name: '选项 3', children: []),
    DropDownMenuModel(id: '4', name: '选项 4', children: []),
    DropDownMenuModel(id: '5', name: '选项 5', children: []),
  ];

  [@override](/user/override)
  Widget build(BuildContext context) {
    debugPrint('controller: ${cascadeController.hashCode}');
    return Scaffold(
      body: KeyboardListener(
        focusNode: FocusNode(),
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            children: [
              const SizedBox(height: 100),
              SizedBox(
                width: 410,
                child: CascadeWidget(
                  list: testList,
                  controller: cascadeController,
                  selectedCallBack: (selectedList) {
                    debugPrint('selected items:');
                    for (final e in selectedList) {
                      debugPrint('name:${e.name}, id:${e.id}');
                    }
                  },
                  fieldDecoration: FieldDecoration(
                    hintText: '请选择',
                    hintStyle: const TextStyle(color: Colors.black45),
                    border: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(4),
                      borderSide: const BorderSide(color: Colors.grey),
                    ),
                    focusedBorder: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(4),
                      borderSide: const BorderSide(
                        color: Colors.black87,
                      ),
                    ),
                    isRow: true,
                  ),
                  chipDecoration: const ChipDecoration(
                    backgroundColor: Colors.blueAccent,
                    runSpacing: 2,
                    spacing: 10,
                    labelStyle: TextStyle(
                      color: Colors.white,
                    ),
                    borderRadius: BorderRadius.all(Radius.circular(4)),
                    deleteIcon: Icon(Icons.clear_outlined, color: Colors.white, size: 16),
                  ),
                ),
              ),
              const SizedBox(height: 8),
              ElevatedButton(
                onPressed: () {
                  cascadeController.cancelAllSelected();
                  setState(() {});
                },
                child: const Text('取消所有选择'),
              ),
              const SizedBox(height: 50),
              SizedBox(
                width: 410,
                child: MultipleSelectWidget(
                  list: mulList,
                  selectedCallBack: (selectedList) {
                    for (final e in selectedList) {
                      debugPrint('name:${e.name}, id:${e.id}');
                    }
                  },
                  fieldDecoration: FieldDecoration(
                    hintText: '多选',
                    hintStyle: const TextStyle(
                      color: Colors.black45,
                      fontSize: 14,
                    ),
                    padding: const EdgeInsets.symmetric(horizontal: 12),
                    border: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(4),
                      borderSide: const BorderSide(color: Colors.grey),
                    ),
                    focusedBorder: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(4),
                      borderSide: const BorderSide(
                        color: Colors.black87,
                      ),
                    ),
                    clearIcon: const Icon(
                      Icons.clear,
                      size: 14,
                    ),
                    style: const TextStyle(
                      fontSize: 14,
                    ),
                  ),
                  chipDecoration: const ChipDecoration(
                    backgroundColor: Colors.black12,
                    padding: EdgeInsets.symmetric(horizontal: 6, vertical: 2),
                    runSpacing: 0,
                    spacing: 5,
                    labelStyle: TextStyle(
                      color: Colors.black87,
                      fontSize: 12,
                    ),
                    borderRadius: BorderRadius.all(Radius.circular(4)),
                    deleteIcon: Icon(
                      Icons.clear_outlined,
                      color: Colors.black54,
                      size: 15,
                    ),
                  ),
                  popupDecoration: const PopupDecoration(
                    isShowFullPathFromSearch: false,
                    popupHeight: 300,
                    isSingleChoice: true,
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

更多关于Flutter级联布局插件cascade_widget的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter级联布局插件cascade_widget的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter中使用cascade_widget插件的示例代码。cascade_widget是一个用于创建级联布局(Cascading Layout)的插件,它允许你以一种优雅的方式堆叠子组件,每个子组件相对于前一个组件有一定的偏移。

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

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

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

以下是一个简单的示例,展示如何使用CascadeWidget来创建一个级联布局:

import 'package:flutter/material.dart';
import 'package:cascade_widget/cascade_widget.dart'; // 导入cascade_widget

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Cascade Widget Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Cascade Widget Demo'),
        ),
        body: Center(
          child: CascadeWidget(
            alignment: Alignment.center, // 子组件的对齐方式
            crossAxisAlignment: CrossAxisAlignment.center, // 交叉轴对齐方式
            mainAxisAlignment: MainAxisAlignment.start, // 主轴对齐方式
            children: <Widget>[
              Container(
                width: 100,
                height: 100,
                color: Colors.red,
                child: Center(child: Text('1')),
              ),
              Container(
                width: 100,
                height: 100,
                color: Colors.green,
                child: Center(child: Text('2')),
              ),
              Container(
                width: 100,
                height: 100,
                color: Colors.blue,
                child: Center(child: Text('3')),
              ),
            ],
            cascadeOffset: Offset(20, 20), // 每个子组件相对于前一个组件的偏移量
          ),
        ),
      ),
    );
  }
}

在这个示例中,我们创建了一个简单的Flutter应用,它使用CascadeWidget来堆叠三个不同颜色的容器。每个容器相对于前一个容器有一个20像素的水平和垂直偏移。

  • alignment属性决定了子组件在CascadeWidget中的对齐方式。
  • crossAxisAlignmentmainAxisAlignment属性分别决定了交叉轴和主轴上的对齐方式。
  • children是一个包含所有子组件的列表。
  • cascadeOffset属性定义了每个子组件相对于前一个组件的偏移量。

你可以根据需要调整这些属性来实现不同的级联布局效果。

回到顶部