Flutter可拖拽底部面板插件draggable_sheet的使用

Flutter可拖拽底部面板插件draggable_sheet的使用

Draggable Sheet 是一个 Flutter 包,使开发者能够在应用中实现一个可自定义、交互性强的底部面板,并且该面板的高度可以动态调整,展示优雅的项目。它通过提供更复杂的控制来扩展了典型的可拖拽面板功能,提供了更丰富的用户交互体验。

特性

  • 动态高度调整:根据内容或预设限制调整底部面板的高度。
  • 项目交互:点击项目进行交互或选择,面板会根据上下文做出响应。
  • 自定义动画和捕捉:平滑的动画效果和在不同高度处的可选捕捉点。
  • 响应式设计:适应不同的屏幕尺寸和方向。

安装

要在你的 Flutter 项目中添加 Draggable Sheet,编辑你的 pubspec.yaml 文件:

dependencies:
  draggable_sheet: ^1.0.1+3

然后,在你的 Dart 代码中导入包:

import 'package:draggable_sheet/draggable_sheet.dart';

使用

此包提供了一个 DraggableSheet 小部件,可以包含在你的 Flutter 应用程序中。以下是一个简单的示例,说明如何将它集成到你的应用中:

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: DraggableSheet(
          minHeight: 0.1,
          maxHeight: 0.8,
          itemHeight: 50,
          list: [
            (Widget: Text('Item 1'), index: 0),
            (Widget: Text('Item 2'), index: 1),
          ],
          didSelectItem: (index) {
            print('Selected item $index');
          },
        ),
      ),
    );
  }
}

配置

  • minHeight: 可拖拽面板能占据的屏幕高度的最小比例。
  • maxHeight: 可拖拽面板能占据的屏幕高度的最大比例。
  • itemHeight: 可拖拽面板中每个项目的高度。
  • list: 一个包含元组的列表,每个元组包含一个 Widget 和其对应的索引。
  • didSelectItem: 当项目被选中时调用的回调函数。

示例代码

以下是完整的示例代码,展示了如何使用 Draggable Sheet 插件:

import 'dart:math';

import 'package:draggable_sheet/draggable_sheet.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.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> {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: HomePage(),
    );
  }
}

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

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

class _HomePageState extends State<HomePage> {
  var list = List.generate(10, (index) {
    return (
      Colors.primaries[Random().nextInt(Colors.primaries.length)].withOpacity(1),
      index,
    );
  });

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          Positioned(
            left: 0,
            right: 0,
            bottom: 0,
            height: 100 + kBottomNavigationBarHeight,
            child: Row(
              children: [
                Expanded(
                  child: Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: SizedBox(
                      height: 100,
                      child: TextFormField(
                        decoration: const InputDecoration(
                          label: Padding(
                            padding: EdgeInsets.all(0),
                            child: Text("Enter the number of cards"),
                          ),
                          labelStyle: TextStyle(
                            fontSize: 18,
                            fontWeight: FontWeight.w500,
                            // height: 0,
                          ),
                          floatingLabelAlignment: FloatingLabelAlignment.start,
                        ),
                        textInputAction: TextInputAction.done,
                        keyboardType: TextInputType.number,
                        inputFormatters: [
                          FilteringTextInputFormatter.digitsOnly,
                        ],
                        textAlign: TextAlign.start,
                        onTapOutside: (event) {
                          FocusScope.of(context).unfocus();
                        },
                        onChanged: (value) {
                          final intValue = int.tryParse(value) ?? 1;
                          setState(() {
                            list = List.generate(intValue, (index) {
                              return (
                                Colors.primaries[Random().nextInt(Colors.primaries.length)]
                                    .withOpacity(1),
                                index
                              );
                            });
                          });
                        },
                      ),
                    ),
                  ),
                )
              ],
            ),
          ),
          Positioned.fill(
            child: () {
              final mediaQuery = MediaQuery.of(context);
              final height = mediaQuery.size.height;
              return DraggableSheet(
                minHeight: (kBottomNavigationBarHeight * 2 + (0.25 * height)) / height,
                maxHeight: 1,
                itemHeight: 0.25 * height,
                list: List.generate(list.length, (index) {
                  return (
                    HomeProfileItemView(
                      index: index,
                      itemHeight: 0.25 * height,
                      item: list[index],
                    ),
                    index
                  );
                }),
                didSelectItem: (index) {
                  var tempList = List<(Color, int)>.from(list);
                  final tempSelectedItem = tempList[index];
                  tempList.removeAt(index);
                  tempList.insert(tempList.length, tempSelectedItem);
                  setState(() {
                    list = tempList;
                  });
                },
              );
            }(),
          ),
        ],
      ),
    );
  }
}

class HomeProfileItemView extends StatefulWidget {
  const HomeProfileItemView({
    super.key,
    required this.index,
    required this.itemHeight,
    required this.item,
    this.onTap,
  });

  final int index;
  final double itemHeight;
  final (Color, int) item;
  final void Function()? onTap;

  [@override](/user/override)
  State<HomeProfileItemView> createState() => _HomeProfileItemViewState();
}

class _HomeProfileItemViewState extends State<HomeProfileItemView> {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: widget.onTap,
      child: Card(
        color: Colors.transparent,
        elevation: 0,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(15),
        ),
        child: SizedBox(
          height: widget.itemHeight,
          child: Container(
            decoration: BoxDecoration(
              color: widget.item.$1,
              borderRadius: BorderRadius.circular(15),
            ),
            alignment: Alignment.center,
            child: Text(
              widget.item.$2.toString(),
              style: const TextStyle(
                fontSize: 26,
              ),
            ),
          ),
        ),
      ),
    );
  }
}

更多关于Flutter可拖拽底部面板插件draggable_sheet的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter可拖拽底部面板插件draggable_sheet的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用 draggable_sheet 插件在 Flutter 中实现可拖拽底部面板的示例代码。draggable_sheet 插件允许你创建一个可以像 iOS 的 Draggable Bottom Sheet 那样拖动的面板。

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

dependencies:
  flutter:
    sdk: flutter
  draggable_sheet: ^latest_version  # 请替换为最新版本号

然后,运行 flutter pub get 来获取依赖。

接下来是一个完整的示例代码,展示了如何使用 draggable_sheet:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Draggable Sheet Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final GlobalKey<DraggableSheetState> _draggableSheetKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Draggable Sheet Example'),
      ),
      body: Column(
        children: [
          Expanded(
            child: Center(
              child: Text('Main Content'),
            ),
          ),
          DraggableSheet(
            key: _draggableSheetKey,
            initialExtent: 0.3,
            minExtent: 0.1,
            maxExtent: 1,
            builder: (context, controller) {
              return Container(
                decoration: BoxDecoration(
                  color: Colors.white,
                  borderRadius: BorderRadius.only(
                    topLeft: Radius.circular(20),
                    topRight: Radius.circular(20),
                  ),
                ),
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.start,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        'Draggable Bottom Sheet',
                        style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
                      ),
                      SizedBox(height: 16),
                      Text(
                        'You can drag this sheet up and down.',
                        style: TextStyle(fontSize: 16),
                      ),
                      SizedBox(height: 16),
                      ElevatedButton(
                        onPressed: () {
                          _draggableSheetKey.currentState?.close();
                        },
                        child: Text('Close'),
                      ),
                    ],
                  ),
                ),
              );
            },
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _draggableSheetKey.currentState?.expand();
        },
        tooltip: 'Open Sheet',
        child: Icon(Icons.add),
      ),
    );
  }
}

在这个示例中:

  1. 我们创建了一个 MyApp 小部件,它是应用的根小部件。
  2. MyHomePage 是主页,它包含一个 Scaffold,其中包含一个 AppBar 和一个 Column。
  3. Column 包含了一个 Expanded 小部件,用于显示主内容,以及一个 DraggableSheet 小部件。
  4. DraggableSheet 小部件使用了一个 GlobalKey,以便我们可以在其他地方控制它(例如,打开或关闭它)。
  5. DraggableSheet 的 builder 参数接收一个构建器函数,用于构建面板的内容。
  6. 面板内容是一个简单的 Container,其中包含一些文本和一个关闭按钮。
  7. 一个 FloatingActionButton 被添加到 Scaffold 的 floatingActionButton 属性中,用于打开面板。

你可以根据需要调整 initialExtent、minExtent 和 maxExtent 的值来控制面板的初始高度、最小高度和最大高度。此外,你可以通过调用 _draggableSheetKey.currentState?.expand() 或 _draggableSheetKey.currentState?.close() 来编程控制面板的展开和关闭。

回到顶部