You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter如何创建内部带Spinner、可隔离setState调用的可复用按钮

Flutter 加载状态按钮封装方案

完全可以把Spinner切换逻辑完全封装在组件内部,核心思路是让按钮接收异步回调函数,内部自行管理加载状态,无需外部传入控制参数也不用外部触发状态更新。

具体实现逻辑

  • 组件为StatefulWidget,内部State中定义私有布尔变量_isLoading,默认值为false,作为控制Spinner显示的唯一内部状态
  • 组件接收的onPressed回调要求为返回Future的异步函数,匹配网络请求这类异步操作的场景
  • 点击事件触发时做如下处理:
    1. 若当前已经处于加载状态,直接拦截点击避免重复触发
    2. 调用内部setState将_isLoading置为true,按钮切换为Spinner显示
    3. 用try-finally包裹异步回调的执行逻辑,无论回调执行成功还是抛出异常,最终都在finally块中调用setState将_isLoading重置为false,恢复按钮文字显示
  • 构建布局时根据_isLoading的状态动态切换显示内容:加载时显示Spinner,否则显示按钮文字

参考实现代码

import 'package:flutter/material.dart';

class LoadingButton extends StatefulWidget {
  const LoadingButton({
    super.key,
    required this.text,
    required this.onPressed,
    this.style,
    this.textStyle,
    this.disabled = false,
  });

  final String text;
  final Future<void> Function() onPressed;
  final ButtonStyle? style;
  final TextStyle? textStyle;
  final bool disabled;

  @override
  State<LoadingButton> createState() => _LoadingButtonState();
}

class _LoadingButtonState extends State<LoadingButton> {
  bool _isLoading = false;

  Future<void> _handleTap() async {
    if (_isLoading || widget.disabled) return;
    setState(() {
      _isLoading = true;
    });
    try {
      await widget.onPressed();
    } finally {
      if (mounted) {
        setState(() {
          _isLoading = false;
        });
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      style: widget.style,
      onPressed: _handleTap,
      child: _isLoading
          ? const CircularProgressIndicator(color: Colors.white)
          : Text(
              widget.text,
              style: widget.textStyle,
            ),
    );
  }
}

使用示例

外部使用时无需管理任何加载状态,直接传入异步的请求逻辑即可:

LoadingButton(
  text: "提交数据",
  onPressed: () async {
    // 这里直接写你的网络请求逻辑即可,不用手动控制loading
    await Future.delayed(const Duration(seconds: 2));
    // 请求完成后按钮会自动恢复文字显示
  },
)

可选扩展

如果有特殊场景需要外部强制控制加载状态,可以新增一个可选的bool? showLoading参数,构建时优先使用外部传入的参数值,内部_isLoading作为降级选项,兼顾灵活性和通用性。

内容的提问来源于stack exchange,提问作者lxknvlk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 14:45:10