IconButton和长按检测

5

请帮我处理图标按钮的长按检测。

我正在尝试创建一个图标按钮,如果点击一次则将数量值增加1,而在长按时则将其增加10。

但是,在Flutter 2.12中,IconButton没有提供长按事件处理程序,这是一个问题。

因此,我使用了以下代码中的Container内部的Icon来实现:

        GestureDetector(
          child: Container(
            child: const Icon(
              Icons.add,
            ),
            padding: EdgeInsets.symmetric(vertical: 6.0, horizontal: 18.0),
          ),
          onTap: () {
            increment(1);
          },
          onLongPressStart: (_) async {
            startPressing(() => increment(10));
          },
          onLongPressCancel: () {
            cancelPress();
          },
          onLongPressEnd: (_) {
            cancelPress();
          },
        ),

它能工作,但问题在于按压区域非常小,在移动设备上很难找到按压点而感到不舒适。

我尝试将图标大小增加到48,但结果很糟糕,图标过于不自然地变大。

const Icon(
              Icons.add,
              size: 48,
            ),

对我而言,看起来不错的设计是使用GestureDetector(用于长按)和IconButton(以及onPressed用于单击检测):

        GestureDetector(
          child: IconButton(
            onPressed: () => decrement(1),
            icon: const Icon(
              Icons.remove,
            ),
            padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 18.0),
            color: Theme.of(context).primaryColor,
          ),
          onLongPressStart: (_) async {
            startPressing(() => decrement(10));
          },
          onLongPressCancel: () {
            cancelPress();
          },
          onLongPressEnd: (_) {
            cancelPress();
          },
        ),

Flutter使用GestureDetector来处理长按事件,使用IconButton来处理点击事件是否可行?我在某些特定的Android版本上会遇到问题吗?


当您触发 onPressed 时,它也会触发 onLongPressEnd,请尝试添加 print() 来查看发生了什么。 - cahyo
@cahyo 一切都运行良好。我的问题是“在GuestureDetecor上放置IconButton是否安全”? - oleksa
我觉得这样可以。虽然不是最优雅的,但它对我来说有用且易读。 - Nils Tierecke
3个回答

3

尝试使用InkWell替代,它会像IconButton一样,并给您水波纹效果。

Material(
  child: InkWell(
    onTap: () {},
    onLongPress: () {},
    child: Ink(
      child: Icon(Icons.add),
    ),
  ),
),

谢谢,但它仍有相同的问题 - 只有图标在轻按(或长按)时会有反应。可以使用“Ink(padding)”修复这个问题,但仍存在另一个问题。GestureDetector允许在开始长按操作后每次增加10个值,直到 onLongPressCancelonLongPressEnd。然而,InkWell(onLongPress)只触发一次。 - oleksa

1

设置Containerwidthheight,并将其放入GestureDetector中,并通过Icon的填充来固定大小。

     Container(
      alignment: Alignment.center,
      width: 40, 
      height: 40,
      child: GestureDetector(
        child: Padding(
         padding: EdgeInsets.symmetric(vertical: 6.0, horizontal: 18.0),
         child: Icon(
          Icons.add,
      ),),
      onTap: () {
        increment(1);
      },
      onLongPressStart: (_) async {
        startPressing(() => increment(10));
      },
      onLongPressCancel: () {
        cancelPress();
      },
      onLongPressEnd: (_) {
        cancelPress();
      },
    ),
   )

如果从小部件控件层次结构中删除child: Padding(,则此代码将正常工作。使用Padding()时,onTaponLongPressStart将完全无法工作。 - oleksa
填充(padding)是“GestureDetector”的子级,它无法禁用父级的操作。 - novol
可能是因为在第一条评论之前,我已经尝试过你的示例并与可工作的“IconButton”进行了比较。但是,“GuestureDetector”无法与“Padding”子元素一起使用(当删除“Padding”时它可以正常工作)。 - oleksa

0
自定义图标按钮。基于cahyo的答案。
import 'package:flutter/material.dart';

class LongPressIconButton extends StatelessWidget {
  final void Function() onPressed;
  final void Function() onLongPressed;
  final double width;
  final double height;
  final IconData iconData;
  final Color color;
  final double? iconSize;
  final String? tooltip;

  const LongPressIconButton(
      {super.key,
      required this.onPressed,
      required this.onLongPressed,
      required this.width,
      required this.height,
      required this.iconData,
      required this.color,
      this.tooltip,
      this.iconSize});
  @override
  Widget build(BuildContext context) {
    return Material(
      child: Tooltip(
        message: tooltip ?? '',
        child: InkWell(
          customBorder: new CircleBorder(),
          onTap: onPressed,
          onLongPress: onLongPressed,
          child: Ink(
            width: width,
            height: height,
            padding: EdgeInsets.zero,
            child: Icon(iconData, color: color, size: iconSize ?? 24),
          ),
        ),
      ),
    );
  }
}

使用方式:

  LongPressIconButton(
          onPressed: () {
            increment(1);
          },
          onLongPressed: () {
           increment(10);
          },
          color: Theme.of(context).colorScheme.primary,
          height: 60,
          width: 60,
          iconData: Icons.plus_one,
          tooltip: 'Increment',
        ),

我没有机会去检查,但是当用户长按图标时,它会继续增加吗?Cahyo的回答没有提供这种可能性,而且onLongPressed只会触发一次。 - oleksa
它只会触发一次。刚在安卓和网页上检查过。 - Yuriy N.
@oleksa。你可能会对以下链接感兴趣:https://dev59.com/5VQK5IYBdhLWcg3wQt5t - Yuriy N.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接