Flutter之使用Competer做防抖

11 阅读2分钟

Flutter中,Completer 可以用来实现防抖功能。防抖是用于确保时间内的所有触发被合并成单一请求。对于连续的事件触发(如用户的键盘输入、按钮的连续点击),只有在指定的延迟时间内没有再次触发事件时,才执行实际的操作。

下面是如何使用 Completer 来实现异步防抖的一个示例,代码如下:

import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Drag to Sort',
      home: MyHomePage(),
    );
  }
}

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

class _MyHomePageState extends State<MyHomePage> {
  final List<String> _items = List<String>.generate(10, (i) => 'Item $i');
  bool _isReorderable = false;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    var debouncer = Debouncer(delay: Duration(seconds: 1));

    // 模拟快速连续触发事件
    debouncer.run(() => print('Action 1'));
    debouncer.run(() => print('Action 2'));
    debouncer.run(() => print('Action 3'));

    // 等待一秒后执行
    Future.delayed(Duration(seconds: 2), () {
      debouncer.run(() => print('Action after delay'));
    });

  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      //  backgroundColor: Colors.blueAccent,
      appBar: AppBar(
        title: Text('Test'),
      ),
      body: Column(children: [
        _buildContainer(Colors.lightBlue,const Flexible(
            child: Text("这是一个项目",maxLines: 1,overflow: TextOverflow.ellipsis,))),
        _buildContainer(Colors.red, const Flexible(
            fit: FlexFit.tight,
            child: Text("这是一个项目",maxLines: 1,overflow: TextOverflow.ellipsis,))),
        _buildContainer(Colors.purple,  Flexible(
            fit: FlexFit.tight,
            child: Text("这是一个项目" * 6,maxLines: 1,overflow: TextOverflow.ellipsis,))),
        _buildContainer(Colors.blue,  Expanded(
            child: Text("这是一个项目" * 6,maxLines: 1,overflow: TextOverflow.ellipsis,))),

      ],),
    );
  }

  Container _buildContainer(Color color,Widget child) {
    return Container(
      height: 56,
      color: color,
      child: Row(
        children: [
          const SizedBox(width:16),
          const Text("来源:"),
          child,
          const SizedBox(width: 8),
          Container(
            padding: EdgeInsets.all(5),
            decoration: const BoxDecoration(
                color: Colors.cyan,
                borderRadius: BorderRadius.all(Radius.circular(6))
            ),
            child: Text("项目"),
          ),
          const SizedBox(width:16),
        ],
      ),
    );
  }
}

class Debouncer {
  final Duration delay;
  Completer? _lastCompleter;
  Timer? _timer;

  Debouncer({required this.delay});

  void run(Function action) {
    // 如果之前的操作还没有完成,取消它
    if (_lastCompleter != null && !_lastCompleter!.isCompleted) {
      _lastCompleter!.completeError('Cancelled');
    }

    _lastCompleter = Completer();

    // 重置计时器
    _timer?.cancel();
    _timer = Timer(delay, () {
      action();
      _lastCompleter!.complete();
    });

    // 处理取消操作
    _lastCompleter!.future.catchError((error) {
      print('操作被取消');
    });
  }
}

打印如下:

截屏2024-03-12 14.16.46.png 在这个示例中:

  • Debouncer 类包含了防抖逻辑。run 方法接受一个要执行的动作,并且确保在连续调用时,只有最后一次调用会在指定的延迟后执行。
  • run 方法被连续调用时,它会通过 Completer 取消前一个还未完成的动作,并重新开始计时。
  • 只有在延迟时间过去且没有新的调用时,最后一次动作才会执行。

这种方法可以有效地限制事件(如用户输入、按钮点击等)的处理频率,从而优化性能和资源利用。在实际应用中,大家可能需要根据具体情况调整延迟时间和处理逻辑。