Flutter:长按时显示上下文菜单

在使用 Flutter 开发应用程序时,您可能希望在用户长按某个元素时显示上下文菜单。作为合理的事情,上下文菜单的位置将靠近新闻位置。这篇实用的文章向您展示了完成它的技术,然后引导您完成在实践中应用该技术的完整示例。

重点是什么?

要检测图像或其他类型的小部件上的长按,请使用GestureDetector小部件包装它,如下所示:

GestureDetector(
              // get tap location
              onTapDown: (details) => _getTapPosition(details),
              // show the context menu
              onLongPress: () => _showContextMenu(context),
              child: Image.network(/* ... */),
),

在上面的代码片段中, _getTapPosition用于保留点击位置(用户手指点击屏幕的位置)。在 Flutter 中,我们可以像这样获得点击位置:

void _getTapPosition(TapDownDetails details) {
    final RenderBox referenceBox = context.findRenderObject() as RenderBox;
    final tapPosition = referenceBox.globalToLocal(details.globalPosition);
}

_showContextMenu函数,顾名思义,用于显示上下文菜单。在 Flutter 中,有一个名为showMenu的内置函数可以帮助我们完成这项工作:

void _showContextMenu(BuildContext context) async {
    final result = await showMenu(
        context: context,

        // Position the context menu
        // It should be placed near the long press location
        position: /* ...*/,

        // set a list of choices for the context menu
        items: [/* ... */]);
}

为了更清楚,请参阅下面的工作示例。

例子

应用概览

我们要制作的示例呈现一个蓝色框和一个图像。当长按框或图像时,将出现一个包含 3 个选项的上下文菜单(添加到收藏夹写评论隐藏)。选定的选项将被打印出来(到终端)。要关闭上下文菜单,只需点击它之外的某个地方。

如果您仔细观察,您会注意到上下文菜单出现在长按操作发生的位置,但从未侵入屏幕边界。这是演示:

Flutter:长按时显示上下文菜单

代码

main.dart中的完整源代码及说明:

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

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // Remove the debug banner
      debugShowCheckedModeBanner: false,
      title: 'KindaCode.com',
      theme: ThemeData(
        primarySwatch: Colors.pink,
      ),
      home: const KindaCodeDemo(),
    );
  }
}

class KindaCodeDemo extends StatefulWidget {
  const KindaCodeDemo({Key? key}) : super(key: key);

  @override
  State<KindaCodeDemo> createState() => _KindaCodeDemoState();
}

class _KindaCodeDemoState extends State<KindaCodeDemo> {
  // Tap location will be used use to position the context menu
  Offset _tapPosition = Offset.zero;
  void _getTapPosition(TapDownDetails details) {
    final RenderBox referenceBox = context.findRenderObject() as RenderBox;
    setState(() {
      _tapPosition = referenceBox.globalToLocal(details.globalPosition);
    });
  }

  // This function will be called when you long press on the blue box or the image
  void _showContextMenu(BuildContext context) async {
    final RenderObject? overlay =
        Overlay.of(context)?.context.findRenderObject();

    final result = await showMenu(
        context: context,

        // Show the context menu at the tap location
        position: RelativeRect.fromRect(
            Rect.fromLTWH(_tapPosition.dx, _tapPosition.dy, 30, 30),
            Rect.fromLTWH(0, 0, overlay!.paintBounds.size.width,
                overlay.paintBounds.size.height)),

        // set a list of choices for the context menu
        items: [
          const PopupMenuItem(
            value: 'favorites',
            child: Text('Add To Favorites'),
          ),
          const PopupMenuItem(
            value: 'comment',
            child: Text('Write Comment'),
          ),
          const PopupMenuItem(
            value: 'hide',
            child: Text('Hide'),
          ),
        ]);

    // Implement the logic for each choice here
    switch (result) {
      case 'favorites':
        debugPrint('Add To Favorites');
        break;
      case 'comment':
        debugPrint('Write Comment');
        break;
      case 'hide':
        debugPrint('Hide');
        break;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('KindaCode.com')),
      body: Padding(
        padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
        child: Column(
          children: [
            GestureDetector(
              // get tap location
              onTapDown: (details) => _getTapPosition(details),
              // show the context menu
              onLongPress: () => _showContextMenu(context),
              child: Container(
                width: double.infinity,
                height: 200,
                color: Colors.blue,
                child: const Center(
                  child: Text(
                    'Hi There',
                    style: TextStyle(fontSize: 30, color: Colors.white),
                  ),
                ),
              ),
            ),
            const SizedBox(
              height: 50,
            ),
            GestureDetector(
              // get tap location
              onTapDown: (details) => _getTapPosition(details),
              // show the context menu
              onLongPress: () => _showContextMenu(context),
              child: Image.network(
                  'https://www.kindacode.com/wp-content/uploads/2022/07/plant-example.jpeg',
                  width: double.infinity,
                  height: 300,
                  fit: BoxFit.cover),
            ),
          ],
        ),
      ),
    );
  }
}

结论

您已经学习了如何在小部件长按时显示弹出上下文菜单。

免责声明:
1.本站所有内容由本站原创、网络转载、消息撰写、网友投稿等几部分组成。
2.本站原创文字内容若未经特别声明,则遵循协议CC3.0共享协议,转载请务必注明原文链接。
3.本站部分来源于网络转载的文章信息是出于传递更多信息之目的,不意味着赞同其观点。
4.本站所有源码与软件均为原作者提供,仅供学习和研究使用。
5.如您对本网站的相关版权有任何异议,或者认为侵犯了您的合法权益,请及时通知我们处理。
火焰兔 » Flutter:长按时显示上下文菜单