为什么Flutter TextButton onPressed函数生成类型分配不匹配



我想使用Maps_launcher包启动谷歌地图。

当我将下面的TextButton代码复制到MaterialApp主页部分的一个新项目中时(或者去掉我自己的main.dart(,它工作得很好(编辑:它必须包装在容器或脚手架中才能工作,否则我会得到相同类型的不匹配错误。(

但是,由于一些我不知道的原因,我在我想要的结构中不断出现两个错误之一:

场景/错误A

当我使用这个代码:

onPressed: MapsLauncher.launchQuery(businesses[index].address)

我得到这个错误:

The argument type 'Future<bool>' can't be assigned to the parameter type 'void Function()?'.

场景/错误B

当我使用这个代码:

我得到这个错误:

════════ Exception caught by widgets library ═══════════════════════════════════
The following _TypeError was thrown building:
type 'String' is not a subtype of type 'Widget'
When the exception was thrown, this was the stack
#0      BusinessList.build.<anonymous closure>.<anonymous closure>
#1      SliverChildBuilderDelegate.build
#2      SliverMultiBoxAdaptorElement._build
#3      SliverMultiBoxAdaptorElement.createChild.<anonymous closure>
#4      BuildOwner.buildScope
#5      SliverMultiBoxAdaptorElement.createChild
#6      RenderSliverMultiBoxAdaptor._createOrObtainChild.<anonymous closure>
#7      RenderObject.invokeLayoutCallback.<anonymous closure>
#8      PipelineOwner._enableMutationsToDirtySubtrees
#9      RenderObject.invokeLayoutCallback
#10     RenderSliverMultiBoxAdaptor._createOrObtainChild
#11     RenderSliverMultiBoxAdaptor.addInitialChild
#12     RenderSliverList.performLayout
#13     RenderObject.layout
#14     RenderSliverEdgeInsetsPadding.performLayout
#15     RenderSliverPadding.performLayout
#16     RenderObject.layout
#17     RenderViewportBase.layoutChildSequence
#18     RenderViewport._attemptLayout
#19     RenderViewport.performLayout
#20     RenderObject.layout
#21     RenderProxyBoxMixin.performLayout
#22     RenderObject.layout
#23     RenderProxyBoxMixin.performLayout
#24     RenderObject.layout
#25     RenderProxyBoxMixin.performLayout
#26     RenderObject.layout
#27     RenderProxyBoxMixin.performLayout
#28     RenderObject.layout
#29     RenderProxyBoxMixin.performLayout
#30     RenderObject.layout
#31     RenderProxyBoxMixin.performLayout
#32     RenderObject.layout
#33     RenderProxyBoxMixin.performLayout
#34     RenderObject.layout
#35     RenderProxyBoxMixin.performLayout
#36     RenderCustomPaint.performLayout
#37     RenderObject.layout
#38     RenderProxyBoxMixin.performLayout
#39     RenderObject.layout
#40     MultiChildLayoutDelegate.layoutChild
#41     _ScaffoldLayout.performLayout
#42     MultiChildLayoutDelegate._callPerformLayout
#43     RenderCustomMultiChildLayoutBox.performLayout
#44     RenderObject._layoutWithoutResize
#45     PipelineOwner.flushLayout
#46     RendererBinding.drawFrame
#47     WidgetsBinding.drawFrame
#48     RendererBinding._handlePersistentFrameCallback
#49     SchedulerBinding._invokeFrameCallback
#50     SchedulerBinding.handleDrawFrame
#51     SchedulerBinding._handleDrawFrame
#55     _invoke (dart:ui/hooks.dart:150:10)
#56     PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:270:5)
#57     _drawFrame (dart:ui/hooks.dart:114:31)
(elided 3 frames from dart:async)

完整代码

以下是生成上述错误的代码(粘贴过程中删除了包导入(:

class BusinessList extends StatelessWidget {
  const BusinessList({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Business List')),
      body: StreamBuilder(
        stream: FirebaseFirestore.instance
            .collection('businesses')
            .snapshots()
            .map((snapshot) => snapshot.docs
                .map((doc) => Business.fromJson(doc.data()))
                .toList()),
        builder: (BuildContext context, AsyncSnapshot<List> snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const CircularProgressIndicator();
          }
          if (snapshot.hasData) {
            if (snapshot.data!.isNotEmpty) {
              final businesses = snapshot.data;
              return ListView.builder(
                itemCount: businesses!.length,
                itemBuilder: (BuildContext context, int index) {
                  return Card(
                    child: Column(
                      children: [
                        ExpansionTile(
                          leading: const Icon(Icons.business),
                          title: Text(businesses[index].name),
                          subtitle: Text(businesses[index].category),
                          children: [
                            ListTile(
                              leading: const Icon(Icons.location_pin),
                              title: TextButton(
                                child: businesses[index].address,
                                onPressed: () => MapsLauncher.launchQuery(
                                    businesses[index].address),
                              ),
                            ),
                          ],
                        ),
                      ],
                    ),
                  );
                },
              );
            }
          }
          return const Text('error');
        },
      ),
    );
  }
}

我的代码的红色下划线部分(第42行(是:

MapsLauncher.launchQuery(businesses[index].address)

我认为是launchQuery返回一个bool,这在编译器中显示出来,就像您试图将bool赋予想要void Function? 的参数一样

我认为这会解决问题。

onPressed: () => MapsLauncher.launchQuery(businesses[index].address),

或者您可能需要执行此操作,具体取决于launchQuery的工作方式:

onPressed: () async => await MapsLauncher.launchQuery(businesses[index].address),

这解决了类型不匹配的问题,因为当按下按钮时,添加() => 告诉编译器您正在为其提供一个onPressed执行的函数。

免责声明:这是未经测试的代码

好吧,我很高兴但也很失望地报告,生成该错误是初学者的错误。

问题实际上不在于onPressed,而在于需要Widget包装String的子项。

这是一个字符串:

child: businesses[index].address

所以我所要做的就是把它包装成这样:

child: Text(businesses[index].address)

当错误看起来像是在其他地方而不是实际位置时,这是非常令人沮丧的。我希望这有一天能帮助到某人。。。

相关内容

最新更新