简体   繁体   English

Flutter Execute Method 这么长时间按下按钮

[英]Flutter Execute Method so long the button pressed

I need to Execute Method when the user press buton and during this Pressing Operation in other words the user will press the button for unkown period of time ai need to execute method during this Period of time any one have an idea how i can do that in Flutter i tried GestureDetector but there are no Option to do that also onLongPress hasn't this option becouse on Long Press triggered after the press Operation I will write psudo code for what i need:我需要在用户按下按钮时执行方法,在此按下操作期间,换句话说,用户将按下按钮一段未知的时间,我需要在这段时间内执行方法,任何人都知道我如何做到这一点Flutter 我试过 GestureDetector 但也没有选项可以做到这一点 onLongPress 也没有这个选项,因为在按下操作后长按触发,我将编写我需要的伪代码:

While(Button.isPressed){
 //Execute Method
 }

Use a Listener and a stateful widget.使用Listener和有状态小部件。 I also introduced a slight delay after every loop:我还在每个循环后引入了一个轻微的延迟:

import 'dart:async';

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(brightness: Brightness.dark),
      home: MyHomePage(),
    );
  }
}

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

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  bool _buttonPressed = false;
  bool _loopActive = false;

  void _increaseCounterWhilePressed() async {
    // make sure that only one loop is active
    if (_loopActive) return;

    _loopActive = true;

    while (_buttonPressed) {
      // do your thing
      setState(() {
        _counter++;
      });

      // wait a bit
      await Future.delayed(Duration(milliseconds: 200));
    }

    _loopActive = false;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Listener(
          onPointerDown: (details) {
            _buttonPressed = true;
            _increaseCounterWhilePressed();
          },
          onPointerUp: (details) {
            _buttonPressed = false;
          },
          child: Container(
            decoration: BoxDecoration(color: Colors.orange, border: Border.all()),
            padding: EdgeInsets.all(16.0),
            child: Text('Value: $_counter'),
          ),
        ),
      ),
    );
  }
}

A simpler way, without the listener, is as follows:一种更简单的方法,没有监听器,如下所示:

  GestureDetector(
      child: InkWell(
        child: Icon(Icons.skip_previous_rounded),
        onTap: widget.onPrevious,
      ),
      onLongPressStart: (_) async {
        isPressed = true;
        do {
          print('long pressing'); // for testing
          await Future.delayed(Duration(seconds: 1));
        } while (isPressed);
      },
      onLongPressEnd: (_) => setState(() => isPressed = false),
    );
  }

Building on the solution from ThinkDigital , my observation is that InkWell contains all the events necessary to do this without an extra GestureDetector (I find that the GestureDetector interferes with the ink animation on long press).基于ThinkDigital的解决方案,我的观察是InkWell包含执行此操作所需的所有事件,而无需额外的GestureDetector (我发现GestureDetector干扰长GestureDetector的墨迹动画)。 Here's a control I implemented for a pet project that fires its event with a decreasing delay when held (this is a rounded button with an icon, but anything using InkWell will do):这是我为一个宠物项目实现的控件,该控件在按住时以减少的延迟触发其事件(这是一个带有图标的圆形按钮,但使用InkWell任何事情都可以):

/// A round button with an icon that can be tapped or held
/// Tapping the button once simply calls [onUpdate], holding
/// the button will
class TapOrHoldButton extends StatefulWidget {
  /// Update callback
  final VoidCallback onUpdate;

  /// Minimum delay between update events when holding the button
  final int minDelay;

  /// Initial delay between change events when holding the button
  final int initialDelay;

  /// Number of steps to go from [initialDelay] to [minDelay]
  final int delaySteps;

  /// Icon on the button
  final IconData icon;

  const TapOrHoldButton(
      {Key? key,
      required this.onUpdate,
      this.minDelay = 80,
      this.initialDelay = 300,
      this.delaySteps = 5,
      required this.icon})
      : assert(minDelay <= initialDelay,
            "The minimum delay cannot be larger than the initial delay"),
        super(key: key);

  @override
  _TapOrHoldButtonState createState() => _TapOrHoldButtonState();
}

class _TapOrHoldButtonState extends State<TapOrHoldButton> {
  /// True if the button is currently being held
  bool _holding = false;

  @override
  Widget build(BuildContext context) {
    var shape = CircleBorder();
    return Material(
      color: Theme.of(context).dividerColor,
      shape: shape,
      child: InkWell(
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Icon(
            widget.icon,
            color:
                Theme.of(context).textTheme.headline1?.color ?? Colors.white70,
            size: 36,
          ),
        ),
        onTap: () => _stopHolding(),
        onTapDown: (_) => _startHolding(),
        onTapCancel: () => _stopHolding(),
        customBorder: shape,
      ),
    );
  }

  void _startHolding() async {
    // Make sure this isn't called more than once for
    // whatever reason.
    if (_holding) return;
    _holding = true;

    // Calculate the delay decrease per step
    final step =
        (widget.initialDelay - widget.minDelay).toDouble() / widget.delaySteps;
    var delay = widget.initialDelay.toDouble();

    while (_holding) {
      widget.onUpdate();
      await Future.delayed(Duration(milliseconds: delay.round()));
      if (delay > widget.minDelay) delay -= step;
    }
  }

  void _stopHolding() {
    _holding = false;
  }
}

Here it is in action:这是在行动:

保持增加控制

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM