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

如何为Flutter无状态组件传入自定义按钮及回调函数?

实现方案

要让FileUploadMutation组件支持传入任意类型按钮并复用,核心是通过**按钮构建器(Button Builder)**将按钮的创建逻辑交给外部调用方,同时把文件上传的核心逻辑封装在组件内部供外部按钮触发。

步骤1:修改组件定义

更新FileUploadMutation,添加一个buttonBuilder参数——这是一个函数,接收封装好的上传方法和Mutation的状态结果,返回任意类型的按钮组件。同时在组件内部封装上传逻辑,避免外部关注runMutation的细节。

修改后的完整代码:

class FileUploadMutation extends StatelessWidget {
  const FileUploadMutation({
    required this.user,
    required this.switchScreenFn,
    this.buttonBuilder,
    super.key,
  });

  final User user;
  final Function switchScreenFn;
  // 按钮构建器:接收上传方法和Mutation状态,返回自定义按钮
  final Widget Function(Future<void> Function() upload, QueryResult result)? buttonBuilder;

  @override
  Widget build(BuildContext context) {
    return Mutation(
      options: MutationOptions(
        document: gql(fileUploadMutation),
      ),
      builder: (runMutation, result) {
        // 封装上传核心逻辑,供外部按钮调用
        Future<void> _upload() async {
          List<MultipartFile> files = user.files;
          await runMutation({
            'containerName': containerName,
            'files': files,
          });
          switchScreenFn();
        }

        // 优先使用外部传入的按钮构建器,无传入则使用默认ElevatedButton
        return buttonBuilder?.call(_upload, result) ?? ElevatedButton(
          style: ElevatedButton.styleFrom(
            backgroundColor: Colors.red,
            elevation: 0,
          ),
          onPressed: result.isLoading ? null : _upload,
          child: result.isLoading 
              ? const CircularProgressIndicator(color: Colors.white) 
              : const Text("Continue"),
        );
      },
    );
  }
}

步骤2:调用组件时传入不同按钮

现在可以在任意位置调用FileUploadMutation,按需传入不同类型的按钮:

示例1:传入OutlineButton

FileUploadMutation(
  user: currentUser,
  switchScreenFn: () => Navigator.pushNamed(context, '/next-screen'),
  buttonBuilder: (upload, result) {
    return OutlineButton(
      borderSide: const BorderSide(color: Colors.blue),
      onPressed: result.isLoading ? null : upload,
      child: result.isLoading 
          ? const SizedBox(width:20, height:20, child: CircularProgressIndicator())
          : const Text("上传文件"),
    );
  },
)

示例2:传入IconButton

FileUploadMutation(
  user: currentUser,
  switchScreenFn: () => setState(() => isUploaded = true),
  buttonBuilder: (upload, result) {
    return IconButton(
      icon: result.isLoading 
          ? const CircularProgressIndicator(size:20) 
          : const Icon(Icons.cloud_upload),
      onPressed: result.isLoading ? null : upload,
      color: Colors.green,
    );
  },
)

示例3:自定义样式的ElevatedButton

FileUploadMutation(
  user: currentUser,
  switchScreenFn: () {},
  buttonBuilder: (upload, result) {
    return ElevatedButton(
      style: ElevatedButton.styleFrom(
        backgroundColor: Colors.purple,
        padding: const EdgeInsets.symmetric(horizontal:30, vertical:12),
      ),
      onPressed: result.isLoading ? null : upload,
      child: result.isLoading 
          ? const Text("上传中...") 
          : const Text("开始上传", style: TextStyle(fontSize:16)),
    );
  },
)

核心优势

  • 高度灵活:支持任意按钮类型,样式、内容完全由调用方控制
  • 逻辑封装:文件上传和Mutation逻辑都在组件内部,外部只需调用upload方法即可
  • 状态同步:自动同步Mutation的加载状态,方便处理按钮禁用、加载提示等逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 01:27:56